1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/PoolQuery.cc
15 #include "zypp/base/Gettext.h"
16 #include "zypp/base/Logger.h"
17 #include "zypp/base/Algorithm.h"
18 #include "zypp/base/String.h"
19 #include "zypp/repo/RepoException.h"
21 #include "zypp/sat/Pool.h"
22 #include "zypp/sat/Solvable.h"
24 #include "zypp/PoolQuery.h"
28 #include "satsolver/repo.h"
32 using namespace zypp::sat;
34 ///////////////////////////////////////////////////////////////////
36 { /////////////////////////////////////////////////////////////////
38 ///////////////////////////////////////////////////////////////////
40 // CLASS NAME : PoolQuery::Impl
46 : _flags( SEARCH_ALL_REPOS | SEARCH_NOCASE | SEARCH_SUBSTRING | SEARCH_SKIP_KIND )
57 const_iterator begin() const;
58 const_iterator end() const;
60 string asString() const;
64 string createRegex(const StrContainer & container) const;
67 /** Raw search strings. */
68 StrContainer _strings;
69 /** Compiled search strings. */
70 mutable string _rcstrings;
71 /** Compiled regex struct */
72 mutable str::regex _regex;
75 /** Regex-compiled attributes */
76 mutable AttrCompiledStrMap _rcattrs;
77 mutable AttrRegexMap _rattrs;
79 /** Repos to search. */
81 /** Kinds to search */
84 /** Sat solver search flags */
86 /** Backup of search flags. compile() may change the flags if needed, so
87 * in order to reuse the query, the original flags need to be stored
88 * at the start of compile() */
90 /** Sat solver status flags */
91 StatusFilter _status_flags;
97 mutable bool _compiled;
100 friend Impl * rwcowClone<Impl>( const Impl * rhs );
101 /** clone for RWCOW_pointer */
103 { return new Impl( *this ); }
109 MyInserter(PoolQuery::StrContainer & cont) : _cont(cont) {}
111 bool operator()(const string & str)
117 PoolQuery::StrContainer & _cont;
123 bool operator()(const string & str)
130 void PoolQuery::Impl::compile() const
134 // 'different' - will have to iterate through all and match by ourselves (slow)
135 // 'same' - will pass the compiled string to dataiterator_init
136 // 'one-attr' - will pass it to dataiterator_init
137 // 'one-non-regex-str' - will pass to dataiterator_init, set flag to SEARCH_STRING or SEARCH_SUBSTRING
142 // create regex; store in _rcstrings; if more strings flag regex;
145 _rcstrings = createRegex(_strings);
146 if (_strings.size() > 1)
147 _cflags = (_cflags & ~SEARCH_STRINGMASK) | SEARCH_REGEX;//setMatchRegex();
151 // else if _attrs is not empty but it contains just one attr
152 // for all _strings and _attr[key] strings
153 // create regex; store in _rcattrs; flag 'one-attr'; if more strings flag regex;
154 else if (_attrs.size() == 1)
157 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
158 invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
159 _rcstrings = createRegex(joined);
160 _rcattrs.insert(pair<sat::SolvAttr, string>(_attrs.begin()->first, string()));
163 // // MULTIPLE ATTRIBUTES
166 // check whether there are any per-attribute strings
167 bool attrvals_empty = true;
168 for (AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
169 if (!ai->second.empty())
170 for(StrContainer::const_iterator it = ai->second.begin();
171 it != ai->second.end(); it++)
174 attrvals_empty = false;
175 goto attremptycheckend;
179 // chceck whether the per-attribute strings are all the same
180 bool attrvals_thesame = true;
181 AttrRawStrMap::const_iterator ai = _attrs.begin();
182 const StrContainer & set1 = ai->second;
184 for (; ai != _attrs.end(); ++ai)
188 set1.begin(), set1.end(),
189 ai->second.begin(), ai->second.end(),
190 inserter(result, result.begin())/*, ltstr()*/);
193 attrvals_thesame = false;
198 // // THE SAME STRINGS FOR DIFFERENT ATTRS
199 // else if _attrs is not empty but it does not contain strings
200 // for each key in _attrs take all _strings
201 // create regex; store in _rcattrs and _rcstrings; flag 'same'; if more strings flag regex;
202 if (attrvals_empty || attrvals_thesame)
207 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
208 _rcstrings = createRegex(joined);
212 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
213 invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined));
214 _rcstrings = createRegex(joined);
216 // copy the _attrs keys to _rcattrs
217 for_(ai, _attrs.begin(), _attrs.end())
218 _rcattrs.insert(pair<sat::SolvAttr, string>(ai->first, string()));
220 if ((_cflags & SEARCH_STRINGMASK) == SEARCH_REGEX)
221 /* We feed multiple lines eventually (e.g. authors or descriptions), so set REG_NEWLINE. */
222 _regex = str::regex(_rcstrings, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | (_cflags & SEARCH_NOCASE ? REG_ICASE : 0));
225 // // DIFFERENT STRINGS FOR DIFFERENT ATTRS
226 // if _attrs is not empty and it contains non-empty vectors with non-empty strings
227 // for each key in _attrs take all _strings + all _attrs[key] strings
228 // create regex; store in _rcattrs; flag 'different'; if more strings flag regex;
231 for_(ai, _attrs.begin(), _attrs.end())
234 invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
235 invokeOnEach(ai->second.begin(), ai->second.end(), EmptyFilter(), MyInserter(joined));
236 string s = createRegex(joined);
237 _rcattrs.insert(pair<sat::SolvAttr, string>(ai->first, s));
239 if ((_cflags & SEARCH_STRINGMASK) == SEARCH_REGEX)
241 str::regex regex(s, REG_EXTENDED | REG_NOSUB | REG_NEWLINE | (_cflags & SEARCH_NOCASE ? REG_ICASE : 0));
242 _rattrs.insert(pair<sat::SolvAttr, str::regex>(ai->first, regex));
248 // tell the Dataiterator to search only in one repo if only one specified
249 if (_repos.size() == 1)
250 _cflags &= ~SEARCH_ALL_REPOS;
254 DBG << asString() << endl;
258 * Converts '*' and '?' wildcards within str into their regex equivalents.
260 static string wildcards2regex(const string & str)
262 string regexed = str;
264 str::regex all("\\*"); // regex to search for '*'
265 str::regex one("\\?"); // regex to search for '?'
266 string r_all(".*"); // regex equivalent of '*'
267 string r_one("."); // regex equivalent of '?'
268 string::size_type pos;
270 // replace all "*" in input with ".*"
271 for (pos = 0; (pos = regexed.find("*", pos)) != std::string::npos; pos+=2)
272 regexed = regexed.replace(pos, 1, r_all);
274 // replace all "?" in input with "."
275 for (pos = 0; (pos = regexed.find('?', pos)) != std::string::npos; ++pos)
276 regexed = regexed.replace(pos, 1, r_one);
278 DBG << " -> " << regexed << endl;
283 //! macro for word boundary tags for regexes
284 #define WB (_match_word ? string("\\b") : string())
286 string PoolQuery::Impl::createRegex(const StrContainer & container) const
290 if (container.empty())
293 if (container.size() == 1)
296 return ".*" + WB + *container.begin() + WB + ".*";
298 return *container.begin();
303 bool use_wildcards = (_cflags & SEARCH_STRINGMASK) == SEARCH_GLOB;
304 StrContainer::const_iterator it = container.begin();
308 tmp = wildcards2regex(*it);
312 if (!(_cflags & SEARCH_STRING)) // not match exact
313 tmp += ".*" + WB + tmp;
314 rstr = "(?=" + tmp + ")";
318 if (_cflags & SEARCH_STRING) // match exact
328 for (; it != container.end(); ++it)
331 tmp = wildcards2regex(*it);
335 if (!(_cflags & SEARCH_STRING)) // not match exact
336 tmp += ".*" + WB + tmp;
337 rstr += "(?=" + tmp + ")";
347 if (!(_cflags & SEARCH_STRING)) // not match exact
353 if (_cflags & SEARCH_STRING) // match exact
363 PoolQuery::const_iterator PoolQuery::Impl::begin() const
367 sat::Pool pool(sat::Pool::instance());
368 // no pool or no repos
369 if (!pool.get() || pool.reposEmpty())
372 // if only one repository has been specified, find it in the pool
374 if (!(_cflags & SEARCH_ALL_REPOS) && _repos.size() == 1)
376 string theone = *_repos.begin();
377 repo = pool.reposFind(theone);
378 if (repo == Repository::noRepository)
380 RepoInfo info; info.setAlias(theone);
381 ERR << "Repository not found in sat pool." << endl;
382 ZYPP_THROW(repo::RepoNotFoundException(info));
386 if ((_cflags & SEARCH_ALL_REPOS) || repo == Repository::noRepository)
387 repo = *pool.reposBegin();
389 DBG << "_cflags:" << _cflags << endl;
391 scoped_ptr< ::_Dataiterator> _rdit( new ::Dataiterator );
392 // needed while LookupAttr::iterator::dip_equal does ::memcmp:
393 ::memset( _rdit.get(), 0, sizeof(::_Dataiterator) );
395 // initialize the Dataiterator for different cases
396 if (_rcattrs.empty())
398 ::dataiterator_init(_rdit.get(),
399 repo.get(), // either the first repo or the repo to search
400 0, // search all solvables
401 0, // attribute id - only if 1 attr key specified
402 _rcstrings.empty() ? 0 : _rcstrings.c_str(), // compiled search string
405 else if (_rcattrs.size() == 1)
407 ::dataiterator_init(_rdit.get(),
408 repo.get(), // either the first repo or the repo to search
409 0, // search all solvables
410 _rcattrs.begin()->first.id(), // keyname - attribute id - only if 1 attr key specified
411 _rcstrings.empty() ? 0 : _rcstrings.c_str(), // compiled search string
416 ::dataiterator_init(_rdit.get(),
417 repo.get(), // either the first repo or the repo to search
418 0, /*search all resolvables */
419 0, /*keyname - if only 1 attr key specified, pass it here, otherwise do more magic */
420 0, //qs.empty() ? 0 : qs.c_str(), /* create regex, pass it here */
424 if ((_cflags & SEARCH_STRINGMASK) == SEARCH_REGEX && _rdit->regex_err != 0)
425 ZYPP_THROW(Exception(str::form(
426 _("Invalid regular expression '%s': regcomp returned %d"),
427 _rcstrings.c_str(), _rdit->regex_err)));
429 PoolQuery::const_iterator it(_rdit, this);
435 PoolQuery::const_iterator PoolQuery::Impl::end() const
437 return PoolQuery::const_iterator();
441 string PoolQuery::Impl::asString() const
445 o << "compiled: " << _compiled << endl;
448 for(Kinds::const_iterator it = _kinds.begin();
449 it != _kinds.end(); ++it)
454 for(StrContainer::const_iterator it = _repos.begin();
455 it != _repos.end(); ++it)
459 o << "string match flags:" << endl;
460 o << "* string/substring/glob/regex: " << (_cflags & SEARCH_STRINGMASK) << endl;
461 o << "* SEARCH_NOCASE: " << ((_cflags & SEARCH_NOCASE) ? "yes" : "no") << endl;
462 o << "* SEARCH_ALL_REPOS: " << ((_cflags & SEARCH_ALL_REPOS) ? "yes" : "no") << endl;
463 o << "status filter flags:" << _status_flags << endl;
468 for(StrContainer::const_iterator it = _strings.begin();
469 it != _strings.end(); ++it)
473 o << "attributes: " << endl;
474 for(AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
476 o << "* " << ai->first << ": ";
477 for(StrContainer::const_iterator vi = ai->second.begin();
478 vi != ai->second.end(); ++vi)
485 o << "compiled strings: " << _rcstrings << endl;
486 o << "compiled attributes:" << endl;
487 for (AttrCompiledStrMap::const_iterator ai = _rcattrs.begin(); ai != _rcattrs.end(); ++ai)
488 o << "* " << ai->first << ": " << ai->second << endl;
493 /** \relates PoolQuery::Impl Stream output *//*
494 inline std::ostream & operator<<( std::ostream & str, const PoolQuery::Impl & obj )
496 return str << "PoolQuery::Impl";
499 ///////////////////////////////////////////////////////////////////
501 ///////////////////////////////////////////////////////////////////
503 { /////////////////////////////////////////////////////////////////
505 ///////////////////////////////////////////////////////////////////
507 // CLASS NAME : PoolQuery::ResultIterator
509 ///////////////////////////////////////////////////////////////////
511 PoolQueryIterator::PoolQueryIterator()
512 : _sid(0), _has_next(false), _do_matching(false)
513 { this->base_reference() = LookupAttr::iterator(); }
516 PoolQueryIterator::PoolQueryIterator(
517 scoped_ptr< ::_Dataiterator> & dip_r,
518 const PoolQuery::Impl * pqimpl)
521 , _do_matching(pqimpl->_rcattrs.size() > 1)
522 , _flags(pqimpl->_cflags)
523 , _str(pqimpl->_rcstrings)
524 , _regex(pqimpl->_regex)
525 , _attrs_str(pqimpl->_rcattrs)
526 , _attrs_regex(pqimpl->_rattrs)
527 , _repos(pqimpl->_repos)
528 , _kinds(pqimpl->_kinds)
529 , _status_flags(pqimpl->_status_flags)
531 this->base_reference() = LookupAttr::iterator(dip_r, true); //!\todo pass chain_repos
532 _has_next = (*base_reference() != sat::detail::noId);
536 PoolQueryIterator::PoolQueryIterator(const PoolQueryIterator & rhs)
538 , _has_next(rhs._has_next)
539 , _do_matching(rhs._do_matching)
543 , _attrs_str(rhs._attrs_str)
544 , _attrs_regex(rhs._attrs_regex)
547 , _status_flags(rhs._status_flags)
548 { base_reference() = LookupAttr::iterator(rhs.base()); }
551 PoolQueryIterator::~PoolQueryIterator()
555 PoolQueryIterator & PoolQueryIterator::operator=( const PoolQueryIterator & rhs )
557 base_reference() = rhs.base();
559 _has_next = rhs._has_next;
560 _do_matching = rhs._do_matching;
564 _attrs_str = rhs._attrs_str;
565 _attrs_regex = rhs._attrs_regex;
568 _status_flags = rhs._status_flags;
573 void PoolQueryIterator::increment()
578 bool got_match = false;
580 while (_has_next && !(got_match = matchSolvable()));
582 // no more solvables and the last did not match
583 if (!got_match && !_has_next)
585 base_reference() = LookupAttr::iterator();
590 bool PoolQueryIterator::matchSolvable()
592 _sid = base().get()->solvid;
594 bool new_solvable = true;
595 bool matches = !_do_matching;
596 bool drop_by_kind_status = false;
597 bool drop_by_repo = false;
604 drop_by_repo = false;
605 if(!_repos.empty() &&
606 _repos.find(base().get()->repo->name) == _repos.end())
612 drop_by_kind_status = false;
614 // whether to drop an uninstalled (repo) solvable
615 if ( (_status_flags & PoolQuery::INSTALLED_ONLY) &&
616 base().get()->repo->name != sat::Pool::instance().systemRepoName() )
618 drop_by_kind_status = true;
622 // whether to drop an installed (target) solvable
623 if ((_status_flags & PoolQuery::UNINSTALLED_ONLY) &&
624 base().get()->repo->name == sat::Pool::instance().systemRepoName())
626 drop_by_kind_status = true;
630 // whether to drop unwanted kind
633 sat::Solvable s(_sid);
634 // the user wants to filter by kind.
635 if (_kinds.find(s.kind()) == _kinds.end())
636 drop_by_kind_status = true;
642 matches = matches && !drop_by_kind_status && !drop_by_repo;
645 if (_do_matching && !drop_by_kind_status)
649 SolvAttr attr(base().get()->key->name);
650 PoolQuery::AttrCompiledStrMap::const_iterator ai = _attrs_str.find(attr);
651 if (ai != _attrs_str.end())
653 if ((_flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
655 const regex_t * regex_p;
658 PoolQuery::AttrRegexMap::iterator rai = _attrs_regex.find(attr);
659 if (rai != _attrs_regex.end())
660 regex_p = rai->second.get();
663 ERR << "no compiled regex found for " << attr << endl;
668 regex_p = _regex.get();
669 matches = ::dataiterator_match(base().get(), _flags, regex_p);
673 const string & sstr =
674 _str.empty() ? ai->second : _str;
675 matches = ::dataiterator_match(base().get(), _flags, sstr.c_str());
679 /* After calling dataiterator_match (with any string matcher set)
680 the kv.str member will be filled with something sensible. */
681 /* INT << "value: " << base().get()->kv.str << endl
682 << " mstr: " << sstr << endl; */
689 base_reference().nextSkipRepo();
690 drop_by_repo = false;
692 else if (drop_by_kind_status)
694 base_reference().nextSkipSolvable();
695 drop_by_kind_status = false;
698 // copy the iterator to forward check for the next attribute ***
699 _tmpit = base_reference();
700 _has_next = (*(++_tmpit) != sat::detail::noId);
704 // *** now increment. Had it not be done this way,
705 // the LookupAttr::iterator could have reached the end() while
706 // trying to reach a matching attribute or the next solvable
707 // thus resulting to a problem in the equal() method
709 new_solvable = base().get()->solvid != _sid;
711 // no more attributes in this repo, return
713 return matches; // did the last solvable match conditions?
715 while (!new_solvable);
720 ///////////////////////////////////////////////////////////////////
722 ///////////////////////////////////////////////////////////////////
724 ///////////////////////////////////////////////////////////////////
726 // CLASS NAME : PoolQuery
728 ///////////////////////////////////////////////////////////////////
730 PoolQuery::PoolQuery()
735 PoolQuery::~PoolQuery()
739 void PoolQuery::addRepo(const std::string &repoalias)
741 _pimpl->_repos.insert(repoalias);
742 _pimpl->_flags &= ~SEARCH_ALL_REPOS;
746 void PoolQuery::addKind(const ResKind & kind)
747 { _pimpl->_kinds.insert(kind); }
750 void PoolQuery::addString(const string & value)
751 { _pimpl->_strings.insert(value); }
754 void PoolQuery::addAttribute(const sat::SolvAttr & attr, const std::string & value)
755 { _pimpl->_attrs[attr].insert(value); }
758 void PoolQuery::setCaseSensitive(const bool value)
761 _pimpl->_flags &= ~SEARCH_NOCASE;
763 _pimpl->_flags |= SEARCH_NOCASE;
767 void PoolQuery::setMatchSubstring()
768 { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_SUBSTRING; }
769 void PoolQuery::setMatchExact()
770 { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_STRING; }
771 void PoolQuery::setMatchRegex()
772 { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_REGEX; }
773 void PoolQuery::setMatchGlob()
774 { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_GLOB; }
775 void PoolQuery::setMatchWord()
777 _pimpl->_match_word = true;
778 _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_REGEX;
781 void PoolQuery::setFlags(int flags)
782 { _pimpl->_flags = flags; }
785 void PoolQuery::setInstalledOnly()
786 { _pimpl->_status_flags = INSTALLED_ONLY; }
787 void PoolQuery::setUninstalledOnly()
788 { _pimpl->_status_flags = UNINSTALLED_ONLY; }
789 void PoolQuery::setStatusFilterFlags( PoolQuery::StatusFilter flags )
790 { _pimpl->_status_flags = flags; }
793 void PoolQuery::setRequireAll(const bool require_all)
794 { _pimpl->_require_all = require_all; }
797 const PoolQuery::StrContainer &
798 PoolQuery::strings() const
799 { return _pimpl->_strings; }
801 const PoolQuery::AttrRawStrMap &
802 PoolQuery::attributes() const
803 { return _pimpl->_attrs; }
805 const PoolQuery::StrContainer &
806 PoolQuery::attribute(const sat::SolvAttr & attr) const
808 static const PoolQuery::StrContainer nocontainer;
809 AttrRawStrMap::const_iterator it = _pimpl->_attrs.find(attr);
810 return it != _pimpl->_attrs.end() ? it->second : nocontainer;
813 const PoolQuery::Kinds &
814 PoolQuery::kinds() const
815 { return _pimpl->_kinds; }
817 const PoolQuery::StrContainer &
818 PoolQuery::repos() const
819 { return _pimpl->_repos; }
821 bool PoolQuery::caseSensitive() const
822 { return !(_pimpl->_flags & SEARCH_NOCASE); }
824 bool PoolQuery::matchExact() const
825 { return (_pimpl->_flags & SEARCH_STRINGMASK) == SEARCH_STRING; }
826 bool PoolQuery::matchSubstring() const
827 { return (_pimpl->_flags & SEARCH_STRINGMASK) == SEARCH_SUBSTRING; }
828 bool PoolQuery::matchGlob() const
829 { return (_pimpl->_flags & SEARCH_STRINGMASK) == SEARCH_GLOB; }
830 bool PoolQuery::matchRegex() const
831 { return (_pimpl->_flags & SEARCH_STRINGMASK) == SEARCH_REGEX; }
832 int PoolQuery::matchType() const
833 { return _pimpl->_flags & SEARCH_STRINGMASK; }
835 bool PoolQuery::matchWord() const
836 { return _pimpl->_match_word; }
838 bool PoolQuery::requireAll() const
839 { return _pimpl->_require_all; }
841 PoolQuery::StatusFilter PoolQuery::statusFilterFlags() const
842 { return _pimpl->_status_flags; }
844 PoolQuery::const_iterator PoolQuery::begin() const
845 { return _pimpl->begin(); }
848 PoolQuery::const_iterator PoolQuery::end() const
849 { return _pimpl->end(); }
852 bool PoolQuery::empty() const
853 { return _pimpl->begin() == _pimpl->end(); }
855 //! \todo collect the result, reuse if not dirty
856 PoolQuery::size_type PoolQuery::size() const
859 for(const_iterator it = _pimpl->begin(); it != _pimpl->end(); ++it, ++count);
864 void PoolQuery::execute(ProcessResolvable fnc)
865 { invokeOnEach(_pimpl->begin(), _pimpl->end(), fnc); }
868 ///////////////////////////////////////////////////////////////////
870 // CLASS NAME : PoolQuery::Attr
873 * represents all atributes in PoolQuery except SolvAtributes, which are
874 * used as is (not needed extend anything if someone adds new solv attr)
876 struct PoolQueryAttr : public IdStringType<PoolQueryAttr>
879 friend class IdStringType<PoolQueryAttr>;
886 explicit PoolQueryAttr( const char* cstr_r )
890 explicit PoolQueryAttr( const std::string & str_r )
895 static const PoolQueryAttr noAttr;
898 static const PoolQueryAttr repoAttr;
899 static const PoolQueryAttr kindAttr;
900 static const PoolQueryAttr stringAttr;
901 static const PoolQueryAttr stringTypeAttr;
902 static const PoolQueryAttr requireAllAttr;
903 static const PoolQueryAttr caseSensitiveAttr;
904 static const PoolQueryAttr installStatusAttr;
907 const PoolQueryAttr PoolQueryAttr::noAttr;
909 const PoolQueryAttr PoolQueryAttr::repoAttr( "repo" );
910 const PoolQueryAttr PoolQueryAttr::kindAttr( "kind" );
911 const PoolQueryAttr PoolQueryAttr::stringAttr( "global_string" );
912 const PoolQueryAttr PoolQueryAttr::stringTypeAttr("string_type");
913 const PoolQueryAttr PoolQueryAttr::requireAllAttr("require_all");
914 const PoolQueryAttr PoolQueryAttr::caseSensitiveAttr("case_sensitive");
915 const PoolQueryAttr PoolQueryAttr::installStatusAttr("install_status");
917 class StringTypeAttr : public IdStringType<PoolQueryAttr>
919 friend class IdStringType<StringTypeAttr>;
924 explicit StringTypeAttr( const char* cstr_r )
926 explicit StringTypeAttr( const std::string & str_r )
929 static const StringTypeAttr noAttr;
931 static const StringTypeAttr exactAttr;
932 static const StringTypeAttr substringAttr;
933 static const StringTypeAttr regexAttr;
934 static const StringTypeAttr globAttr;
935 static const StringTypeAttr wordAttr;
937 const StringTypeAttr StringTypeAttr::noAttr;
939 const StringTypeAttr StringTypeAttr::exactAttr("exact");
940 const StringTypeAttr StringTypeAttr::substringAttr("substring");
941 const StringTypeAttr StringTypeAttr::regexAttr("regex");
942 const StringTypeAttr StringTypeAttr::globAttr("glob");
943 const StringTypeAttr StringTypeAttr::wordAttr("word");
945 ///////////////////////////////////////////////////////////////////
948 //\TODO maybe ctor with stream can be usefull
949 bool PoolQuery::recover( istream &str, char delim )
951 bool finded_something = false; //indicates some atributes is finded
957 getline( str, s, delim );
959 if ((!s.empty()) && s[0]=='#') //comment
964 string::size_type pos = s.find(':');
965 if (s.empty() || pos == s.npos) // some garbage on line... act like blank line
967 if (finded_something) //is first blank line after record?
977 finded_something = true;
979 string attrName(str::trim(string(s,0,pos))); // trimmed name of atribute
980 string attrValue(str::trim(string(s,pos+1,s.npos))); //trimmed value
982 PoolQueryAttr attribute( attrName );
984 if ( attribute==PoolQueryAttr::repoAttr )
986 addRepo( attrValue );
988 else if ( attribute==PoolQueryAttr::kindAttr )
990 addKind( ResKind(attrValue) );
992 else if ( attribute==PoolQueryAttr::stringAttr )
994 addString( attrValue );
996 else if ( attribute==PoolQueryAttr::stringTypeAttr )
998 StringTypeAttr s(attrValue);
999 if( s == StringTypeAttr::regexAttr )
1003 else if ( s == StringTypeAttr::globAttr )
1007 else if ( s == StringTypeAttr::exactAttr )
1011 else if ( s == StringTypeAttr::substringAttr )
1013 setMatchSubstring();
1015 else if ( s == StringTypeAttr::wordAttr )
1019 else if ( s == StringTypeAttr::noAttr )
1021 WAR << "unknown string type " << attrValue << endl;
1025 WAR << "forget recover some attribute defined as String type attribute: " << attrValue << endl;
1028 else if ( attribute==PoolQueryAttr::requireAllAttr )
1030 if ( str::strToTrue(attrValue) )
1032 setRequireAll(true);
1034 else if ( !str::strToFalse(attrValue) )
1036 setRequireAll(false);
1040 WAR << "unknown boolean value " << attrValue << endl;
1043 else if ( attribute==PoolQueryAttr::caseSensitiveAttr )
1045 if ( str::strToTrue(attrValue) )
1047 setCaseSensitive(true);
1049 else if ( !str::strToFalse(attrValue) )
1051 setCaseSensitive(false);
1055 WAR << "unknown boolean value " << attrValue << endl;
1058 else if ( attribute==PoolQueryAttr::installStatusAttr )
1060 if( attrValue == "all" )
1062 setStatusFilterFlags( ALL );
1064 else if( attrValue == "installed" )
1068 else if( attrValue == "not-installed" )
1070 setUninstalledOnly();
1074 WAR << "Unknown value for install status " << attrValue << endl;
1077 else if ( attribute==PoolQueryAttr::noAttr )
1079 WAR << "empty attribute name" << endl;
1083 string s = attrName;
1084 str::replace_all( s,"_",":" );
1086 addAttribute(a,attrValue);
1091 return finded_something;
1094 void PoolQuery::serialize( ostream &str, char delim ) const
1098 //iterate thrue all settings and write it
1099 static const zypp::PoolQuery q; //not save default options, so create default query example
1101 for_( it, repos().begin(), repos().end() )
1103 str << "repo: " << *it << delim ;
1106 for_( it, kinds().begin(), kinds().end() )
1108 str << "kind: " << it->idStr() << delim ;
1111 if (matchType()!=q.matchType())
1113 switch( matchType() )
1116 str << "string_type: exact" << delim;
1118 case SEARCH_SUBSTRING:
1119 str << "string_type: substring" << delim;
1122 str << "string_type: glob" << delim;
1125 str << "string_type: regex" << delim;
1128 WAR << "unknown match type " << matchType() << endl;
1132 if( caseSensitive() != q.caseSensitive() )
1134 str << "case_sensitive: ";
1135 if (caseSensitive())
1137 str << "on" << delim;
1141 str << "off" << delim;
1145 if( requireAll() != q.requireAll() )
1147 str << "require_all: ";
1150 str << "on" << delim;
1154 str << "off" << delim;
1158 if( statusFilterFlags() != q.statusFilterFlags() )
1160 switch( statusFilterFlags() )
1163 str << "install_status: all" << delim;
1165 case INSTALLED_ONLY:
1166 str << "install_status: installed" << delim;
1168 case UNINSTALLED_ONLY:
1169 str << "install_status: not-installed" << delim;
1174 for_( it, strings().begin(), strings().end() )
1176 str << "global_string: " << *it << delim;
1179 for_( it, attributes().begin(), attributes().end() )
1181 string s = it->first.asString();
1182 str::replace_all(s,":","_");
1183 for_( it2,it->second.begin(),it->second.end() )
1185 str << s <<": "<< *it2 << delim;
1189 //separating delim - protection
1195 string PoolQuery::asString() const
1196 { return _pimpl->asString(); }
1199 ostream & operator<<( ostream & str, const PoolQuery & obj )
1200 { return str << obj.asString(); }
1202 //internal matching two containers O(n^2)
1203 template <class Container>
1204 bool equalContainers(const Container& a, const Container& b)
1206 if (a.size()!=b.size())
1209 for_(it,a.begin(),a.end())
1211 bool finded = false;
1212 for_( it2, b.begin(),b.end() )
1227 bool PoolQuery::operator==(const PoolQuery& a) const
1229 if (!_pimpl->_compiled)
1231 if (!a._pimpl->_compiled)
1232 a._pimpl->compile();
1233 if( matchType()!=a.matchType() )
1235 if( a.matchWord()!=matchWord())
1237 if( a.requireAll()!=requireAll() )
1239 if(!equalContainers(a.kinds(), kinds()))
1241 if(!equalContainers(a.repos(), repos()))
1243 if(a._pimpl->_rcstrings!=_pimpl->_rcstrings)
1245 if(!equalContainers(a._pimpl->_rcattrs, _pimpl->_rcattrs))
1247 if(a._pimpl->_cflags!= _pimpl->_cflags)
1254 /////////////////////////////////////////////////////////////////
1256 ///////////////////////////////////////////////////////////////////