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