Fix poolquery handling repo restrictions correctly. (bnc#661976)
[platform/upstream/libzypp.git] / zypp / PoolQuery.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/PoolQuery.cc
10  *
11 */
12 #include <iostream>
13 #include <sstream>
14
15 #include "zypp/base/Gettext.h"
16 #include "zypp/base/LogTools.h"
17 #include "zypp/base/Algorithm.h"
18 #include "zypp/base/String.h"
19 #include "zypp/repo/RepoException.h"
20 #include "zypp/RelCompare.h"
21
22 #include "zypp/sat/Pool.h"
23 #include "zypp/sat/Solvable.h"
24 #include "zypp/sat/AttrMatcher.h"
25
26 #include "zypp/PoolQuery.h"
27
28 #undef ZYPP_BASE_LOGGER_LOGGROUP
29 #define ZYPP_BASE_LOGGER_LOGGROUP "PoolQuery"
30
31 using namespace std;
32 using namespace zypp::sat;
33
34 ///////////////////////////////////////////////////////////////////
35 namespace zypp
36 { /////////////////////////////////////////////////////////////////
37
38   ///////////////////////////////////////////////////////////////////
39   namespace
40   { /////////////////////////////////////////////////////////////////
41
42     /////////////////////////////////////////////////////////////////
43     // some Helpers and Predicates
44     /////////////////////////////////////////////////////////////////
45
46     bool isDependencyAttribute( sat::SolvAttr attr_r )
47     {
48       static sat::SolvAttr deps[] = {
49         SolvAttr::provides,
50         SolvAttr::requires,
51         SolvAttr::recommends,
52         SolvAttr::obsoletes,
53         SolvAttr::conflicts,
54         SolvAttr::suggests,
55         SolvAttr::supplements,
56         SolvAttr::enhances,
57       };
58       for_( it, arrayBegin(deps), arrayEnd(deps) )
59         if ( *it == attr_r )
60           return true;
61       return false;
62     }
63
64     /** Whether the current capabilities edition range ovelaps and/or its solvables arch matches.
65      * Query asserts \a iter_r points to a capability and we
66      * have to check the range only.
67      */
68     struct EditionRangePredicate
69     {
70       EditionRangePredicate( const Rel & op, const Edition & edition )
71         : _range( op, edition )
72         , _arch( Arch_empty )
73       {}
74       EditionRangePredicate( const Rel & op, const Edition & edition, const Arch & arch )
75         : _range( op, edition )
76         , _arch( arch )
77       {}
78
79       bool operator()( sat::LookupAttr::iterator iter_r )
80       {
81         if ( !_arch.empty() && iter_r.inSolvable().arch() != _arch )
82           return false;
83
84         CapDetail cap( iter_r.id() );
85         if ( ! cap.isSimple() )
86           return false;
87         if ( cap.isNamed() ) // no range to match
88           return true;
89         return overlaps( Edition::MatchRange( cap.op(), cap.ed() ), _range );
90       }
91
92       std::string serialize() const
93       {
94         std::string ret( "EditionRange" );
95         str::appendEscaped( ret, _range.op.asString() );
96         str::appendEscaped( ret, _range.value.asString() );
97         str::appendEscaped( ret, _arch.asString() );
98         return ret;
99       }
100
101       Edition::MatchRange _range;
102       Arch                _arch;
103    };
104
105     /** Whether the current Solvables edition is within a given range and/or its arch matches. */
106     struct SolvableRangePredicate
107     {
108       SolvableRangePredicate( const Rel & op, const Edition & edition )
109         : _range( op, edition )
110         , _arch( Arch_empty )
111       {}
112
113       SolvableRangePredicate( const Rel & op, const Edition & edition, const Arch & arch )
114         : _range( op, edition )
115         , _arch( arch )
116       {}
117
118       bool operator()( sat::LookupAttr::iterator iter_r )
119       {
120         if ( !_arch.empty() && iter_r.inSolvable().arch() != _arch )
121           return false;
122         return overlaps( Edition::MatchRange( Rel::EQ, iter_r.inSolvable().edition() ), _range );
123       }
124
125       std::string serialize() const
126       {
127         std::string ret( "SolvableRange" );
128         str::appendEscaped( ret, _range.op.asString() );
129         str::appendEscaped( ret, _range.value.asString() );
130         str::appendEscaped( ret, _arch.asString() );
131         return ret;
132       }
133
134       Edition::MatchRange _range;
135       Arch                _arch;
136     };
137
138     /** Whether the current capability matches a given one.
139      * Query asserts \a iter_r points to a capability and we
140      * have to check the match only.
141      */
142     struct CapabilityMatchPredicate
143     {
144       CapabilityMatchPredicate( Capability cap_r )
145         : _cap( cap_r )
146       {}
147
148       bool operator()( sat::LookupAttr::iterator iter_r ) const
149       {
150         return _cap.matches( iter_r.asType<Capability>() ) == CapMatch::yes;
151       }
152
153       std::string serialize() const
154       {
155         std::string ret( "CapabilityMatch" );
156         str::appendEscaped( ret, _cap.asString() );
157         return ret;
158       }
159
160       Capability _cap;
161     };
162
163     /////////////////////////////////////////////////////////////////
164     //
165     /////////////////////////////////////////////////////////////////
166     /** Match data per attribtue.
167      *
168      * This includes the attribute itself, an optional \ref sat::AttrMatcher
169      * to restrict the query to certain string values, and an optional
170      * boolean \ref Predicate that may apply further restrictions that can
171      * not be expressed by the \ref attrMatcher.
172      *
173      * Example for such a \ref predicate would be an additional edition range
174      * check whan looking for dependencies. The \ref attrMatcher would
175      * find potential matches by looking at the dependencies name, the
176      * predicate will then check the edition ranges.
177      *
178      * As the \ref predicate takes an iterator pointing to the current
179      * match, it's also suitable for sub-structure (flexarray) inspection
180      * (\see \ref sat::LookupAttr::iterator::solvAttrSubEntry).
181      *
182      * \note: \see \ref addPredicate for further constraints.
183      */
184     struct AttrMatchData
185     {
186       typedef function<bool(sat::LookupAttr::iterator)> Predicate;
187
188       static bool always( sat::LookupAttr::iterator ) { return true; }
189       static bool never( sat::LookupAttr::iterator ) { return false; }
190
191       AttrMatchData()
192       {}
193
194       AttrMatchData( sat::SolvAttr attr_r, const sat::AttrMatcher & attrMatcher_r )
195         : attr( attr_r )
196         , attrMatcher( attrMatcher_r )
197       {}
198
199       AttrMatchData( sat::SolvAttr attr_r, const sat::AttrMatcher & attrMatcher_r,
200                      const Predicate & predicate_r, const std::string & predicateStr_r )
201         : attr( attr_r )
202         , attrMatcher( attrMatcher_r )
203         , predicate( predicate_r )
204         , predicateStr( predicateStr_r )
205       {}
206
207       /** A usable Predicate must provide a string serialization.
208        * As there is no \c operator== for \ref Predicate, we compare it's
209        * string representation instead. If you add new predicated, check the
210        * deserialization code in \ref deserialize.
211        */
212       template<class _Predicate>
213       void addPredicate( const _Predicate & predicate_r )
214       {
215         predicate    = predicate_r;
216         predicateStr = predicate_r.serialize();
217       }
218
219       /** Dumb serialization.
220        * \code
221        *   AttrMatchData ATTRIBUTE SEARCHSTRING [C|X] SERIALIZED_PREDICATE
222        * \endcode
223       */
224       std::string serialize() const
225       {
226         std::string ret( "AttrMatchData" );
227         str::appendEscaped( ret, attr.asString() );
228         str::appendEscaped( ret, attrMatcher.searchstring() );
229         // TODO: Actually the flag should be serialized too, but for PoolQuery
230         // it's by now sufficient to differ between mode OTHER and others,
231         // i.e. whether to compile or not compile.
232         str::appendEscaped( ret, attrMatcher.flags().mode() == Match::OTHER ? "C" : "X" );
233         str::appendEscaped( ret, predicateStr );
234         return ret;
235       }
236
237        /** Dumb restore from serialized string.
238         * \throw Exception on parse error.
239         */
240       static AttrMatchData deserialize( const std::string & str_r )
241       {
242         std::vector<std::string> words;
243         str::splitEscaped( str_r, std::back_inserter(words) );
244         if ( words.empty() || words[0] != "AttrMatchData" )
245           ZYPP_THROW( Exception( str::Str() << "Expecting AttrMatchData: " << str_r ) );
246         if ( words.size() != 5 )
247           ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
248
249         AttrMatchData ret;
250         ret.attr = sat::SolvAttr( words[1] );
251         ret.attrMatcher = sat::AttrMatcher( words[2] );
252         if ( words[3] == "C" )
253           ret.attrMatcher.setFlags( Match::OTHER );
254         ret.predicateStr = words[4];
255
256         // now the predicate
257         words.clear();
258         str::splitEscaped( ret.predicateStr, std::back_inserter(words) );
259         if ( ! words.empty() )
260         {
261           if ( words[0] == "EditionRange" )
262           {
263             switch( words.size() )
264             {
265               case 3:
266                 ret.predicate = EditionRangePredicate( Rel(words[1]), Edition(words[2]) );
267                 break;
268               case 4:
269                 ret.predicate = EditionRangePredicate( Rel(words[1]), Edition(words[2]), Arch(words[3]) );
270                 break;
271               default:
272                 ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
273                 break;
274             }
275           }
276           else if ( words[0] == "SolvableRange" )
277           {
278             switch( words.size() )
279             {
280               case 3:
281                 ret.predicate = SolvableRangePredicate( Rel(words[1]), Edition(words[2]) );
282                 break;
283               case 4:
284                 ret.predicate = SolvableRangePredicate( Rel(words[1]), Edition(words[2]), Arch(words[3]) );
285                 break;
286               default:
287                 ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
288                 break;
289             }
290           }
291           else if ( words[0] == "CapabilityMatch" )
292           {
293             if ( words.size() != 2 )
294               ZYPP_THROW( Exception( str::Str() << "Wrong number of words: " << str_r ) );
295             ret.predicate = CapabilityMatchPredicate( Capability(words[1]) );
296           }
297           else
298             ZYPP_THROW( Exception( str::Str() << "Unknown predicate: " << str_r ) );
299         }
300         return ret;
301      }
302
303       sat::SolvAttr    attr;
304       sat::AttrMatcher attrMatcher;
305       Predicate        predicate;
306       std::string      predicateStr;
307     };
308
309     /** \relates AttrMatchData */
310     inline std::ostream & operator<<( std::ostream & str, const AttrMatchData & obj )
311     {
312       str << obj.attr << ": " << obj.attrMatcher;
313       if ( obj.predicate )
314         str << " +(" << obj.predicateStr << ")";
315       return str;
316     }
317
318     /** \relates AttrMatchData */
319     inline bool operator==( const AttrMatchData & lhs, const AttrMatchData & rhs )
320     {
321       return ( lhs.attr == rhs.attr
322                && lhs.attrMatcher == rhs.attrMatcher
323                && lhs.predicateStr == rhs.predicateStr );
324     }
325
326     /** \relates AttrMatchData */
327     inline bool operator!=( const AttrMatchData & lhs, const AttrMatchData & rhs )
328     { return !( lhs == rhs ); }
329
330     /** \relates AttrMatchData Arbitrary order for std::container. */
331     inline bool operator<( const AttrMatchData & lhs, const AttrMatchData & rhs )
332     {
333       if ( lhs.attr != rhs.attr )
334         return (  lhs.attr < rhs.attr );
335       if ( lhs.attrMatcher != rhs.attrMatcher )
336         return (  lhs.attrMatcher < rhs.attrMatcher );
337       if ( lhs.predicateStr != rhs.predicateStr )
338         return (  lhs.predicateStr < rhs.predicateStr );
339       return false;
340     }
341
342     typedef std::list<AttrMatchData> AttrMatchList;
343
344
345   } /////////////////////////////////////////////////////////////////
346   // namespace
347   ///////////////////////////////////////////////////////////////////
348
349   ///////////////////////////////////////////////////////////////////
350   //
351   //  CLASS NAME : PoolQuery::Impl
352   //
353   /** */
354   class PoolQuery::Impl
355   {
356   public:
357     Impl()
358       : _flags( Match::SUBSTRING | Match::NOCASE | Match::SKIP_KIND )
359       , _match_word(false)
360       , _require_all(false)
361       , _status_flags(ALL)
362     {}
363
364     ~Impl()
365     {}
366
367   public:
368     /** String representation */
369     string asString() const;
370
371     /** \name Raw query options. */
372     //@{
373     /** Raw search strings. */
374     StrContainer _strings;
375     /** Raw attributes */
376     AttrRawStrMap _attrs;
377     /** Uncompiled attributes with predicate. */
378     std::set<AttrMatchData> _uncompiledPredicated;
379
380     /** Sat solver search flags */
381     Match _flags;
382     bool _match_word;
383     bool _require_all;
384
385     /** Sat solver status flags */
386     StatusFilter _status_flags;
387
388     /** Edition condition operand */
389     Edition _edition;
390     /** Operator for edition condition */
391     Rel _op;
392
393     /** Repos to search. */
394     StrContainer _repos;
395
396     /** Kinds to search */
397     Kinds _kinds;
398     //@}
399
400   public:
401
402     bool operator==( const PoolQuery::Impl & rhs ) const
403     {
404       return ( _strings == rhs._strings
405                && _attrs == rhs._attrs
406                && _uncompiledPredicated == rhs._uncompiledPredicated
407                && _flags == rhs._flags
408                && _match_word == rhs._match_word
409                && _require_all == rhs._require_all
410                && _status_flags == rhs._status_flags
411                && _edition == rhs._edition
412                && _op == rhs._op
413                && _repos == rhs._repos
414                && _kinds == rhs._kinds );
415     }
416
417     bool operator!=( const PoolQuery::Impl & rhs ) const
418     { return ! operator==( rhs ); }
419
420   public:
421     /** Compile the regex.
422      * Basically building the \ref _attrMatchList from strings.
423      * \throws MatchException Any of the exceptions thrown by \ref AttrMatcher::compile.
424      */
425     void compile() const;
426
427     /** AttrMatcher per attribtue. */
428     mutable AttrMatchList _attrMatchList;
429
430   private:
431     /** Pass flags from \ref compile, as they may have been changed. */
432     string createRegex( const StrContainer & container, const Match & flags ) const;
433
434   private:
435     friend Impl * rwcowClone<Impl>( const Impl * rhs );
436     /** clone for RWCOW_pointer */
437     Impl * clone() const
438     { return new Impl( *this ); }
439   };
440
441   ///////////////////////////////////////////////////////////////////
442
443   struct MyInserter
444   {
445     MyInserter(PoolQuery::StrContainer & cont) : _cont(cont) {}
446
447     bool operator()(const string & str)
448     {
449       _cont.insert(str);
450       return true;
451     }
452
453     PoolQuery::StrContainer & _cont;
454   };
455
456
457   struct EmptyFilter
458   {
459     bool operator()(const string & str)
460     {
461       return !str.empty();
462     }
463   };
464
465   void PoolQuery::Impl::compile() const
466   {
467     _attrMatchList.clear();
468
469     Match cflags( _flags );
470     if ( cflags.mode() == Match::OTHER ) // this will never succeed...
471       ZYPP_THROW( MatchUnknownModeException( cflags ) );
472
473     /** Compiled search strings. */
474     string rcstrings;
475
476
477     // 'different'         - will have to iterate through all and match by ourselves (slow)
478     // 'same'              - will pass the compiled string to dataiterator_init
479     // 'one-attr'          - will pass it to dataiterator_init
480     // 'one-non-regex-str' - will pass to dataiterator_init, set flag to SEARCH_STRING or SEARCH_SUBSTRING
481
482     // // NO ATTRIBUTE
483     // else
484     //   for all _strings
485     //     create regex; store in rcstrings; if more strings flag regex;
486     if (_attrs.empty())
487     {
488       ; // A default 'query-all' will be added after all sources are processed.
489     }
490
491     // // ONE ATTRIBUTE
492     // else if _attrs is not empty but it contains just one attr
493     //   for all _strings and _attr[key] strings
494     //     create regex; flag 'one-attr'; if more strings flag regex;
495     else if (_attrs.size() == 1)
496     {
497       StrContainer joined;
498       invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
499       invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
500       rcstrings = createRegex(joined, cflags);
501       if (joined.size() > 1) // switch to regex for multiple strings
502         cflags.setModeRegex();
503       _attrMatchList.push_back( AttrMatchData( _attrs.begin()->first,
504                                 sat::AttrMatcher( rcstrings, cflags ) ) );
505     }
506
507     // // MULTIPLE ATTRIBUTES
508     else
509     {
510       // check whether there are any per-attribute strings
511       bool attrvals_empty = true;
512       for (AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
513         if (!ai->second.empty())
514           for(StrContainer::const_iterator it = ai->second.begin();
515               it != ai->second.end(); it++)
516             if (!it->empty())
517             {
518               attrvals_empty = false;
519               goto attremptycheckend;
520             }
521 attremptycheckend:
522
523       // chceck whether the per-attribute strings are all the same
524       bool attrvals_thesame = true;
525       AttrRawStrMap::const_iterator ai = _attrs.begin();
526       const StrContainer & set1 = ai->second;
527       ++ai;
528       for (; ai != _attrs.end(); ++ai)
529       {
530         StrContainer result;
531         set_difference(
532           set1.begin(), set1.end(),
533           ai->second.begin(), ai->second.end(),
534           inserter(result, result.begin())/*, ltstr()*/);
535         if (!result.empty())
536         {
537           attrvals_thesame = false;
538           break;
539         }
540       }
541
542       // // THE SAME STRINGS FOR DIFFERENT ATTRS
543       // else if _attrs is not empty but it does not contain strings
544       //   for each key in _attrs take all _strings
545       //     create regex; store in rcstrings; flag 'same'; if more strings flag regex;
546       if (attrvals_empty || attrvals_thesame)
547       {
548         StrContainer joined;
549         if (attrvals_empty)
550         {
551           invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
552           rcstrings = createRegex(joined, cflags);
553         }
554         else
555         {
556           invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
557           invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
558           rcstrings = createRegex(joined, cflags);
559         }
560         if (joined.size() > 1) // switch to regex for multiple strings
561           cflags.setModeRegex();
562         // May use the same AttrMatcher for all
563         sat::AttrMatcher matcher( rcstrings, cflags );
564         for_( ai, _attrs.begin(), _attrs.end() )
565         {
566           _attrMatchList.push_back( AttrMatchData( ai->first, matcher ) );
567         }
568       }
569
570       // // DIFFERENT STRINGS FOR DIFFERENT ATTRS
571       // if _attrs is not empty and it contains non-empty vectors with non-empty strings
572       //   for each key in _attrs take all _strings + all _attrs[key] strings
573       //     create regex; flag 'different'; if more strings flag regex;
574       else
575       {
576         for_(ai, _attrs.begin(), _attrs.end())
577         {
578           StrContainer joined;
579           invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
580           invokeOnEach(ai->second.begin(), ai->second.end(), EmptyFilter(), MyInserter(joined));
581           string s = createRegex(joined, cflags);
582           if (joined.size() > 1) // switch to regex for multiple strings
583             cflags.setModeRegex();
584           _attrMatchList.push_back( AttrMatchData( ai->first,
585                                     sat::AttrMatcher( s, cflags ) ) );
586         }
587       }
588     }
589
590     // Now handle any predicated queries
591     if ( ! _uncompiledPredicated.empty() )
592     {
593       StrContainer global;
594       invokeOnEach( _strings.begin(), _strings.end(), EmptyFilter(), MyInserter(global) );
595       for_( it, _uncompiledPredicated.begin(), _uncompiledPredicated.end() )
596       {
597         if ( it->attrMatcher.flags().mode() == Match::OTHER )
598         {
599           // need to compile:
600           StrContainer joined( global );
601           const std::string & mstr( it->attrMatcher.searchstring() );
602           if ( ! mstr.empty() )
603             joined.insert( mstr );
604
605           cflags = _flags;
606           rcstrings = createRegex( joined, cflags );
607           if ( joined.size() > 1 ) // switch to regex for multiple strings
608             cflags.setModeRegex();
609
610           _attrMatchList.push_back( AttrMatchData( it->attr,
611                                     sat::AttrMatcher( rcstrings, cflags ),
612                                                       it->predicate, it->predicateStr ) );
613         }
614         else
615         {
616           // copy matcher
617          _attrMatchList.push_back( *it );
618         }
619       }
620     }
621
622     // If no attributes defined at all, then add 'query all'
623     if ( _attrMatchList.empty() )
624     {
625       cflags = _flags;
626       rcstrings = createRegex( _strings, cflags );
627       if ( _strings.size() > 1 ) // switch to regex for multiple strings
628         cflags.setModeRegex();
629       _attrMatchList.push_back( AttrMatchData( sat::SolvAttr::allAttr,
630                                 sat::AttrMatcher( rcstrings, cflags ) ) );
631     }
632
633     // Finally check here, whether all involved regex compile.
634     for_( it, _attrMatchList.begin(), _attrMatchList.end() )
635     {
636       it->attrMatcher.compile(); // throws on error
637     }
638     //DBG << asString() << endl;
639   }
640
641
642   /**
643    * Converts '*' and '?' wildcards within str into their regex equivalents.
644    */
645   static string wildcards2regex(const string & str)
646   {
647     string regexed = str;
648
649     string r_all(".*"); // regex equivalent of '*'
650     string r_one(".");  // regex equivalent of '?'
651     string::size_type pos;
652
653     // replace all "*" in input with ".*"
654     for (pos = 0; (pos = regexed.find("*", pos)) != std::string::npos; pos+=2)
655       regexed = regexed.replace(pos, 1, r_all);
656
657     // replace all "?" in input with "."
658     for (pos = 0; (pos = regexed.find('?', pos)) != std::string::npos; ++pos)
659       regexed = regexed.replace(pos, 1, r_one);
660
661     return regexed;
662   }
663
664   string PoolQuery::Impl::createRegex( const StrContainer & container, const Match & flags ) const
665   {
666 //! macro for word boundary tags for regexes
667 #define WB (_match_word ? string("\\b") : string())
668     string rstr;
669
670     if (container.empty())
671       return rstr;
672
673     if (container.size() == 1)
674     {
675       return WB + *container.begin() + WB;
676     }
677
678     // multiple strings
679
680     bool use_wildcards = flags.isModeGlob();
681     StrContainer::const_iterator it = container.begin();
682     string tmp;
683
684     if (use_wildcards)
685       tmp = wildcards2regex(*it);
686     else
687       tmp = *it;
688
689     if (_require_all)
690     {
691       if ( ! flags.isModeString() ) // not match exact
692         tmp += ".*" + WB + tmp;
693       rstr = "(?=" + tmp + ")";
694     }
695     else
696     {
697       if ( flags.isModeString() || flags.isModeGlob() )
698         rstr = "^";
699       rstr += WB + "(" + tmp;
700     }
701
702     ++it;
703
704     for (; it != container.end(); ++it)
705     {
706       if (use_wildcards)
707         tmp = wildcards2regex(*it);
708       else
709         tmp = *it;
710
711       if (_require_all)
712       {
713         if ( ! flags.isModeString() ) // not match exact
714           tmp += ".*" + WB + tmp;
715         rstr += "(?=" + tmp + ")";
716       }
717       else
718       {
719         rstr += "|" + tmp;
720       }
721     }
722
723     if (_require_all)
724     {
725       if ( ! flags.isModeString() ) // not match exact
726         rstr += WB + ".*";
727     }
728     else
729     {
730       rstr += ")" + WB;
731       if ( flags.isModeString() || flags.isModeGlob() )
732         rstr += "$";
733     }
734
735     return rstr;
736 #undef WB
737   }
738
739   string PoolQuery::Impl::asString() const
740   {
741     ostringstream o;
742
743     o << "kinds: ";
744     if ( _kinds.empty() )
745       o << "ALL";
746     else
747     {
748       for(Kinds::const_iterator it = _kinds.begin();
749           it != _kinds.end(); ++it)
750         o << *it << " ";
751     }
752     o << endl;
753
754     o << "repos: ";
755     if ( _repos.empty() )
756       o << "ALL";
757     else
758     {
759       for(StrContainer::const_iterator it = _repos.begin();
760           it != _repos.end(); ++it)
761         o << *it << " ";
762     }
763     o << endl;
764
765     o << "version: "<< _op << " " << _edition.asString() << endl;
766     o << "status: " << ( _status_flags ? ( _status_flags == INSTALLED_ONLY ? "INSTALLED_ONLY" : "UNINSTALLED_ONLY" )
767                                        : "ALL" ) << endl;
768
769     o << "string match flags: " << Match(_flags) << endl;
770
771     // raw
772     o << "strings: ";
773     for(StrContainer::const_iterator it = _strings.begin();
774         it != _strings.end(); ++it)
775       o << *it << " ";
776     o << endl;
777
778     o << "attributes: " << endl;
779     for(AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
780     {
781       o << "* " << ai->first << ": ";
782       for(StrContainer::const_iterator vi = ai->second.begin();
783           vi != ai->second.end(); ++vi)
784         o << *vi << " ";
785       o << endl;
786     }
787
788     o << "predicated: " << endl;
789     for_( it, _uncompiledPredicated.begin(), _uncompiledPredicated.end() )
790     {
791       o << "* " << *it << endl;
792     }
793
794     // compiled
795     o << "last attribute matcher compiled: " << endl;
796     if ( _attrMatchList.empty() )
797     {
798       o << "not yet compiled" << endl;
799     }
800     else
801     {
802       for_( it, _attrMatchList.begin(), _attrMatchList.end() )
803       {
804         o << "* " << *it << endl;
805       }
806     }
807     return o.str();
808   }
809
810   ///////////////////////////////////////////////////////////////////
811
812   ///////////////////////////////////////////////////////////////////
813   //
814   //    CLASS NAME : PoolQuery
815   //
816   ///////////////////////////////////////////////////////////////////
817
818   PoolQuery::PoolQuery()
819     : _pimpl(new Impl())
820   {}
821
822   PoolQuery::~PoolQuery()
823   {}
824
825   void PoolQuery::addRepo(const std::string &repoalias)
826   {
827     if (repoalias.empty())
828     {
829       WAR << "ignoring an empty repository alias" << endl;
830       return;
831     }
832     _pimpl->_repos.insert(repoalias);
833   }
834
835   void PoolQuery::addKind(const ResKind & kind)
836   { _pimpl->_kinds.insert(kind); }
837
838   void PoolQuery::addString(const string & value)
839   { _pimpl->_strings.insert(value); }
840
841   void PoolQuery::addAttribute(const sat::SolvAttr & attr, const std::string & value)
842   { _pimpl->_attrs[attr].insert(value); }
843
844   void PoolQuery::addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition )
845   { return addDependency( attr, name, op, edition, Arch_empty ); }
846
847   void PoolQuery::addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition, const Arch & arch )
848   {
849     switch ( op.inSwitch() )
850     {
851       case Rel::ANY_e:  // no additional constraint on edition.
852         if ( arch.empty() )     // no additional constraint on arch.
853         {
854           addAttribute( attr, name );
855           return;
856         }
857         break;
858
859       case Rel::NONE_e: // will never match.
860         return;
861
862       default: // go and add the predicated query (uncompiled)
863         break;
864     }
865
866     // Match::OTHER indicates need to compile
867     // (merge global search strings into name).
868     AttrMatchData attrMatchData( attr, sat::AttrMatcher( name, Match::OTHER ) );
869
870     if ( isDependencyAttribute( attr ) )
871       attrMatchData.addPredicate( EditionRangePredicate( op, edition, arch ) );
872     else
873       attrMatchData.addPredicate( SolvableRangePredicate( op, edition, arch ) );
874
875     _pimpl->_uncompiledPredicated.insert( attrMatchData );
876   }
877
878   void PoolQuery::addDependency( const sat::SolvAttr & attr, Capability cap_r )
879   {
880     CapDetail cap( cap_r );
881     if ( ! cap.isSimple() ) // will never match.
882       return;
883
884     // Matches STRING per default. (won't get compiled!)
885     AttrMatchData attrMatchData( attr, sat::AttrMatcher( cap.name().asString() ) );
886
887     if ( isDependencyAttribute( attr ) )
888       attrMatchData.addPredicate( CapabilityMatchPredicate( cap_r ) );
889     else
890       attrMatchData.addPredicate( SolvableRangePredicate( cap.op(), cap.ed() ) );
891
892     _pimpl->_uncompiledPredicated.insert( attrMatchData );
893   }
894
895   void PoolQuery::setEdition(const Edition & edition, const Rel & op)
896   {
897     _pimpl->_edition = edition;
898     _pimpl->_op = op;
899   }
900
901   void PoolQuery::setMatchSubstring()   { _pimpl->_flags.setModeSubstring(); }
902   void PoolQuery::setMatchExact()       { _pimpl->_flags.setModeString(); }
903   void PoolQuery::setMatchRegex()       { _pimpl->_flags.setModeRegex(); }
904   void PoolQuery::setMatchGlob()        { _pimpl->_flags.setModeGlob(); }
905   void PoolQuery::setMatchWord()
906   {
907     _pimpl->_match_word = true;
908     _pimpl->_flags.setModeRegex();
909   }
910
911   Match PoolQuery::flags() const
912   { return _pimpl->_flags; }
913   void PoolQuery::setFlags( const Match & flags )
914   { _pimpl->_flags = flags; }
915
916
917   void PoolQuery::setInstalledOnly()
918   { _pimpl->_status_flags = INSTALLED_ONLY; }
919   void PoolQuery::setUninstalledOnly()
920   { _pimpl->_status_flags = UNINSTALLED_ONLY; }
921   void PoolQuery::setStatusFilterFlags( PoolQuery::StatusFilter flags )
922   { _pimpl->_status_flags = flags; }
923
924
925   void PoolQuery::setRequireAll(bool require_all)
926   { _pimpl->_require_all = require_all; }
927
928
929   const PoolQuery::StrContainer &
930   PoolQuery::strings() const
931   { return _pimpl->_strings; }
932
933   const PoolQuery::AttrRawStrMap &
934   PoolQuery::attributes() const
935   { return _pimpl->_attrs; }
936
937   const PoolQuery::StrContainer &
938   PoolQuery::attribute(const sat::SolvAttr & attr) const
939   {
940     static const PoolQuery::StrContainer nocontainer;
941     AttrRawStrMap::const_iterator it = _pimpl->_attrs.find(attr);
942     return it != _pimpl->_attrs.end() ? it->second : nocontainer;
943   }
944
945   const Edition PoolQuery::edition() const
946   { return _pimpl->_edition; }
947   const Rel PoolQuery::editionRel() const
948   { return _pimpl->_op; }
949
950
951   const PoolQuery::Kinds &
952   PoolQuery::kinds() const
953   { return _pimpl->_kinds; }
954
955   const PoolQuery::StrContainer &
956   PoolQuery::repos() const
957   { return _pimpl->_repos; }
958
959
960   bool PoolQuery::caseSensitive() const
961   { return !_pimpl->_flags.test( Match::NOCASE ); }
962   void PoolQuery::setCaseSensitive( bool value )
963   { _pimpl->_flags.turn( Match::NOCASE, !value ); }
964
965   bool PoolQuery::filesMatchFullPath() const
966   { return _pimpl->_flags.test( Match::FILES ); }
967   void PoolQuery::setFilesMatchFullPath( bool value )
968   { _pimpl->_flags.turn( Match::FILES, value ); }
969
970   bool PoolQuery::matchExact() const            { return _pimpl->_flags.isModeString(); }
971   bool PoolQuery::matchSubstring() const        { return _pimpl->_flags.isModeSubstring(); }
972   bool PoolQuery::matchGlob() const             { return _pimpl->_flags.isModeGlob(); }
973   bool PoolQuery::matchRegex() const            { return _pimpl->_flags.isModeRegex(); }
974
975   bool PoolQuery::matchWord() const
976   { return _pimpl->_match_word; }
977
978   bool PoolQuery::requireAll() const
979   { return _pimpl->_require_all; }
980
981   PoolQuery::StatusFilter PoolQuery::statusFilterFlags() const
982   { return _pimpl->_status_flags; }
983
984   bool PoolQuery::empty() const
985   {
986     try { return begin() == end(); }
987     catch (const Exception & ex) {}
988     return true;
989   }
990
991   PoolQuery::size_type PoolQuery::size() const
992   {
993     try
994     {
995       size_type count = 0;
996       for_( it, begin(), end() )
997         ++count;
998       return count;
999     }
1000     catch (const Exception & ex) {}
1001     return 0;
1002   }
1003
1004   void PoolQuery::execute(ProcessResolvable fnc)
1005   { invokeOnEach( begin(), end(), fnc); }
1006
1007
1008   ///////////////////////////////////////////////////////////////////
1009   //
1010   //  CLASS NAME : PoolQuery::Attr
1011   //
1012   /**
1013    * represents all atributes in PoolQuery except SolvAtributes, which are
1014    * used as is (not needed extend anything if someone adds new solv attr)
1015    */
1016   struct PoolQueryAttr : public IdStringType<PoolQueryAttr>
1017   {
1018   private:
1019     friend class IdStringType<PoolQueryAttr>;
1020     IdString _str;
1021   public:
1022
1023     //noAttr
1024     PoolQueryAttr(){}
1025
1026     explicit PoolQueryAttr( const char* cstr_r )
1027         : _str( cstr_r )
1028       {}
1029
1030     explicit PoolQueryAttr( const std::string & str_r )
1031         : _str( str_r )
1032       {}
1033
1034     // unknown atributes
1035     static const PoolQueryAttr noAttr;
1036
1037     // PoolQuery's own attributes
1038     static const PoolQueryAttr repoAttr;
1039     static const PoolQueryAttr kindAttr;
1040     static const PoolQueryAttr stringAttr;
1041     static const PoolQueryAttr stringTypeAttr;
1042     static const PoolQueryAttr requireAllAttr;
1043     static const PoolQueryAttr caseSensitiveAttr;
1044     static const PoolQueryAttr installStatusAttr;
1045     static const PoolQueryAttr editionAttr;
1046     static const PoolQueryAttr complexAttr;
1047   };
1048
1049   const PoolQueryAttr PoolQueryAttr::noAttr;
1050
1051   const PoolQueryAttr PoolQueryAttr::repoAttr( "repo" );
1052   const PoolQueryAttr PoolQueryAttr::kindAttr( "type" );
1053   const PoolQueryAttr PoolQueryAttr::stringAttr( "query_string" );
1054   const PoolQueryAttr PoolQueryAttr::stringTypeAttr("match_type");
1055   const PoolQueryAttr PoolQueryAttr::requireAllAttr("require_all");
1056   const PoolQueryAttr PoolQueryAttr::caseSensitiveAttr("case_sensitive");
1057   const PoolQueryAttr PoolQueryAttr::installStatusAttr("install_status");
1058   const PoolQueryAttr PoolQueryAttr::editionAttr("version");
1059   const PoolQueryAttr PoolQueryAttr::complexAttr("complex");
1060
1061   class StringTypeAttr : public IdStringType<PoolQueryAttr>
1062   {
1063     friend class IdStringType<StringTypeAttr>;
1064     IdString _str;
1065
1066   public:
1067     StringTypeAttr(){}
1068     explicit StringTypeAttr( const char* cstr_r )
1069             : _str( cstr_r ){}
1070     explicit StringTypeAttr( const std::string & str_r )
1071              : _str( str_r ){}
1072
1073     static const StringTypeAttr noAttr;
1074
1075     static const StringTypeAttr exactAttr;
1076     static const StringTypeAttr substringAttr;
1077     static const StringTypeAttr regexAttr;
1078     static const StringTypeAttr globAttr;
1079     static const StringTypeAttr wordAttr;
1080   };
1081
1082   const StringTypeAttr StringTypeAttr::noAttr;
1083
1084   const StringTypeAttr StringTypeAttr::exactAttr("exact");
1085   const StringTypeAttr StringTypeAttr::substringAttr("substring");
1086   const StringTypeAttr StringTypeAttr::regexAttr("regex");
1087   const StringTypeAttr StringTypeAttr::globAttr("glob");
1088   const StringTypeAttr StringTypeAttr::wordAttr("word");
1089
1090   ///////////////////////////////////////////////////////////////////
1091
1092
1093   //\TODO maybe ctor with stream can be usefull
1094   //\TODO let it throw, let it throw, let it throw.
1095   bool PoolQuery::recover( istream &str, char delim )
1096   {
1097     bool finded_something = false; //indicates some atributes is finded
1098     string s;
1099     do {
1100       if ( str.eof() )
1101         break;
1102
1103       getline( str, s, delim );
1104
1105       if ((!s.empty()) && s[0]=='#') //comment
1106       {
1107         continue;
1108       }
1109
1110       string::size_type pos = s.find(':');
1111       if (s.empty() || pos == s.npos) // some garbage on line... act like blank line
1112       {
1113         if (finded_something) //is first blank line after record?
1114         {
1115           break;
1116         }
1117         else
1118         {
1119           continue;
1120         }
1121       }
1122
1123       finded_something = true;
1124
1125       string attrName(str::trim(string(s,0,pos))); // trimmed name of atribute
1126       string attrValue(str::trim(string(s,pos+1,s.npos))); //trimmed value
1127
1128       PoolQueryAttr attribute( attrName );
1129
1130       MIL << "attribute name: " << attrName << endl;
1131
1132       if ( attribute==PoolQueryAttr::repoAttr )
1133       {
1134         addRepo( attrValue );
1135       }
1136       /* some backwards compatibility */
1137       else if ( attribute==PoolQueryAttr::kindAttr || attribute=="kind" )
1138       {
1139         addKind( ResKind(attrValue) );
1140       }
1141       else if ( attribute==PoolQueryAttr::stringAttr
1142         || attribute=="global_string")
1143       {
1144         addString( attrValue );
1145       }
1146       else if ( attribute==PoolQueryAttr::stringTypeAttr
1147         || attribute=="string_type" )
1148       {
1149         StringTypeAttr s(attrValue);
1150         if( s == StringTypeAttr::regexAttr )
1151         {
1152           setMatchRegex();
1153         }
1154         else if ( s == StringTypeAttr::globAttr )
1155         {
1156           setMatchGlob();
1157         }
1158         else if ( s == StringTypeAttr::exactAttr )
1159         {
1160           setMatchExact();
1161         }
1162         else if ( s == StringTypeAttr::substringAttr )
1163         {
1164           setMatchSubstring();
1165         }
1166         else if ( s == StringTypeAttr::wordAttr )
1167         {
1168           setMatchWord();
1169         }
1170         else if ( s == StringTypeAttr::noAttr )
1171         {
1172           WAR << "unknown string type " << attrValue << endl;
1173         }
1174         else
1175         {
1176           WAR << "forget recover some attribute defined as String type attribute: " << attrValue << endl;
1177         }
1178       }
1179       else if ( attribute==PoolQueryAttr::requireAllAttr )
1180       {
1181         if ( str::strToTrue(attrValue) )
1182         {
1183           setRequireAll(true);
1184         }
1185         else if ( !str::strToFalse(attrValue) )
1186         {
1187           setRequireAll(false);
1188         }
1189         else
1190         {
1191           WAR << "unknown boolean value " << attrValue << endl;
1192         }
1193       }
1194       else if ( attribute==PoolQueryAttr::caseSensitiveAttr )
1195       {
1196         if ( str::strToTrue(attrValue) )
1197         {
1198           setCaseSensitive(true);
1199         }
1200         else if ( !str::strToFalse(attrValue) )
1201         {
1202           setCaseSensitive(false);
1203         }
1204         else
1205         {
1206           WAR << "unknown boolean value " << attrValue << endl;
1207         }
1208       }
1209       else if ( attribute==PoolQueryAttr::installStatusAttr )
1210       {
1211         if( attrValue == "all" )
1212         {
1213           setStatusFilterFlags( ALL );
1214         }
1215         else if( attrValue == "installed" )
1216         {
1217           setInstalledOnly();
1218         }
1219         else if( attrValue == "not-installed" )
1220         {
1221           setUninstalledOnly();
1222         }
1223         else
1224         {
1225           WAR << "Unknown value for install status " << attrValue << endl;
1226         }
1227       }
1228       else if ( attribute == PoolQueryAttr::editionAttr)
1229       {
1230         string::size_type pos;
1231         Rel rel("==");
1232         if (attrValue.find_first_of("=<>!") == 0)
1233         {
1234           pos = attrValue.find_last_of("=<>");
1235           rel = Rel(attrValue.substr(0, pos+1));
1236           attrValue = str::trim(attrValue.substr(pos+1, attrValue.npos));
1237         }
1238
1239         setEdition(Edition(attrValue), rel);
1240       }
1241       else if ( attribute == PoolQueryAttr::complexAttr )
1242       {
1243         try
1244         {
1245           _pimpl->_uncompiledPredicated.insert( AttrMatchData::deserialize( attrValue ) );
1246         }
1247         catch ( const Exception & err )
1248         {
1249           WAR << "Unparsable value for complex: " << err.asUserHistory() << endl;
1250
1251         }
1252       }
1253       else if ( attribute==PoolQueryAttr::noAttr )
1254       {
1255         WAR << "empty attribute name" << endl;
1256       }
1257       else
1258       {
1259         string s = attrName;
1260         str::replaceAll( s,"_",":" );
1261         SolvAttr a(s);
1262         if ( a == SolvAttr::name || isDependencyAttribute( a ) )
1263         {
1264           Capability c( attrValue );
1265           CapDetail d( c );
1266           if ( d.isVersioned() )
1267             addDependency( a, d.name().asString(), d.op(), d.ed() );
1268           else
1269             addDependency( a, attrValue );
1270         }
1271         else
1272           addAttribute( a, attrValue );
1273       }
1274
1275     } while ( true );
1276
1277     return finded_something;
1278   }
1279
1280   void PoolQuery::serialize( ostream &str, char delim ) const
1281   {
1282     //separating delim
1283     str << delim;
1284     //iterate thrue all settings and write it
1285     static const zypp::PoolQuery q; //not save default options, so create default query example
1286
1287     for_( it, repos().begin(), repos().end() )
1288     {
1289       str << "repo: " << *it << delim ;
1290     }
1291
1292     for_( it, kinds().begin(), kinds().end() )
1293     {
1294       str << PoolQueryAttr::kindAttr.asString() << ": "
1295           << it->idStr() << delim ;
1296     }
1297
1298     if (editionRel() != Rel::ANY && edition() != Edition::noedition)
1299       str << PoolQueryAttr::editionAttr.asString() << ": " << editionRel() << " " << edition() << delim;
1300
1301     if (matchMode()!=q.matchMode())
1302     {
1303       switch( matchMode() )
1304       {
1305       case Match::STRING:
1306         str << PoolQueryAttr::stringTypeAttr.asString() << ": exact" << delim;
1307         break;
1308       case Match::SUBSTRING:
1309         str << PoolQueryAttr::stringTypeAttr.asString()
1310             << ": substring" << delim;
1311         break;
1312       case Match::GLOB:
1313         str << PoolQueryAttr::stringTypeAttr.asString() << ": glob" << delim;
1314         break;
1315       case Match::REGEX:
1316         str << PoolQueryAttr::stringTypeAttr.asString() << ": regex" << delim;
1317         break;
1318       default:
1319         WAR << "unknown match type "  << matchMode() << endl;
1320       }
1321     }
1322
1323     if( caseSensitive() != q.caseSensitive() )
1324     {
1325       str << "case_sensitive: ";
1326       if (caseSensitive())
1327       {
1328         str << "on" << delim;
1329       }
1330       else
1331       {
1332         str << "off" << delim;
1333       }
1334     }
1335
1336     if( requireAll() != q.requireAll() )
1337     {
1338       str << "require_all: ";
1339       if (requireAll())
1340       {
1341         str << "on" << delim;
1342       }
1343       else
1344       {
1345         str << "off" << delim;
1346       }
1347     }
1348
1349     if( statusFilterFlags() != q.statusFilterFlags() )
1350     {
1351       switch( statusFilterFlags() )
1352       {
1353       case ALL:
1354         str << "install_status: all" << delim;
1355         break;
1356       case INSTALLED_ONLY:
1357         str << "install_status: installed" << delim;
1358         break;
1359       case UNINSTALLED_ONLY:
1360         str << "install_status: not-installed" << delim;
1361         break;
1362       }
1363     }
1364
1365     for_( it, strings().begin(), strings().end() )
1366     {
1367       str << PoolQueryAttr::stringAttr.asString()<< ": " << *it << delim;
1368     }
1369
1370     for_( it, attributes().begin(), attributes().end() )
1371     {
1372       string s = it->first.asString();
1373       str::replaceAll(s,":","_");
1374       for_( it2,it->second.begin(),it->second.end() )
1375       {
1376         str << s <<": "<< *it2 << delim;
1377       }
1378     }
1379
1380     for_( it, _pimpl->_uncompiledPredicated.begin(), _pimpl->_uncompiledPredicated.end() )
1381     {
1382       str << "complex: "<< it->serialize() << delim;
1383     }
1384
1385     //separating delim - protection
1386     str << delim;
1387   }
1388
1389   string PoolQuery::asString() const
1390   { return _pimpl->asString(); }
1391
1392   ostream & operator<<( ostream & str, const PoolQuery & obj )
1393   { return str << obj.asString(); }
1394
1395   std::ostream & dumpOn( std::ostream & str, const PoolQuery & obj )
1396   { return dumpRange( str << obj, obj.begin(), obj.end() ); }
1397
1398   bool PoolQuery::operator==( const PoolQuery & rhs ) const
1399   { return *_pimpl == *rhs._pimpl; }
1400
1401   ///////////////////////////////////////////////////////////////////
1402   namespace detail
1403   { /////////////////////////////////////////////////////////////////
1404
1405     ///////////////////////////////////////////////////////////////////
1406     //
1407     //  CLASS NAME : PoolQueryMatcher
1408     //
1409     /** Store \ref PoolQuery settings and assist \ref PoolQueryIterator.
1410      *
1411      * Basically the matcher performs a base query, which should preselect
1412      * candidates for a match. And has some filter conditions on top of it.
1413      * Query and fileter depend on the \ref PoolQuery settings.
1414      *
1415      * Matcher must be stateless, as it is shared between multiple
1416      * \ref PoolQueryIterator instances.
1417      *
1418      * If \ref base_iterator is at the \ref end, \ref advance moves it
1419      * to the first match. Otherwise advance moves to the next match, or
1420      * to the \ref end, if there is no more match.
1421      *
1422      * \note The original implementation treated an empty search string as
1423      * <it>"match always"</it>. We stay compatible.
1424      */
1425     class PoolQueryMatcher
1426     {
1427       public:
1428         typedef sat::LookupAttr::iterator base_iterator;
1429
1430       public:
1431         const base_iterator & end() const
1432         {
1433           static base_iterator _end;
1434           return _end;
1435         }
1436
1437         bool advance( base_iterator & base_r ) const
1438         {
1439           if ( base_r == end() )
1440             base_r = startNewQyery(); // first candidate
1441           else
1442           {
1443             base_r.nextSkipSolvable(); // assert we don't visit this Solvable again
1444             ++base_r; // advance to next candidate
1445           }
1446
1447           while ( base_r != end() )
1448           {
1449             if ( isAMatch( base_r ) )
1450               return true;
1451             // No match: try next
1452             ++base_r;
1453           }
1454           return false;
1455         }
1456
1457         /** Provide all matching attributes within this solvable.
1458          *
1459          */
1460         void matchDetail( const base_iterator & base_r, std::vector<base_iterator> & return_r ) const
1461         {
1462           if ( base_r == end() )
1463             return;
1464
1465           sat::Solvable inSolvable( base_r.inSolvable() );
1466
1467           if ( _attrMatchList.size() == 1 )
1468           {
1469             // base_r is already on the 1st matching attribute!
1470             // String matching is done by the base iterator. We must check the predicate here.
1471             // Let's see if there are more matches for this solvable:
1472             base_iterator base( base_r );
1473             base.stayInThisSolvable(); // avoid discarding matches we found far away from here.
1474             return_r.push_back( base );
1475
1476             const AttrMatchData::Predicate & predicate( _attrMatchList.front().predicate );
1477             for ( ++base; base.inSolvable() == inSolvable; ++base ) // safe even if base == end()
1478             {
1479               if ( ! predicate || predicate( base ) )
1480                 return_r.push_back( base );
1481             }
1482           }
1483           else
1484           {
1485             // Here: search all attributes ;(
1486             for_( mi, _attrMatchList.begin(), _attrMatchList.end() )
1487             {
1488               const AttrMatchData & matchData( *mi );
1489               sat::LookupAttr q( matchData.attr, inSolvable );
1490               if ( matchData.attrMatcher ) // an empty searchstring matches always
1491                 q.setAttrMatcher( matchData.attrMatcher );
1492
1493               if ( ! q.empty() ) // there are matches.
1494               {
1495                 // now check any predicate:
1496                 const AttrMatchData::Predicate & predicate( matchData.predicate );
1497                 for_( it, q.begin(), q.end() )
1498                 {
1499                   if ( ! predicate || predicate( it ) )
1500                     return_r.push_back( it );
1501                 }
1502               }
1503             }
1504           }
1505         }
1506
1507       public:
1508         /** Ctor stores the \ref PoolQuery settings.
1509          * \throw MatchException Any of the exceptions thrown by \ref PoolQuery::Impl::compile.
1510          */
1511         PoolQueryMatcher( const shared_ptr<const PoolQuery::Impl> & query_r )
1512         {
1513           query_r->compile();
1514
1515           // Repo restriction:
1516           sat::Pool satpool( sat::Pool::instance() );
1517
1518           for_( it, query_r->_repos.begin(), query_r->_repos.end() )
1519           {
1520             Repository r( satpool.reposFind( *it ) );
1521             if ( r )
1522               _repos.insert( r );
1523             else
1524               _neverMatchRepo = true;
1525           }
1526           // _neverMatchRepo: we just need to catch the case that no repo
1527           // matched, so we'd interpret the empty list as 'take from all'
1528           if ( _neverMatchRepo && ! _repos.empty() )
1529             _neverMatchRepo = false;
1530
1531           // Kind restriction:
1532           _kinds = query_r->_kinds;
1533           // Edition restriction:
1534           _op      = query_r->_op;
1535           _edition = query_r->_edition;
1536           // Status restriction:
1537           _status_flags = query_r->_status_flags;
1538           // AttrMatcher
1539           _attrMatchList = query_r->_attrMatchList;
1540         }
1541
1542         ~PoolQueryMatcher()
1543         {}
1544
1545       private:
1546         /** Initialize a new base query. */
1547         base_iterator startNewQyery() const
1548         {
1549           sat::LookupAttr q;
1550
1551           if ( _neverMatchRepo )
1552             return q.end();
1553
1554           // Repo restriction:
1555           if ( _repos.size() == 1 )
1556             q.setRepo( *_repos.begin() );
1557           // else: handled in isAMatch.
1558
1559           // Attribute restriction:
1560           if ( _attrMatchList.size() == 1 ) // all (SolvAttr::allAttr) or 1 attr
1561           {
1562             const AttrMatchData & matchData( _attrMatchList.front() );
1563             q.setAttr( matchData.attr );
1564             if ( matchData.attrMatcher ) // empty searchstring matches always
1565               q.setAttrMatcher( matchData.attrMatcher );
1566           }
1567           else // more than 1 attr (but not all)
1568           {
1569             // no restriction, it's all handled in isAMatch.
1570             q.setAttr( sat::SolvAttr::allAttr );
1571           }
1572
1573           return q.begin();
1574         }
1575
1576
1577         /** Check whether we are on a match.
1578          *
1579          * The check covers the whole Solvable, not just the current
1580          * attribute \c base_r points to. If there's no match, also
1581          * prepare \c base_r to advance appropriately. If there is
1582          * a match, simply return \c true. \ref advance always moves
1583          * to the next Solvable if there was a match.
1584          *
1585          * \note: Caller asserts we're not at \ref end.
1586         */
1587         bool isAMatch( base_iterator & base_r ) const
1588         {
1589           /////////////////////////////////////////////////////////////////////
1590           Repository inRepo( base_r.inRepo() );
1591           // Status restriction:
1592           if ( _status_flags
1593              && ( (_status_flags == PoolQuery::INSTALLED_ONLY) != inRepo.isSystemRepo() ) )
1594           {
1595             base_r.nextSkipRepo();
1596             return false;
1597           }
1598           // Repo restriction:
1599           if ( _repos.size() > 1 && _repos.find( inRepo ) == _repos.end() )
1600           {
1601             base_r.nextSkipRepo();
1602             return false;
1603           }
1604           /////////////////////////////////////////////////////////////////////
1605           sat::Solvable inSolvable( base_r.inSolvable() );
1606           // Kind restriction:
1607           if ( ! _kinds.empty() && ! inSolvable.isKind( _kinds.begin(), _kinds.end() ) )
1608           {
1609             base_r.nextSkipSolvable();
1610             return false;
1611           }
1612
1613           // Edition restriction:
1614           if ( _op != Rel::ANY && !compareByRel( _op, inSolvable.edition(), _edition, Edition::Match() ) )
1615           {
1616             base_r.nextSkipSolvable();
1617             return false;
1618           }
1619           /////////////////////////////////////////////////////////////////////
1620           // string and predicate matching:
1621
1622           if ( _attrMatchList.size() == 1 )
1623           {
1624             // String matching was done by the base iterator.
1625             // Now check any predicate:
1626             const AttrMatchData::Predicate & predicate( _attrMatchList.front().predicate );
1627             if ( ! predicate || predicate( base_r ) )
1628               return true;
1629
1630             return false; // no skip as there may be more occurrences od this attr.
1631           }
1632
1633           // Here: search all attributes ;(
1634           for_( mi, _attrMatchList.begin(), _attrMatchList.end() )
1635           {
1636             const AttrMatchData & matchData( *mi );
1637             sat::LookupAttr q( matchData.attr, inSolvable );
1638             if ( matchData.attrMatcher ) // an empty searchstring matches always
1639               q.setAttrMatcher( matchData.attrMatcher );
1640
1641             if ( ! q.empty() ) // there are matches.
1642             {
1643               // now check any predicate:
1644               const AttrMatchData::Predicate & predicate( matchData.predicate );
1645               if ( predicate )
1646               {
1647                 for_( it, q.begin(), q.end() )
1648                 {
1649                   if ( predicate( it ) )
1650                     return true;
1651                 }
1652               }
1653               else
1654                 return true;
1655             }
1656           }
1657           base_r.nextSkipSolvable();
1658           return false;
1659         }
1660
1661       private:
1662         /** Repositories include in the search. */
1663         std::set<Repository> _repos;
1664         DefaultIntegral<bool,false> _neverMatchRepo;
1665         /** Resolvable kinds to include. */
1666         std::set<ResKind> _kinds;
1667         /** Edition filter. */
1668         Rel _op;
1669         Edition _edition;
1670         /** Installed status filter flags. \see PoolQuery::StatusFilter */
1671         int _status_flags;
1672         /** AttrMatcher per attribtue. */
1673         AttrMatchList _attrMatchList;
1674     };
1675     ///////////////////////////////////////////////////////////////////
1676
1677     void PoolQueryIterator::increment()
1678     {
1679       // matcher restarts if at end! It is called from the ctor
1680       // to get the 1st match. But if the end is reached, it should
1681       // be deleted, otherwise we'd start over again.
1682       if ( !_matcher )
1683         return; // at end
1684       if ( _matches )
1685         _matches.reset(); // invalidate old matches
1686       if ( ! _matcher->advance( base_reference() ) )
1687         _matcher.reset();
1688     }
1689
1690     const PoolQueryIterator::Matches & PoolQueryIterator::matches() const
1691     {
1692       if ( _matches )
1693         return *_matches;
1694
1695       if ( !_matcher )
1696       {
1697         // at end of query:
1698         static const Matches _none;
1699         return _none;
1700       }
1701
1702       _matches.reset( new Matches );
1703       _matcher->matchDetail( base_reference(), *_matches );
1704       return *_matches;
1705     }
1706
1707     std::ostream & dumpOn( std::ostream & str, const PoolQueryIterator & obj )
1708     {
1709       str << *obj;
1710       if ( ! obj.matchesEmpty() )
1711       {
1712         for_( it, obj.matchesBegin(), obj.matchesEnd() )
1713         {
1714           str << endl << "    " << it->inSolvAttr() << "\t" << it->asString();
1715         }
1716       }
1717       return str;
1718     }
1719
1720     ///////////////////////////////////////////////////////////////////
1721   } //namespace detail
1722   ///////////////////////////////////////////////////////////////////
1723
1724   detail::PoolQueryIterator PoolQuery::begin() const
1725   {
1726     return shared_ptr<detail::PoolQueryMatcher>( new detail::PoolQueryMatcher( _pimpl.getPtr() ) );
1727   }
1728
1729   /////////////////////////////////////////////////////////////////
1730 } // namespace zypp
1731 ///////////////////////////////////////////////////////////////////
1732