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 )
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 // if only one repository has been specified, find it in the pool
368 sat::Pool pool(sat::Pool::instance());
369 sat::Pool::RepositoryIterator itr = pool.reposBegin();
370 if (!(_cflags & SEARCH_ALL_REPOS) && _repos.size() == 1)
372 string theone = *_repos.begin();
373 for (; itr->info().alias() != theone && itr != pool.reposEnd(); ++itr);
374 if (itr == pool.reposEnd())
376 RepoInfo info; info.setAlias(theone);
377 ERR << "Repository not found in sat pool." << endl;
378 ZYPP_THROW(repo::RepoNotFoundException(info));
382 DBG << "_cflags:" << _cflags << endl;
384 scoped_ptr< ::_Dataiterator> _rdit( new ::Dataiterator );
385 // needed while LookupAttr::iterator::dip_equal does ::memcmp:
386 ::memset( _rdit.get(), 0, sizeof(::_Dataiterator) );
388 if (_rcattrs.empty())
390 ::dataiterator_init(_rdit.get(),
391 _cflags & SEARCH_ALL_REPOS ? pool.get()->repos[0] : itr->get(), // repository \todo fix this
392 0, // search all solvables
393 0, // attribute id - only if 1 attr key specified
394 _rcstrings.empty() ? 0 : _rcstrings.c_str(), // compiled search string
397 else if (_rcattrs.size() == 1)
399 ::dataiterator_init(_rdit.get(),
400 _cflags & SEARCH_ALL_REPOS ? pool.get()->repos[0] : itr->get(), // repository \todo fix this
401 0, // search all solvables
402 _rcattrs.begin()->first.id(), // keyname - attribute id - only if 1 attr key specified
403 _rcstrings.empty() ? 0 : _rcstrings.c_str(), // compiled search string
408 ::dataiterator_init(_rdit.get(),
409 _cflags & SEARCH_ALL_REPOS ? pool.get()->repos[0] : itr->get(), /* repository - switch to next at the end of current one in increment() */
410 0, /*search all resolvables */
411 0, /*keyname - if only 1 attr key specified, pass it here, otherwise do more magic */
412 0, //qs.empty() ? 0 : qs.c_str(), /* create regex, pass it here */
416 if ((_cflags & SEARCH_STRINGMASK) == SEARCH_REGEX && _rdit->regex_err != 0)
417 ZYPP_THROW(Exception(str::form(
418 _("Invalid regular expression '%s': regcomp returned %d"),
419 _rcstrings.c_str(), _rdit->regex_err)));
421 PoolQuery::const_iterator it(_rdit, this);
426 PoolQuery::const_iterator PoolQuery::Impl::end() const
428 //INT << "end" << endl;
429 return PoolQuery::const_iterator();
433 string PoolQuery::Impl::asString() const
437 o << "compiled: " << _compiled << endl;
440 for(Kinds::const_iterator it = _kinds.begin();
441 it != _kinds.end(); ++it)
446 for(StrContainer::const_iterator it = _repos.begin();
447 it != _repos.end(); ++it)
451 o << "string match flags:" << endl;
452 o << "* string/substring/glob/regex: " << (_cflags & SEARCH_STRINGMASK) << endl;
453 o << "* SEARCH_NOCASE: " << ((_cflags & SEARCH_NOCASE) ? "yes" : "no") << endl;
454 o << "* SEARCH_ALL_REPOS: " << ((_cflags & SEARCH_ALL_REPOS) ? "yes" : "no") << endl;
455 o << "status filter flags:" << _status_flags << endl;
460 for(StrContainer::const_iterator it = _strings.begin();
461 it != _strings.end(); ++it)
465 o << "attributes: " << endl;
466 for(AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai)
468 o << "* " << ai->first << ": ";
469 for(StrContainer::const_iterator vi = ai->second.begin();
470 vi != ai->second.end(); ++vi)
477 o << "compiled strings: " << _rcstrings << endl;
478 o << "compiled attributes:" << endl;
479 for (AttrCompiledStrMap::const_iterator ai = _rcattrs.begin(); ai != _rcattrs.end(); ++ai)
480 o << "* " << ai->first << ": " << ai->second << endl;
485 /** \relates PoolQuery::Impl Stream output *//*
486 inline std::ostream & operator<<( std::ostream & str, const PoolQuery::Impl & obj )
488 return str << "PoolQuery::Impl";
491 ///////////////////////////////////////////////////////////////////
493 ///////////////////////////////////////////////////////////////////
495 { /////////////////////////////////////////////////////////////////
497 ///////////////////////////////////////////////////////////////////
499 // CLASS NAME : PoolQuery::ResultIterator
501 ///////////////////////////////////////////////////////////////////
503 PoolQueryIterator::PoolQueryIterator()
504 : _sid(0), _has_next(false), _do_matching(false)
505 { this->base_reference() = LookupAttr::iterator(); }
508 PoolQueryIterator::PoolQueryIterator(
509 scoped_ptr< ::_Dataiterator> & dip_r,
510 const PoolQuery::Impl * pqimpl)
513 , _do_matching(pqimpl->_rcattrs.size() > 1)
514 , _flags(pqimpl->_cflags)
515 , _str(pqimpl->_rcstrings)
516 , _regex(pqimpl->_regex)
517 , _attrs_str(pqimpl->_rcattrs)
518 , _attrs_regex(pqimpl->_rattrs)
519 , _repos(pqimpl->_repos)
520 , _kinds(pqimpl->_kinds)
521 , _status_flags(pqimpl->_status_flags)
523 this->base_reference() = LookupAttr::iterator(dip_r, true); //!\todo pass chain_repos
524 _has_next = (*base_reference() != sat::detail::noId);
528 PoolQueryIterator::PoolQueryIterator(const PoolQueryIterator & rhs)
530 , _has_next(rhs._has_next)
531 , _do_matching(rhs._do_matching)
535 , _attrs_str(rhs._attrs_str)
536 , _attrs_regex(rhs._attrs_regex)
539 , _status_flags(rhs._status_flags)
540 { base_reference() = LookupAttr::iterator(rhs.base()); }
543 PoolQueryIterator::~PoolQueryIterator()
547 PoolQueryIterator & PoolQueryIterator::operator=( const PoolQueryIterator & rhs )
549 base_reference() = rhs.base();
551 _has_next = rhs._has_next;
552 _do_matching = rhs._do_matching;
556 _attrs_str = rhs._attrs_str;
557 _attrs_regex = rhs._attrs_regex;
560 _status_flags = rhs._status_flags;
565 void PoolQueryIterator::increment()
570 bool got_match = false;
573 DBG << "last: " << _sid << endl;
574 while (_has_next && !(got_match = matchSolvable()));
577 // no more solvables and the last did not match
578 if (!got_match && !_has_next)
580 base_reference() = LookupAttr::iterator();
584 DBG << "next: " << _sid << endl;
587 bool PoolQueryIterator::matchSolvable()
589 _sid = base().get()->solvid;
591 bool new_solvable = true;
592 bool matches = !_do_matching;
593 bool drop_by_kind_status = false;
594 bool drop_by_repo = false;
601 drop_by_repo = false;
602 if(!_repos.empty() &&
603 _repos.find(base().get()->repo->name) == _repos.end())
609 drop_by_kind_status = false;
611 // whether to drop an uninstalled (repo) solvable
612 if ( (_status_flags & PoolQuery::INSTALLED_ONLY) &&
613 base().get()->repo->name != sat::Pool::instance().systemRepoName() )
615 drop_by_kind_status = true;
619 // whether to drop an installed (target) solvable
620 if ((_status_flags & PoolQuery::UNINSTALLED_ONLY) &&
621 base().get()->repo->name == sat::Pool::instance().systemRepoName())
623 drop_by_kind_status = true;
627 // whether to drop unwanted kind
630 sat::Solvable s(_sid);
631 // the user wants to filter by kind.
632 if (_kinds.find(s.kind()) == _kinds.end())
633 drop_by_kind_status = true;
639 matches = matches && !drop_by_kind_status && !drop_by_repo;
642 if (_do_matching && !drop_by_kind_status)
646 SolvAttr attr(base().get()->key->name);
647 PoolQuery::AttrCompiledStrMap::const_iterator ai = _attrs_str.find(attr);
648 if (ai != _attrs_str.end())
650 if ((_flags & SEARCH_STRINGMASK) == SEARCH_REGEX)
652 const regex_t * regex_p;
655 PoolQuery::AttrRegexMap::iterator rai = _attrs_regex.find(attr);
656 if (rai != _attrs_regex.end())
657 regex_p = rai->second.get();
660 ERR << "no compiled regex found for " << attr << endl;
665 regex_p = _regex.get();
666 matches = ::dataiterator_match(base().get(), _flags, regex_p);
670 const string & sstr =
671 _str.empty() ? ai->second : _str;
672 matches = ::dataiterator_match(base().get(), _flags, sstr.c_str());
676 /* After calling dataiterator_match (with any string matcher set)
677 the kv.str member will be filled with something sensible. */
678 /* INT << "value: " << base().get()->kv.str << endl
679 << " mstr: " << sstr << endl; */
686 base_reference().nextSkipRepo();
687 drop_by_repo = false;
689 else if (drop_by_kind_status)
691 base_reference().nextSkipSolvable();
692 drop_by_kind_status = false;
695 // copy the iterator to forward check for the next attribute ***
696 _tmpit = base_reference();
697 _has_next = (*(++_tmpit) != sat::detail::noId);
701 // *** now increment. Had it not be done this way,
702 // the LookupAttr::iterator could have reached the end() while
703 // trying to reach a matching attribute or the next solvable
704 // thus resulting to a problem in the equal() method
706 new_solvable = base().get()->solvid != _sid;
708 // no more attributes in this repo, return
710 return matches; // did the last solvable match conditions?
712 while (!new_solvable);
717 ///////////////////////////////////////////////////////////////////
719 ///////////////////////////////////////////////////////////////////
721 ///////////////////////////////////////////////////////////////////
723 // CLASS NAME : PoolQuery
725 ///////////////////////////////////////////////////////////////////
727 PoolQuery::PoolQuery()
732 PoolQuery::~PoolQuery()
736 void PoolQuery::addRepo(const std::string &repoalias)
738 _pimpl->_repos.insert(repoalias);
739 _pimpl->_flags &= ~SEARCH_ALL_REPOS;
743 void PoolQuery::addKind(const ResKind & kind)
744 { _pimpl->_kinds.insert(kind); }
747 void PoolQuery::addString(const string & value)
748 { _pimpl->_strings.insert(value); }
751 void PoolQuery::addAttribute(const sat::SolvAttr & attr, const std::string & value)
752 { _pimpl->_attrs[attr].insert(value); }
755 void PoolQuery::setCaseSensitive(const bool value)
758 _pimpl->_flags &= ~SEARCH_NOCASE;
760 _pimpl->_flags |= SEARCH_NOCASE;
764 void PoolQuery::setMatchSubstring()
765 { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_SUBSTRING; }
766 void PoolQuery::setMatchExact()
767 { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_STRING; }
768 void PoolQuery::setMatchRegex()
769 { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_REGEX; }
770 void PoolQuery::setMatchGlob()
771 { _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_GLOB; }
772 void PoolQuery::setMatchWord()
774 _pimpl->_match_word = true;
775 _pimpl->_flags = (_pimpl->_flags & ~SEARCH_STRINGMASK) | SEARCH_REGEX;
778 void PoolQuery::setFlags(int flags)
779 { _pimpl->_flags = flags; }
782 void PoolQuery::setInstalledOnly()
783 { _pimpl->_status_flags = INSTALLED_ONLY; }
784 void PoolQuery::setUninstalledOnly()
785 { _pimpl->_status_flags = UNINSTALLED_ONLY; }
786 void PoolQuery::setStatusFilterFlags( PoolQuery::StatusFilter flags )
787 { _pimpl->_status_flags = flags; }
790 void PoolQuery::setRequireAll(const bool require_all)
791 { _pimpl->_require_all = require_all; }
794 const PoolQuery::StrContainer &
795 PoolQuery::strings() const
796 { return _pimpl->_strings; }
798 const PoolQuery::AttrRawStrMap &
799 PoolQuery::attributes() const
800 { return _pimpl->_attrs; }
802 const PoolQuery::StrContainer &
803 PoolQuery::attribute(const sat::SolvAttr & attr) const
805 static const PoolQuery::StrContainer nocontainer;
806 AttrRawStrMap::const_iterator it = _pimpl->_attrs.find(attr);
807 return it != _pimpl->_attrs.end() ? it->second : nocontainer;
810 const PoolQuery::Kinds &
811 PoolQuery::kinds() const
812 { return _pimpl->_kinds; }
814 const PoolQuery::StrContainer &
815 PoolQuery::repos() const
816 { return _pimpl->_repos; }
818 bool PoolQuery::caseSensitive() const
819 { return _pimpl->_flags & SEARCH_NOCASE; }
821 bool PoolQuery::matchExact() const
822 { return (_pimpl->_flags & SEARCH_STRINGMASK) == SEARCH_STRING; }
823 bool PoolQuery::matchSubstring() const
824 { return (_pimpl->_flags & SEARCH_STRINGMASK) == SEARCH_SUBSTRING; }
825 bool PoolQuery::matchGlob() const
826 { return (_pimpl->_flags & SEARCH_STRINGMASK) == SEARCH_GLOB; }
827 bool PoolQuery::matchRegex() const
828 { return (_pimpl->_flags & SEARCH_STRINGMASK) == SEARCH_REGEX; }
829 int PoolQuery::matchType() const
830 { return _pimpl->_flags & SEARCH_STRINGMASK; }
832 bool PoolQuery::matchWord() const
833 { return _pimpl->_match_word; }
835 bool PoolQuery::requireAll() const
836 { return _pimpl->_require_all; }
838 PoolQuery::StatusFilter PoolQuery::statusFilterFlags() const
839 { return _pimpl->_status_flags; }
841 PoolQuery::const_iterator PoolQuery::begin() const
842 { return _pimpl->begin(); }
845 PoolQuery::const_iterator PoolQuery::end() const
846 { return _pimpl->end(); }
849 bool PoolQuery::empty()
850 { return _pimpl->begin() == _pimpl->end(); }
852 //! \todo collect the result, reuse if not dirty
853 PoolQuery::size_type PoolQuery::size()
856 for(const_iterator it = _pimpl->begin(); it != _pimpl->end(); ++it, ++count);
861 void PoolQuery::execute(ProcessResolvable fnc)
862 { invokeOnEach(_pimpl->begin(), _pimpl->end(), fnc); }
865 ///////////////////////////////////////////////////////////////////
867 // CLASS NAME : PoolQuery::Attr
870 * represents all atributes in PoolQuery except SolvAtributes, which are
871 * used as is (not needed extend anything if someone adds new solv attr)
873 struct PoolQueryAttr : public IdStringType<PoolQueryAttr>
876 friend class IdStringType<PoolQueryAttr>;
883 explicit PoolQueryAttr( const char* cstr_r )
887 explicit PoolQueryAttr( const std::string & str_r )
892 static const PoolQueryAttr noAttr;
895 static const PoolQueryAttr repoAttr;
896 static const PoolQueryAttr kindAttr;
897 static const PoolQueryAttr stringAttr;
898 static const PoolQueryAttr stringTypeAttr;
899 static const PoolQueryAttr requireAllAttr;
900 static const PoolQueryAttr caseSensitiveAttr;
901 static const PoolQueryAttr installStatusAttr;
904 const PoolQueryAttr PoolQueryAttr::noAttr;
906 const PoolQueryAttr PoolQueryAttr::repoAttr( "repo" );
907 const PoolQueryAttr PoolQueryAttr::kindAttr( "kind" );
908 const PoolQueryAttr PoolQueryAttr::stringAttr( "global_string" );
909 const PoolQueryAttr PoolQueryAttr::stringTypeAttr("string_type");
910 const PoolQueryAttr PoolQueryAttr::requireAllAttr("require_all");
911 const PoolQueryAttr PoolQueryAttr::caseSensitiveAttr("case_sensitive");
912 const PoolQueryAttr PoolQueryAttr::installStatusAttr("install_status");
914 class StringTypeAttr : public IdStringType<PoolQueryAttr>
916 friend class IdStringType<StringTypeAttr>;
921 explicit StringTypeAttr( const char* cstr_r )
923 explicit StringTypeAttr( const std::string & str_r )
926 static const StringTypeAttr noAttr;
928 static const StringTypeAttr exactAttr;
929 static const StringTypeAttr substringAttr;
930 static const StringTypeAttr regexAttr;
931 static const StringTypeAttr globAttr;
932 static const StringTypeAttr wordAttr;
934 const StringTypeAttr StringTypeAttr::noAttr;
936 const StringTypeAttr StringTypeAttr::exactAttr("exact");
937 const StringTypeAttr StringTypeAttr::substringAttr("substring");
938 const StringTypeAttr StringTypeAttr::regexAttr("regex");
939 const StringTypeAttr StringTypeAttr::globAttr("glob");
940 const StringTypeAttr StringTypeAttr::wordAttr("word");
942 ///////////////////////////////////////////////////////////////////
945 //\TODO maybe ctor with stream can be usefull
946 bool PoolQuery::recover( istream &str, char delim )
948 bool finded_something = false; //indicates some atributes is finded
954 getline( str, s, delim );
956 if ((!s.empty()) && s[0]=='#') //comment
961 string::size_type pos = s.find(':');
962 if (s.empty() || pos == s.npos) // some garbage on line... act like blank line
964 if (finded_something) //is first blank line after record?
974 finded_something = true;
976 string attrName(str::trim(string(s,0,pos))); // trimmed name of atribute
977 string attrValue(str::trim(string(s,pos+1,s.npos))); //trimmed value
979 PoolQueryAttr attribute( attrName );
981 if ( attribute==PoolQueryAttr::repoAttr )
983 addRepo( attrValue );
985 else if ( attribute==PoolQueryAttr::kindAttr )
987 addKind( ResKind(attrValue) );
989 else if ( attribute==PoolQueryAttr::stringAttr )
991 addString( attrValue );
993 else if ( attribute==PoolQueryAttr::stringTypeAttr )
995 StringTypeAttr s(attrValue);
996 if( s == StringTypeAttr::regexAttr )
1000 else if ( s == StringTypeAttr::globAttr )
1004 else if ( s == StringTypeAttr::exactAttr )
1008 else if ( s == StringTypeAttr::substringAttr )
1010 setMatchSubstring();
1012 else if ( s == StringTypeAttr::wordAttr )
1016 else if ( s == StringTypeAttr::noAttr )
1018 WAR << "unknown string type " << attrValue << endl;
1022 WAR << "forget recover some attribute defined as String type attribute: " << attrValue << endl;
1025 else if ( attribute==PoolQueryAttr::requireAllAttr )
1027 if ( str::strToTrue(attrValue) )
1029 setRequireAll(true);
1031 else if ( !str::strToFalse(attrValue) )
1033 setRequireAll(false);
1037 WAR << "unknown boolean value " << attrValue << endl;
1040 else if ( attribute==PoolQueryAttr::caseSensitiveAttr )
1042 if ( str::strToTrue(attrValue) )
1044 setCaseSensitive(true);
1046 else if ( !str::strToFalse(attrValue) )
1048 setCaseSensitive(false);
1052 WAR << "unknown boolean value " << attrValue << endl;
1055 else if ( attribute==PoolQueryAttr::installStatusAttr )
1057 if( attrValue == "all" )
1059 setStatusFilterFlags( ALL );
1061 else if( attrValue == "installed" )
1065 else if( attrValue == "not-installed" )
1067 setUninstalledOnly();
1071 WAR << "Unknown value for install status " << attrValue << endl;
1074 else if ( attribute==PoolQueryAttr::noAttr )
1076 WAR << "empty attribute name" << endl;
1080 string s = attrName;
1081 str::replace_all( s,"_",":" );
1083 addAttribute(a,attrValue);
1088 return finded_something;
1091 void PoolQuery::serialize( ostream &str, char delim ) const
1095 //iterate thrue all settings and write it
1096 static const zypp::PoolQuery q; //not save default options, so create default query example
1098 for_( it, repos().begin(), repos().end() )
1100 str << "repo: " << *it << delim ;
1103 for_( it, kinds().begin(), kinds().end() )
1105 str << "kind: " << it->idStr() << delim ;
1108 if (matchType()!=q.matchType())
1110 switch( matchType() )
1113 str << "string_type: exact" << delim;
1115 case SEARCH_SUBSTRING:
1116 str << "string_type: substring" << delim;
1119 str << "string_type: glob" << delim;
1122 str << "string_type: regex" << delim;
1125 WAR << "unknown match type " << matchType() << endl;
1129 if( caseSensitive() != q.caseSensitive() )
1131 str << "case_sensitive: ";
1132 if (caseSensitive())
1134 str << "on" << delim;
1138 str << "off" << delim;
1142 if( requireAll() != q.requireAll() )
1144 str << "require_all: ";
1147 str << "on" << delim;
1151 str << "off" << delim;
1155 if( statusFilterFlags() != q.statusFilterFlags() )
1157 switch( statusFilterFlags() )
1160 str << "install_status: all" << delim;
1162 case INSTALLED_ONLY:
1163 str << "install_status: installed" << delim;
1165 case UNINSTALLED_ONLY:
1166 str << "install_status: not-installed" << delim;
1171 for_( it, strings().begin(), strings().end() )
1173 str << "global_string: " << *it << delim;
1176 for_( it, attributes().begin(), attributes().end() )
1178 string s = it->first.asString();
1179 str::replace_all(s,":","_");
1180 for_( it2,it->second.begin(),it->second.end() )
1182 str << s <<": "<< *it2 << delim;
1186 //separating delim - protection
1192 string PoolQuery::asString() const
1193 { return _pimpl->asString(); }
1196 ostream & operator<<( ostream & str, const PoolQuery & obj )
1197 { return str << obj.asString(); }
1199 //internal matching two containers O(n^2)
1200 template <class Container>
1201 bool equalContainers(const Container& a, const Container& b)
1203 if (a.size()!=b.size())
1206 for_(it,a.begin(),a.end())
1208 bool finded = false;
1209 for_( it2, b.begin(),b.end() )
1224 bool PoolQuery::operator==(const PoolQuery& a) const
1226 if (!_pimpl->_compiled)
1228 if (!a._pimpl->_compiled)
1229 a._pimpl->compile();
1230 if( matchType()!=a.matchType() )
1232 if( a.matchWord()!=matchWord())
1234 if( a.requireAll()!=requireAll() )
1236 if(!equalContainers(a.kinds(), kinds()))
1238 if(!equalContainers(a.repos(), repos()))
1240 if(a._pimpl->_rcstrings!=_pimpl->_rcstrings)
1242 if(!equalContainers(a._pimpl->_rcattrs, _pimpl->_rcattrs))
1244 if(a._pimpl->_cflags!= _pimpl->_cflags)
1251 /////////////////////////////////////////////////////////////////
1253 ///////////////////////////////////////////////////////////////////