Imported Upstream version 14.45.0
[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/base/StrMatcher.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 StrMatcher
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 strMatcher.
172      *
173      * Example for such a \ref predicate would be an additional edition range
174      * check whan looking for dependencies. The \ref strMatcher 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 StrMatcher & strMatcher_r )
195         : attr( attr_r )
196         , strMatcher( strMatcher_r )
197       {}
198
199       AttrMatchData( sat::SolvAttr attr_r, const StrMatcher & strMatcher_r,
200                      const Predicate & predicate_r, const std::string & predicateStr_r )
201         : attr( attr_r )
202         , strMatcher( strMatcher_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, strMatcher.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, strMatcher.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.strMatcher = StrMatcher( words[2] );
252         if ( words[3] == "C" )
253           ret.strMatcher.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       StrMatcher strMatcher;
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.strMatcher;
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.strMatcher == rhs.strMatcher
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.strMatcher != rhs.strMatcher )
336         return (  lhs.strMatcher < rhs.strMatcher );
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       if ( _flags == rhs._flags
405         // bnc#792901: while libzypp uses exact match mode for a single
406         // package name lock, zypper always uses glob. :(
407         // We unify those two forms to enable zypper to remove zypp locks
408         // without need to actually evaluate the query (which would require
409         // repos to be loaded).
410         || ( ( ( _flags.isModeString() && rhs._flags.isModeGlob() )
411             || ( _flags.isModeGlob() && rhs._flags.isModeString() ) )
412           && _strings.empty()
413           && _attrs.size() == 1
414           && _attrs.begin()->first == sat::SolvAttr::name ) )
415       {
416         return ( _strings == rhs._strings
417               && _attrs == rhs._attrs
418               && _uncompiledPredicated == rhs._uncompiledPredicated
419               && _match_word == rhs._match_word
420               && _require_all == rhs._require_all
421               && _status_flags == rhs._status_flags
422               && _edition == rhs._edition
423               && _op == rhs._op
424               && _repos == rhs._repos
425               && _kinds == rhs._kinds );
426       }
427       return false;
428     }
429
430     bool operator!=( const PoolQuery::Impl & rhs ) const
431     { return ! operator==( rhs ); }
432
433   public:
434     /** Compile the regex.
435      * Basically building the \ref _attrMatchList from strings.
436      * \throws MatchException Any of the exceptions thrown by \ref StrMatcher::compile.
437      */
438     void compile() const;
439
440     /** StrMatcher per attribtue. */
441     mutable AttrMatchList _attrMatchList;
442
443   private:
444     /** Pass flags from \ref compile, as they may have been changed. */
445     string createRegex( const StrContainer & container, const Match & flags ) const;
446
447   private:
448     friend Impl * rwcowClone<Impl>( const Impl * rhs );
449     /** clone for RWCOW_pointer */
450     Impl * clone() const
451     { return new Impl( *this ); }
452   };
453
454   ///////////////////////////////////////////////////////////////////
455
456   struct MyInserter
457   {
458     MyInserter(PoolQuery::StrContainer & cont) : _cont(cont) {}
459
460     bool operator()(const string & str)
461     {
462       _cont.insert(str);
463       return true;
464     }
465
466     PoolQuery::StrContainer & _cont;
467   };
468
469
470   struct EmptyFilter
471   {
472     bool operator()(const string & str)
473     {
474       return !str.empty();
475     }
476   };
477
478   void PoolQuery::Impl::compile() const
479   {
480     _attrMatchList.clear();
481
482     Match cflags( _flags );
483     if ( cflags.mode() == Match::OTHER ) // this will never succeed...
484       ZYPP_THROW( MatchUnknownModeException( cflags ) );
485
486     /** Compiled search strings. */
487     string rcstrings;
488
489
490     // 'different'         - will have to iterate through all and match by ourselves (slow)
491     // 'same'              - will pass the compiled string to dataiterator_init
492     // 'one-attr'          - will pass it to dataiterator_init
493     // 'one-non-regex-str' - will pass to dataiterator_init, set flag to SEARCH_STRING or SEARCH_SUBSTRING
494
495     // // NO ATTRIBUTE
496     // else
497     //   for all _strings
498     //     create regex; store in rcstrings; if more strings flag regex;
499     if (_attrs.empty())
500     {
501       ; // A default 'query-all' will be added after all sources are processed.
502     }
503
504     // // ONE ATTRIBUTE
505     // else if _attrs is not empty but it contains just one attr
506     //   for all _strings and _attr[key] strings
507     //     create regex; flag 'one-attr'; if more strings flag regex;
508     else if (_attrs.size() == 1)
509     {
510       StrContainer joined;
511       invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
512       invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
513       rcstrings = createRegex(joined, cflags);
514       if (joined.size() > 1) // switch to regex for multiple strings
515         cflags.setModeRegex();
516       _attrMatchList.push_back( AttrMatchData( _attrs.begin()->first,
517                                 StrMatcher( rcstrings, cflags ) ) );
518     }
519
520     // // MULTIPLE ATTRIBUTES
521     else
522     {
523       // check whether there are any per-attribute strings
524       bool attrvals_empty = true;
525       for (AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
526         if (!ai->second.empty())
527           for(StrContainer::const_iterator it = ai->second.begin();
528               it != ai->second.end(); it++)
529             if (!it->empty())
530             {
531               attrvals_empty = false;
532               goto attremptycheckend;
533             }
534 attremptycheckend:
535
536       // chceck whether the per-attribute strings are all the same
537       bool attrvals_thesame = true;
538       AttrRawStrMap::const_iterator ai = _attrs.begin();
539       const StrContainer & set1 = ai->second;
540       ++ai;
541       for (; ai != _attrs.end(); ++ai)
542       {
543         StrContainer result;
544         set_difference(
545           set1.begin(), set1.end(),
546           ai->second.begin(), ai->second.end(),
547           inserter(result, result.begin())/*, ltstr()*/);
548         if (!result.empty())
549         {
550           attrvals_thesame = false;
551           break;
552         }
553       }
554
555       // // THE SAME STRINGS FOR DIFFERENT ATTRS
556       // else if _attrs is not empty but it does not contain strings
557       //   for each key in _attrs take all _strings
558       //     create regex; store in rcstrings; flag 'same'; if more strings flag regex;
559       if (attrvals_empty || attrvals_thesame)
560       {
561         StrContainer joined;
562         if (attrvals_empty)
563         {
564           invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
565           rcstrings = createRegex(joined, cflags);
566         }
567         else
568         {
569           invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
570           invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
571           rcstrings = createRegex(joined, cflags);
572         }
573         if (joined.size() > 1) // switch to regex for multiple strings
574           cflags.setModeRegex();
575         // May use the same StrMatcher for all
576         StrMatcher matcher( rcstrings, cflags );
577         for_( ai, _attrs.begin(), _attrs.end() )
578         {
579           _attrMatchList.push_back( AttrMatchData( ai->first, matcher ) );
580         }
581       }
582
583       // // DIFFERENT STRINGS FOR DIFFERENT ATTRS
584       // if _attrs is not empty and it contains non-empty vectors with non-empty strings
585       //   for each key in _attrs take all _strings + all _attrs[key] strings
586       //     create regex; flag 'different'; if more strings flag regex;
587       else
588       {
589         for_(ai, _attrs.begin(), _attrs.end())
590         {
591           StrContainer joined;
592           invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
593           invokeOnEach(ai->second.begin(), ai->second.end(), EmptyFilter(), MyInserter(joined));
594           string s = createRegex(joined, cflags);
595           if (joined.size() > 1) // switch to regex for multiple strings
596             cflags.setModeRegex();
597           _attrMatchList.push_back( AttrMatchData( ai->first,
598                                     StrMatcher( s, cflags ) ) );
599         }
600       }
601     }
602
603     // Now handle any predicated queries
604     if ( ! _uncompiledPredicated.empty() )
605     {
606       StrContainer global;
607       invokeOnEach( _strings.begin(), _strings.end(), EmptyFilter(), MyInserter(global) );
608       for_( it, _uncompiledPredicated.begin(), _uncompiledPredicated.end() )
609       {
610         if ( it->strMatcher.flags().mode() == Match::OTHER )
611         {
612           // need to compile:
613           StrContainer joined( global );
614           const std::string & mstr( it->strMatcher.searchstring() );
615           if ( ! mstr.empty() )
616             joined.insert( mstr );
617
618           cflags = _flags;
619           rcstrings = createRegex( joined, cflags );
620           if ( joined.size() > 1 ) // switch to regex for multiple strings
621             cflags.setModeRegex();
622
623           _attrMatchList.push_back( AttrMatchData( it->attr,
624                                     StrMatcher( rcstrings, cflags ),
625                                                       it->predicate, it->predicateStr ) );
626         }
627         else
628         {
629           // copy matcher
630          _attrMatchList.push_back( *it );
631         }
632       }
633     }
634
635     // If no attributes defined at all, then add 'query all'
636     if ( _attrMatchList.empty() )
637     {
638       cflags = _flags;
639       rcstrings = createRegex( _strings, cflags );
640       if ( _strings.size() > 1 ) // switch to regex for multiple strings
641         cflags.setModeRegex();
642       _attrMatchList.push_back( AttrMatchData( sat::SolvAttr::allAttr,
643                                 StrMatcher( rcstrings, cflags ) ) );
644     }
645
646     // Finally check here, whether all involved regex compile.
647     for_( it, _attrMatchList.begin(), _attrMatchList.end() )
648     {
649       it->strMatcher.compile(); // throws on error
650     }
651     //DBG << asString() << endl;
652   }
653
654
655   /**
656    * Converts '*' and '?' wildcards within str into their regex equivalents.
657    */
658   static string wildcards2regex(const string & str)
659   {
660     string regexed = str;
661
662     string r_all(".*"); // regex equivalent of '*'
663     string r_one(".");  // regex equivalent of '?'
664     string::size_type pos;
665
666     // replace all "*" in input with ".*"
667     for (pos = 0; (pos = regexed.find("*", pos)) != std::string::npos; pos+=2)
668       regexed = regexed.replace(pos, 1, r_all);
669
670     // replace all "?" in input with "."
671     for (pos = 0; (pos = regexed.find('?', pos)) != std::string::npos; ++pos)
672       regexed = regexed.replace(pos, 1, r_one);
673
674     return regexed;
675   }
676
677   string PoolQuery::Impl::createRegex( const StrContainer & container, const Match & flags ) const
678   {
679 //! macro for word boundary tags for regexes
680 #define WB (_match_word ? string("\\b") : string())
681     string rstr;
682
683     if (container.empty())
684       return rstr;
685
686     if (container.size() == 1)
687     {
688       return WB + *container.begin() + WB;
689     }
690
691     // multiple strings
692
693     bool use_wildcards = flags.isModeGlob();
694     StrContainer::const_iterator it = container.begin();
695     string tmp;
696
697     if (use_wildcards)
698       tmp = wildcards2regex(*it);
699     else
700       tmp = *it;
701
702     if (_require_all)
703     {
704       if ( ! flags.isModeString() ) // not match exact
705         tmp += ".*" + WB + tmp;
706       rstr = "(?=" + tmp + ")";
707     }
708     else
709     {
710       if ( flags.isModeString() || flags.isModeGlob() )
711         rstr = "^";
712       rstr += WB + "(" + tmp;
713     }
714
715     ++it;
716
717     for (; it != container.end(); ++it)
718     {
719       if (use_wildcards)
720         tmp = wildcards2regex(*it);
721       else
722         tmp = *it;
723
724       if (_require_all)
725       {
726         if ( ! flags.isModeString() ) // not match exact
727           tmp += ".*" + WB + tmp;
728         rstr += "(?=" + tmp + ")";
729       }
730       else
731       {
732         rstr += "|" + tmp;
733       }
734     }
735
736     if (_require_all)
737     {
738       if ( ! flags.isModeString() ) // not match exact
739         rstr += WB + ".*";
740     }
741     else
742     {
743       rstr += ")" + WB;
744       if ( flags.isModeString() || flags.isModeGlob() )
745         rstr += "$";
746     }
747
748     return rstr;
749 #undef WB
750   }
751
752   string PoolQuery::Impl::asString() const
753   {
754     ostringstream o;
755
756     o << "kinds: ";
757     if ( _kinds.empty() )
758       o << "ALL";
759     else
760     {
761       for(Kinds::const_iterator it = _kinds.begin();
762           it != _kinds.end(); ++it)
763         o << *it << " ";
764     }
765     o << endl;
766
767     o << "repos: ";
768     if ( _repos.empty() )
769       o << "ALL";
770     else
771     {
772       for(StrContainer::const_iterator it = _repos.begin();
773           it != _repos.end(); ++it)
774         o << *it << " ";
775     }
776     o << endl;
777
778     o << "version: "<< _op << " " << _edition.asString() << endl;
779     o << "status: " << ( _status_flags ? ( _status_flags == INSTALLED_ONLY ? "INSTALLED_ONLY" : "UNINSTALLED_ONLY" )
780                                        : "ALL" ) << endl;
781
782     o << "string match flags: " << Match(_flags) << endl;
783
784     // raw
785     o << "strings: ";
786     for(StrContainer::const_iterator it = _strings.begin();
787         it != _strings.end(); ++it)
788       o << *it << " ";
789     o << endl;
790
791     o << "attributes: " << endl;
792     for(AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
793     {
794       o << "* " << ai->first << ": ";
795       for(StrContainer::const_iterator vi = ai->second.begin();
796           vi != ai->second.end(); ++vi)
797         o << *vi << " ";
798       o << endl;
799     }
800
801     o << "predicated: " << endl;
802     for_( it, _uncompiledPredicated.begin(), _uncompiledPredicated.end() )
803     {
804       o << "* " << *it << endl;
805     }
806
807     // compiled
808     o << "last attribute matcher compiled: " << endl;
809     if ( _attrMatchList.empty() )
810     {
811       o << "not yet compiled" << endl;
812     }
813     else
814     {
815       for_( it, _attrMatchList.begin(), _attrMatchList.end() )
816       {
817         o << "* " << *it << endl;
818       }
819     }
820     return o.str();
821   }
822
823   ///////////////////////////////////////////////////////////////////
824
825   ///////////////////////////////////////////////////////////////////
826   //
827   //    CLASS NAME : PoolQuery
828   //
829   ///////////////////////////////////////////////////////////////////
830
831   PoolQuery::PoolQuery()
832     : _pimpl(new Impl())
833   {}
834
835   PoolQuery::~PoolQuery()
836   {}
837
838   void PoolQuery::addRepo(const std::string &repoalias)
839   {
840     if (repoalias.empty())
841     {
842       WAR << "ignoring an empty repository alias" << endl;
843       return;
844     }
845     _pimpl->_repos.insert(repoalias);
846   }
847
848   void PoolQuery::addKind(const ResKind & kind)
849   { _pimpl->_kinds.insert(kind); }
850
851   void PoolQuery::addString(const string & value)
852   { _pimpl->_strings.insert(value); }
853
854   void PoolQuery::addAttribute(const sat::SolvAttr & attr, const std::string & value)
855   { _pimpl->_attrs[attr].insert(value); }
856
857   void PoolQuery::addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition )
858   { return addDependency( attr, name, op, edition, Arch_empty ); }
859
860   void PoolQuery::addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition, const Arch & arch )
861   {
862     switch ( op.inSwitch() )
863     {
864       case Rel::ANY_e:  // no additional constraint on edition.
865         if ( arch.empty() )     // no additional constraint on arch.
866         {
867           addAttribute( attr, name );
868           return;
869         }
870         break;
871
872       case Rel::NONE_e: // will never match.
873         return;
874
875       default: // go and add the predicated query (uncompiled)
876         break;
877     }
878
879     // Match::OTHER indicates need to compile
880     // (merge global search strings into name).
881     AttrMatchData attrMatchData( attr, StrMatcher( name, Match::OTHER ) );
882
883     if ( isDependencyAttribute( attr ) )
884       attrMatchData.addPredicate( EditionRangePredicate( op, edition, arch ) );
885     else
886       attrMatchData.addPredicate( SolvableRangePredicate( op, edition, arch ) );
887
888     _pimpl->_uncompiledPredicated.insert( attrMatchData );
889   }
890
891   void PoolQuery::addDependency( const sat::SolvAttr & attr, Capability cap_r )
892   {
893     CapDetail cap( cap_r );
894     if ( ! cap.isSimple() ) // will never match.
895       return;
896
897     // Matches STRING per default. (won't get compiled!)
898     AttrMatchData attrMatchData( attr, StrMatcher( cap.name().asString() ) );
899
900     if ( isDependencyAttribute( attr ) )
901       attrMatchData.addPredicate( CapabilityMatchPredicate( cap_r ) );
902     else
903       attrMatchData.addPredicate( SolvableRangePredicate( cap.op(), cap.ed() ) );
904
905     _pimpl->_uncompiledPredicated.insert( attrMatchData );
906   }
907
908   void PoolQuery::setEdition(const Edition & edition, const Rel & op)
909   {
910     _pimpl->_edition = edition;
911     _pimpl->_op = op;
912   }
913
914   void PoolQuery::setMatchSubstring()   { _pimpl->_flags.setModeSubstring(); }
915   void PoolQuery::setMatchExact()       { _pimpl->_flags.setModeString(); }
916   void PoolQuery::setMatchRegex()       { _pimpl->_flags.setModeRegex(); }
917   void PoolQuery::setMatchGlob()        { _pimpl->_flags.setModeGlob(); }
918   void PoolQuery::setMatchWord()
919   {
920     _pimpl->_match_word = true;
921     _pimpl->_flags.setModeRegex();
922   }
923
924   Match PoolQuery::flags() const
925   { return _pimpl->_flags; }
926   void PoolQuery::setFlags( const Match & flags )
927   { _pimpl->_flags = flags; }
928
929
930   void PoolQuery::setInstalledOnly()
931   { _pimpl->_status_flags = INSTALLED_ONLY; }
932   void PoolQuery::setUninstalledOnly()
933   { _pimpl->_status_flags = UNINSTALLED_ONLY; }
934   void PoolQuery::setStatusFilterFlags( PoolQuery::StatusFilter flags )
935   { _pimpl->_status_flags = flags; }
936
937
938   void PoolQuery::setRequireAll(bool require_all)
939   { _pimpl->_require_all = require_all; }
940
941
942   const PoolQuery::StrContainer &
943   PoolQuery::strings() const
944   { return _pimpl->_strings; }
945
946   const PoolQuery::AttrRawStrMap &
947   PoolQuery::attributes() const
948   { return _pimpl->_attrs; }
949
950   const PoolQuery::StrContainer &
951   PoolQuery::attribute(const sat::SolvAttr & attr) const
952   {
953     static const PoolQuery::StrContainer nocontainer;
954     AttrRawStrMap::const_iterator it = _pimpl->_attrs.find(attr);
955     return it != _pimpl->_attrs.end() ? it->second : nocontainer;
956   }
957
958   const Edition PoolQuery::edition() const
959   { return _pimpl->_edition; }
960   const Rel PoolQuery::editionRel() const
961   { return _pimpl->_op; }
962
963
964   const PoolQuery::Kinds &
965   PoolQuery::kinds() const
966   { return _pimpl->_kinds; }
967
968   const PoolQuery::StrContainer &
969   PoolQuery::repos() const
970   { return _pimpl->_repos; }
971
972
973   bool PoolQuery::caseSensitive() const
974   { return !_pimpl->_flags.test( Match::NOCASE ); }
975   void PoolQuery::setCaseSensitive( bool value )
976   { _pimpl->_flags.turn( Match::NOCASE, !value ); }
977
978   bool PoolQuery::filesMatchFullPath() const
979   { return _pimpl->_flags.test( Match::FILES ); }
980   void PoolQuery::setFilesMatchFullPath( bool value )
981   { _pimpl->_flags.turn( Match::FILES, value ); }
982
983   bool PoolQuery::matchExact() const            { return _pimpl->_flags.isModeString(); }
984   bool PoolQuery::matchSubstring() const        { return _pimpl->_flags.isModeSubstring(); }
985   bool PoolQuery::matchGlob() const             { return _pimpl->_flags.isModeGlob(); }
986   bool PoolQuery::matchRegex() const            { return _pimpl->_flags.isModeRegex(); }
987
988   bool PoolQuery::matchWord() const
989   { return _pimpl->_match_word; }
990
991   bool PoolQuery::requireAll() const
992   { return _pimpl->_require_all; }
993
994   PoolQuery::StatusFilter PoolQuery::statusFilterFlags() const
995   { return _pimpl->_status_flags; }
996
997   bool PoolQuery::empty() const
998   {
999     try { return begin() == end(); }
1000     catch (const Exception & ex) {}
1001     return true;
1002   }
1003
1004   PoolQuery::size_type PoolQuery::size() const
1005   {
1006     try
1007     {
1008       size_type count = 0;
1009       for_( it, begin(), end() )
1010         ++count;
1011       return count;
1012     }
1013     catch (const Exception & ex) {}
1014     return 0;
1015   }
1016
1017   void PoolQuery::execute(ProcessResolvable fnc)
1018   { invokeOnEach( begin(), end(), fnc); }
1019
1020
1021   ///////////////////////////////////////////////////////////////////
1022   //
1023   //  CLASS NAME : PoolQuery::Attr
1024   //
1025   /**
1026    * represents all atributes in PoolQuery except SolvAtributes, which are
1027    * used as is (not needed extend anything if someone adds new solv attr)
1028    */
1029   struct PoolQueryAttr : public IdStringType<PoolQueryAttr>
1030   {
1031   private:
1032     friend class IdStringType<PoolQueryAttr>;
1033     IdString _str;
1034   public:
1035
1036     //noAttr
1037     PoolQueryAttr(){}
1038
1039     explicit PoolQueryAttr( const char* cstr_r )
1040         : _str( cstr_r )
1041       {}
1042
1043     explicit PoolQueryAttr( const std::string & str_r )
1044         : _str( str_r )
1045       {}
1046
1047     // unknown atributes
1048     static const PoolQueryAttr noAttr;
1049
1050     // PoolQuery's own attributes
1051     static const PoolQueryAttr repoAttr;
1052     static const PoolQueryAttr kindAttr;
1053     static const PoolQueryAttr stringAttr;
1054     static const PoolQueryAttr stringTypeAttr;
1055     static const PoolQueryAttr requireAllAttr;
1056     static const PoolQueryAttr caseSensitiveAttr;
1057     static const PoolQueryAttr installStatusAttr;
1058     static const PoolQueryAttr editionAttr;
1059     static const PoolQueryAttr complexAttr;
1060   };
1061
1062   const PoolQueryAttr PoolQueryAttr::noAttr;
1063
1064   const PoolQueryAttr PoolQueryAttr::repoAttr( "repo" );
1065   const PoolQueryAttr PoolQueryAttr::kindAttr( "type" );
1066   const PoolQueryAttr PoolQueryAttr::stringAttr( "query_string" );
1067   const PoolQueryAttr PoolQueryAttr::stringTypeAttr("match_type");
1068   const PoolQueryAttr PoolQueryAttr::requireAllAttr("require_all");
1069   const PoolQueryAttr PoolQueryAttr::caseSensitiveAttr("case_sensitive");
1070   const PoolQueryAttr PoolQueryAttr::installStatusAttr("install_status");
1071   const PoolQueryAttr PoolQueryAttr::editionAttr("version");
1072   const PoolQueryAttr PoolQueryAttr::complexAttr("complex");
1073
1074   class StringTypeAttr : public IdStringType<PoolQueryAttr>
1075   {
1076     friend class IdStringType<StringTypeAttr>;
1077     IdString _str;
1078
1079   public:
1080     StringTypeAttr(){}
1081     explicit StringTypeAttr( const char* cstr_r )
1082             : _str( cstr_r ){}
1083     explicit StringTypeAttr( const std::string & str_r )
1084              : _str( str_r ){}
1085
1086     static const StringTypeAttr noAttr;
1087
1088     static const StringTypeAttr exactAttr;
1089     static const StringTypeAttr substringAttr;
1090     static const StringTypeAttr regexAttr;
1091     static const StringTypeAttr globAttr;
1092     static const StringTypeAttr wordAttr;
1093   };
1094
1095   const StringTypeAttr StringTypeAttr::noAttr;
1096
1097   const StringTypeAttr StringTypeAttr::exactAttr("exact");
1098   const StringTypeAttr StringTypeAttr::substringAttr("substring");
1099   const StringTypeAttr StringTypeAttr::regexAttr("regex");
1100   const StringTypeAttr StringTypeAttr::globAttr("glob");
1101   const StringTypeAttr StringTypeAttr::wordAttr("word");
1102
1103   ///////////////////////////////////////////////////////////////////
1104
1105
1106   //\TODO maybe ctor with stream can be usefull
1107   //\TODO let it throw, let it throw, let it throw.
1108   bool PoolQuery::recover( istream &str, char delim )
1109   {
1110     bool finded_something = false; //indicates some atributes is finded
1111     string s;
1112     do {
1113       if ( str.eof() )
1114         break;
1115
1116       getline( str, s, delim );
1117
1118       if ((!s.empty()) && s[0]=='#') //comment
1119       {
1120         continue;
1121       }
1122
1123       string::size_type pos = s.find(':');
1124       if (s.empty() || pos == s.npos) // some garbage on line... act like blank line
1125       {
1126         if (finded_something) //is first blank line after record?
1127         {
1128           break;
1129         }
1130         else
1131         {
1132           continue;
1133         }
1134       }
1135
1136       finded_something = true;
1137
1138       string attrName(str::trim(string(s,0,pos))); // trimmed name of atribute
1139       string attrValue(str::trim(string(s,pos+1,s.npos))); //trimmed value
1140
1141       PoolQueryAttr attribute( attrName );
1142
1143       if ( attribute==PoolQueryAttr::repoAttr )
1144       {
1145         addRepo( attrValue );
1146       }
1147       /* some backwards compatibility */
1148       else if ( attribute==PoolQueryAttr::kindAttr || attribute=="kind" )
1149       {
1150         addKind( ResKind(attrValue) );
1151       }
1152       else if ( attribute==PoolQueryAttr::stringAttr
1153         || attribute=="global_string")
1154       {
1155         addString( attrValue );
1156       }
1157       else if ( attribute==PoolQueryAttr::stringTypeAttr
1158         || attribute=="string_type" )
1159       {
1160         StringTypeAttr s(attrValue);
1161         if( s == StringTypeAttr::regexAttr )
1162         {
1163           setMatchRegex();
1164         }
1165         else if ( s == StringTypeAttr::globAttr )
1166         {
1167           setMatchGlob();
1168         }
1169         else if ( s == StringTypeAttr::exactAttr )
1170         {
1171           setMatchExact();
1172         }
1173         else if ( s == StringTypeAttr::substringAttr )
1174         {
1175           setMatchSubstring();
1176         }
1177         else if ( s == StringTypeAttr::wordAttr )
1178         {
1179           setMatchWord();
1180         }
1181         else if ( s == StringTypeAttr::noAttr )
1182         {
1183           WAR << "unknown string type " << attrValue << endl;
1184         }
1185         else
1186         {
1187           WAR << "forget recover some attribute defined as String type attribute: " << attrValue << endl;
1188         }
1189       }
1190       else if ( attribute==PoolQueryAttr::requireAllAttr )
1191       {
1192         if ( str::strToTrue(attrValue) )
1193         {
1194           setRequireAll(true);
1195         }
1196         else if ( !str::strToFalse(attrValue) )
1197         {
1198           setRequireAll(false);
1199         }
1200         else
1201         {
1202           WAR << "unknown boolean value " << attrValue << endl;
1203         }
1204       }
1205       else if ( attribute==PoolQueryAttr::caseSensitiveAttr )
1206       {
1207         if ( str::strToTrue(attrValue) )
1208         {
1209           setCaseSensitive(true);
1210         }
1211         else if ( !str::strToFalse(attrValue) )
1212         {
1213           setCaseSensitive(false);
1214         }
1215         else
1216         {
1217           WAR << "unknown boolean value " << attrValue << endl;
1218         }
1219       }
1220       else if ( attribute==PoolQueryAttr::installStatusAttr )
1221       {
1222         if( attrValue == "all" )
1223         {
1224           setStatusFilterFlags( ALL );
1225         }
1226         else if( attrValue == "installed" )
1227         {
1228           setInstalledOnly();
1229         }
1230         else if( attrValue == "not-installed" )
1231         {
1232           setUninstalledOnly();
1233         }
1234         else
1235         {
1236           WAR << "Unknown value for install status " << attrValue << endl;
1237         }
1238       }
1239       else if ( attribute == PoolQueryAttr::editionAttr)
1240       {
1241         string::size_type pos;
1242         Rel rel("==");
1243         if (attrValue.find_first_of("=<>!") == 0)
1244         {
1245           pos = attrValue.find_last_of("=<>");
1246           rel = Rel(attrValue.substr(0, pos+1));
1247           attrValue = str::trim(attrValue.substr(pos+1, attrValue.npos));
1248         }
1249
1250         setEdition(Edition(attrValue), rel);
1251       }
1252       else if ( attribute == PoolQueryAttr::complexAttr )
1253       {
1254         try
1255         {
1256           _pimpl->_uncompiledPredicated.insert( AttrMatchData::deserialize( attrValue ) );
1257         }
1258         catch ( const Exception & err )
1259         {
1260           WAR << "Unparsable value for complex: " << err.asUserHistory() << endl;
1261
1262         }
1263       }
1264       else if ( attribute==PoolQueryAttr::noAttr )
1265       {
1266         WAR << "empty attribute name" << endl;
1267       }
1268       else
1269       {
1270         string s = attrName;
1271         str::replaceAll( s,"_",":" );
1272         SolvAttr a(s);
1273         if ( a == SolvAttr::name || isDependencyAttribute( a ) )
1274         {
1275           Capability c( attrValue );
1276           CapDetail d( c );
1277           if ( d.isVersioned() )
1278             addDependency( a, d.name().asString(), d.op(), d.ed() );
1279           else
1280             addDependency( a, attrValue );
1281         }
1282         else
1283           addAttribute( a, attrValue );
1284       }
1285
1286     } while ( true );
1287
1288     return finded_something;
1289   }
1290
1291   void PoolQuery::serialize( ostream &str, char delim ) const
1292   {
1293     //separating delim
1294     str << delim;
1295     //iterate thrue all settings and write it
1296     static const zypp::PoolQuery q; //not save default options, so create default query example
1297
1298     for_( it, repos().begin(), repos().end() )
1299     {
1300       str << "repo: " << *it << delim ;
1301     }
1302
1303     for_( it, kinds().begin(), kinds().end() )
1304     {
1305       str << PoolQueryAttr::kindAttr.asString() << ": "
1306           << it->idStr() << delim ;
1307     }
1308
1309     if (editionRel() != Rel::ANY && edition() != Edition::noedition)
1310       str << PoolQueryAttr::editionAttr.asString() << ": " << editionRel() << " " << edition() << delim;
1311
1312     if (matchMode()!=q.matchMode())
1313     {
1314       switch( matchMode() )
1315       {
1316       case Match::STRING:
1317         str << PoolQueryAttr::stringTypeAttr.asString() << ": exact" << delim;
1318         break;
1319       case Match::SUBSTRING:
1320         str << PoolQueryAttr::stringTypeAttr.asString()
1321             << ": substring" << delim;
1322         break;
1323       case Match::GLOB:
1324         str << PoolQueryAttr::stringTypeAttr.asString() << ": glob" << delim;
1325         break;
1326       case Match::REGEX:
1327         str << PoolQueryAttr::stringTypeAttr.asString() << ": regex" << delim;
1328         break;
1329       default:
1330         WAR << "unknown match type "  << matchMode() << endl;
1331       }
1332     }
1333
1334     if( caseSensitive() != q.caseSensitive() )
1335     {
1336       str << "case_sensitive: ";
1337       if (caseSensitive())
1338       {
1339         str << "on" << delim;
1340       }
1341       else
1342       {
1343         str << "off" << delim;
1344       }
1345     }
1346
1347     if( requireAll() != q.requireAll() )
1348     {
1349       str << "require_all: ";
1350       if (requireAll())
1351       {
1352         str << "on" << delim;
1353       }
1354       else
1355       {
1356         str << "off" << delim;
1357       }
1358     }
1359
1360     if( statusFilterFlags() != q.statusFilterFlags() )
1361     {
1362       switch( statusFilterFlags() )
1363       {
1364       case ALL:
1365         str << "install_status: all" << delim;
1366         break;
1367       case INSTALLED_ONLY:
1368         str << "install_status: installed" << delim;
1369         break;
1370       case UNINSTALLED_ONLY:
1371         str << "install_status: not-installed" << delim;
1372         break;
1373       }
1374     }
1375
1376     for_( it, strings().begin(), strings().end() )
1377     {
1378       str << PoolQueryAttr::stringAttr.asString()<< ": " << *it << delim;
1379     }
1380
1381     for_( it, attributes().begin(), attributes().end() )
1382     {
1383       string s = it->first.asString();
1384       str::replaceAll(s,":","_");
1385       for_( it2,it->second.begin(),it->second.end() )
1386       {
1387         str << s <<": "<< *it2 << delim;
1388       }
1389     }
1390
1391     for_( it, _pimpl->_uncompiledPredicated.begin(), _pimpl->_uncompiledPredicated.end() )
1392     {
1393       str << "complex: "<< it->serialize() << delim;
1394     }
1395
1396     //separating delim - protection
1397     str << delim;
1398   }
1399
1400   string PoolQuery::asString() const
1401   { return _pimpl->asString(); }
1402
1403   ostream & operator<<( ostream & str, const PoolQuery & obj )
1404   { return str << obj.asString(); }
1405
1406   std::ostream & dumpOn( std::ostream & str, const PoolQuery & obj )
1407   { return dumpRange( str << obj, obj.begin(), obj.end() ); }
1408
1409   bool PoolQuery::operator==( const PoolQuery & rhs ) const
1410   { return *_pimpl == *rhs._pimpl; }
1411
1412   ///////////////////////////////////////////////////////////////////
1413   namespace detail
1414   { /////////////////////////////////////////////////////////////////
1415
1416     ///////////////////////////////////////////////////////////////////
1417     //
1418     //  CLASS NAME : PoolQueryMatcher
1419     //
1420     /** Store \ref PoolQuery settings and assist \ref PoolQueryIterator.
1421      *
1422      * Basically the matcher performs a base query, which should preselect
1423      * candidates for a match. And has some filter conditions on top of it.
1424      * Query and fileter depend on the \ref PoolQuery settings.
1425      *
1426      * Matcher must be stateless, as it is shared between multiple
1427      * \ref PoolQueryIterator instances.
1428      *
1429      * If \ref base_iterator is at the \ref end, \ref advance moves it
1430      * to the first match. Otherwise advance moves to the next match, or
1431      * to the \ref end, if there is no more match.
1432      *
1433      * \note The original implementation treated an empty search string as
1434      * <it>"match always"</it>. We stay compatible.
1435      */
1436     class PoolQueryMatcher
1437     {
1438       public:
1439         typedef sat::LookupAttr::iterator base_iterator;
1440
1441       public:
1442         const base_iterator & end() const
1443         {
1444           static base_iterator _end;
1445           return _end;
1446         }
1447
1448         bool advance( base_iterator & base_r ) const
1449         {
1450           if ( base_r == end() )
1451             base_r = startNewQyery(); // first candidate
1452           else
1453           {
1454             base_r.nextSkipSolvable(); // assert we don't visit this Solvable again
1455             ++base_r; // advance to next candidate
1456           }
1457
1458           while ( base_r != end() )
1459           {
1460             if ( isAMatch( base_r ) )
1461               return true;
1462             // No match: try next
1463             ++base_r;
1464           }
1465           return false;
1466         }
1467
1468         /** Provide all matching attributes within this solvable.
1469          *
1470          */
1471         void matchDetail( const base_iterator & base_r, std::vector<base_iterator> & return_r ) const
1472         {
1473           if ( base_r == end() )
1474             return;
1475
1476           sat::Solvable inSolvable( base_r.inSolvable() );
1477
1478           if ( _attrMatchList.size() == 1 )
1479           {
1480             // base_r is already on the 1st matching attribute!
1481             // String matching is done by the base iterator. We must check the predicate here.
1482             // Let's see if there are more matches for this solvable:
1483             base_iterator base( base_r );
1484             base.stayInThisSolvable(); // avoid discarding matches we found far away from here.
1485             return_r.push_back( base );
1486
1487             const AttrMatchData::Predicate & predicate( _attrMatchList.front().predicate );
1488             for ( ++base; base.inSolvable() == inSolvable; ++base ) // safe even if base == end()
1489             {
1490               if ( ! predicate || predicate( base ) )
1491                 return_r.push_back( base );
1492             }
1493           }
1494           else
1495           {
1496             // Here: search all attributes ;(
1497             for_( mi, _attrMatchList.begin(), _attrMatchList.end() )
1498             {
1499               const AttrMatchData & matchData( *mi );
1500               sat::LookupAttr q( matchData.attr, inSolvable );
1501               if ( matchData.strMatcher ) // an empty searchstring matches always
1502                 q.setStrMatcher( matchData.strMatcher );
1503
1504               if ( ! q.empty() ) // there are matches.
1505               {
1506                 // now check any predicate:
1507                 const AttrMatchData::Predicate & predicate( matchData.predicate );
1508                 for_( it, q.begin(), q.end() )
1509                 {
1510                   if ( ! predicate || predicate( it ) )
1511                     return_r.push_back( it );
1512                 }
1513               }
1514             }
1515           }
1516         }
1517
1518       public:
1519         /** Ctor stores the \ref PoolQuery settings.
1520          * \throw MatchException Any of the exceptions thrown by \ref PoolQuery::Impl::compile.
1521          */
1522         PoolQueryMatcher( const shared_ptr<const PoolQuery::Impl> & query_r )
1523         {
1524           query_r->compile();
1525
1526           // Repo restriction:
1527           sat::Pool satpool( sat::Pool::instance() );
1528
1529           for_( it, query_r->_repos.begin(), query_r->_repos.end() )
1530           {
1531             Repository r( satpool.reposFind( *it ) );
1532             if ( r )
1533               _repos.insert( r );
1534             else
1535               _neverMatchRepo = true;
1536           }
1537           // _neverMatchRepo: we just need to catch the case that no repo
1538           // matched, so we'd interpret the empty list as 'take from all'
1539           if ( _neverMatchRepo && ! _repos.empty() )
1540             _neverMatchRepo = false;
1541
1542           // Kind restriction:
1543           _kinds = query_r->_kinds;
1544           // Edition restriction:
1545           _op      = query_r->_op;
1546           _edition = query_r->_edition;
1547           // Status restriction:
1548           _status_flags = query_r->_status_flags;
1549           // StrMatcher
1550           _attrMatchList = query_r->_attrMatchList;
1551         }
1552
1553         ~PoolQueryMatcher()
1554         {}
1555
1556       private:
1557         /** Initialize a new base query. */
1558         base_iterator startNewQyery() const
1559         {
1560           sat::LookupAttr q;
1561
1562           if ( _neverMatchRepo )
1563             return q.end();
1564
1565           // Repo restriction:
1566           if ( _repos.size() == 1 )
1567             q.setRepo( *_repos.begin() );
1568           // else: handled in isAMatch.
1569
1570           // Attribute restriction:
1571           if ( _attrMatchList.size() == 1 ) // all (SolvAttr::allAttr) or 1 attr
1572           {
1573             const AttrMatchData & matchData( _attrMatchList.front() );
1574             q.setAttr( matchData.attr );
1575             if ( matchData.strMatcher ) // empty searchstring matches always
1576               q.setStrMatcher( matchData.strMatcher );
1577           }
1578           else // more than 1 attr (but not all)
1579           {
1580             // no restriction, it's all handled in isAMatch.
1581             q.setAttr( sat::SolvAttr::allAttr );
1582           }
1583
1584           return q.begin();
1585         }
1586
1587
1588         /** Check whether we are on a match.
1589          *
1590          * The check covers the whole Solvable, not just the current
1591          * attribute \c base_r points to. If there's no match, also
1592          * prepare \c base_r to advance appropriately. If there is
1593          * a match, simply return \c true. \ref advance always moves
1594          * to the next Solvable if there was a match.
1595          *
1596          * \note: Caller asserts we're not at \ref end.
1597         */
1598         bool isAMatch( base_iterator & base_r ) const
1599         {
1600           /////////////////////////////////////////////////////////////////////
1601           Repository inRepo( base_r.inRepo() );
1602           // Status restriction:
1603           if ( _status_flags
1604              && ( (_status_flags == PoolQuery::INSTALLED_ONLY) != inRepo.isSystemRepo() ) )
1605           {
1606             base_r.nextSkipRepo();
1607             return false;
1608           }
1609           // Repo restriction:
1610           if ( _repos.size() > 1 && _repos.find( inRepo ) == _repos.end() )
1611           {
1612             base_r.nextSkipRepo();
1613             return false;
1614           }
1615           /////////////////////////////////////////////////////////////////////
1616           sat::Solvable inSolvable( base_r.inSolvable() );
1617           // Kind restriction:
1618           if ( ! _kinds.empty() && ! inSolvable.isKind( _kinds.begin(), _kinds.end() ) )
1619           {
1620             base_r.nextSkipSolvable();
1621             return false;
1622           }
1623
1624           // Edition restriction:
1625           if ( _op != Rel::ANY && !compareByRel( _op, inSolvable.edition(), _edition, Edition::Match() ) )
1626           {
1627             base_r.nextSkipSolvable();
1628             return false;
1629           }
1630           /////////////////////////////////////////////////////////////////////
1631           // string and predicate matching:
1632
1633           if ( _attrMatchList.size() == 1 )
1634           {
1635             // String matching was done by the base iterator.
1636             // Now check any predicate:
1637             const AttrMatchData::Predicate & predicate( _attrMatchList.front().predicate );
1638             if ( ! predicate || predicate( base_r ) )
1639               return true;
1640
1641             return false; // no skip as there may be more occurrences od this attr.
1642           }
1643
1644           // Here: search all attributes ;(
1645           for_( mi, _attrMatchList.begin(), _attrMatchList.end() )
1646           {
1647             const AttrMatchData & matchData( *mi );
1648             sat::LookupAttr q( matchData.attr, inSolvable );
1649             if ( matchData.strMatcher ) // an empty searchstring matches always
1650               q.setStrMatcher( matchData.strMatcher );
1651
1652             if ( ! q.empty() ) // there are matches.
1653             {
1654               // now check any predicate:
1655               const AttrMatchData::Predicate & predicate( matchData.predicate );
1656               if ( predicate )
1657               {
1658                 for_( it, q.begin(), q.end() )
1659                 {
1660                   if ( predicate( it ) )
1661                     return true;
1662                 }
1663               }
1664               else
1665                 return true;
1666             }
1667           }
1668           base_r.nextSkipSolvable();
1669           return false;
1670         }
1671
1672       private:
1673         /** Repositories include in the search. */
1674         std::set<Repository> _repos;
1675         DefaultIntegral<bool,false> _neverMatchRepo;
1676         /** Resolvable kinds to include. */
1677         std::set<ResKind> _kinds;
1678         /** Edition filter. */
1679         Rel _op;
1680         Edition _edition;
1681         /** Installed status filter flags. \see PoolQuery::StatusFilter */
1682         int _status_flags;
1683         /** StrMatcher per attribtue. */
1684         AttrMatchList _attrMatchList;
1685     };
1686     ///////////////////////////////////////////////////////////////////
1687
1688     void PoolQueryIterator::increment()
1689     {
1690       // matcher restarts if at end! It is called from the ctor
1691       // to get the 1st match. But if the end is reached, it should
1692       // be deleted, otherwise we'd start over again.
1693       if ( !_matcher )
1694         return; // at end
1695       if ( _matches )
1696         _matches.reset(); // invalidate old matches
1697       if ( ! _matcher->advance( base_reference() ) )
1698         _matcher.reset();
1699     }
1700
1701     const PoolQueryIterator::Matches & PoolQueryIterator::matches() const
1702     {
1703       if ( _matches )
1704         return *_matches;
1705
1706       if ( !_matcher )
1707       {
1708         // at end of query:
1709         static const Matches _none;
1710         return _none;
1711       }
1712
1713       _matches.reset( new Matches );
1714       _matcher->matchDetail( base_reference(), *_matches );
1715       return *_matches;
1716     }
1717
1718     std::ostream & dumpOn( std::ostream & str, const PoolQueryIterator & obj )
1719     {
1720       str << *obj;
1721       if ( ! obj.matchesEmpty() )
1722       {
1723         for_( it, obj.matchesBegin(), obj.matchesEnd() )
1724         {
1725           str << endl << "    " << it->inSolvAttr() << "\t" << it->asString();
1726         }
1727       }
1728       return str;
1729     }
1730
1731     ///////////////////////////////////////////////////////////////////
1732   } //namespace detail
1733   ///////////////////////////////////////////////////////////////////
1734
1735   detail::PoolQueryIterator PoolQuery::begin() const
1736   {
1737     return shared_ptr<detail::PoolQueryMatcher>( new detail::PoolQueryMatcher( _pimpl.getPtr() ) );
1738   }
1739
1740   /////////////////////////////////////////////////////////////////
1741 } // namespace zypp
1742 ///////////////////////////////////////////////////////////////////
1743