X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=zypp%2FPoolQuery.cc;h=5fe838eb231dda8ff59f58deb0abd543e01904be;hb=42b5d038414cf4a4a050e816b471f890b24e8032;hp=17b76151acfa5cb92c6f4404a0a1e6e62234380f;hpb=b61a0ff7e76a542a874714e4ee7753db48f9f8aa;p=platform%2Fupstream%2Flibzypp.git diff --git a/zypp/PoolQuery.cc b/zypp/PoolQuery.cc index 17b7615..5fe838e 100644 --- a/zypp/PoolQuery.cc +++ b/zypp/PoolQuery.cc @@ -179,13 +179,6 @@ namespace zypp * match, it's also suitable for sub-structure (flexarray) inspection * (\see \ref sat::LookupAttr::iterator::solvAttrSubEntry). * - * (bsc#1035729) If SolvAttr::name searches for an explicit \c kind:name, - * this \c kind is stored in \ref kindPredicate and will overwrite any - * 'global' kind restriction applied via \ref PoolQuery::addKind. This - * task can't be passed off to a predicate, as \ref PoolQueryMatcher::isAMatch - * must accept only explicit-kind-checking predicate matches, in case the - * 'global' kind restriction woudl otherwise discard the match. - * * \note: \see \ref addPredicate for further constraints. */ struct AttrMatchData @@ -198,10 +191,6 @@ namespace zypp AttrMatchData() {} - AttrMatchData( sat::SolvAttr attr_r ) - : attr( attr_r ) - {} - AttrMatchData( sat::SolvAttr attr_r, const StrMatcher & strMatcher_r ) : attr( attr_r ) , strMatcher( strMatcher_r ) @@ -220,8 +209,8 @@ namespace zypp * string representation instead. If you add new predicated, check the * deserialization code in \ref deserialize. */ - template - void addPredicate( const _Predicate & predicate_r ) + template + void addPredicate( const TPredicate & predicate_r ) { predicate = predicate_r; predicateStr = predicate_r.serialize(); @@ -312,18 +301,15 @@ namespace zypp } sat::SolvAttr attr; - StrMatcher strMatcher; + StrMatcher strMatcher; Predicate predicate; std::string predicateStr; - ResKind kindPredicate = ResKind::nokind; // holds the 'kind' part if SolvAttr:name looks for an explicit 'kind:name' }; /** \relates AttrMatchData */ inline std::ostream & operator<<( std::ostream & str, const AttrMatchData & obj ) { str << obj.attr << ": " << obj.strMatcher; - if ( obj.kindPredicate ) - str << " +(" << obj.kindPredicate << ")"; if ( obj.predicate ) str << " +(" << obj.predicateStr << ")"; return str; @@ -371,6 +357,7 @@ namespace zypp Impl() : _flags( Match::SUBSTRING | Match::NOCASE | Match::SKIP_KIND ) , _match_word(false) + , _require_all(false) , _status_flags(ALL) {} @@ -393,6 +380,7 @@ namespace zypp /** Sat solver search flags */ Match _flags; bool _match_word; + bool _require_all; /** Sat solver status flags */ StatusFilter _status_flags; @@ -411,23 +399,6 @@ namespace zypp public: - bool operator<( const PoolQuery::Impl & rhs ) const - { -#define OUTS(A) if ( A != rhs.A ) return A < rhs.A; - OUTS( _strings ); - OUTS( _attrs ); - OUTS( _uncompiledPredicated ); - OUTS( _flags.get() ); - OUTS( _match_word ); - OUTS( _status_flags ); - OUTS( _edition ); - OUTS( _op.inSwitch() ); - OUTS( _repos ); - OUTS( _kinds ); -#undef OUTS - return false; - } - bool operator==( const PoolQuery::Impl & rhs ) const { if ( _flags == rhs._flags @@ -446,6 +417,7 @@ namespace zypp && _attrs == rhs._attrs && _uncompiledPredicated == rhs._uncompiledPredicated && _match_word == rhs._match_word + && _require_all == rhs._require_all && _status_flags == rhs._status_flags && _edition == rhs._edition && _op == rhs._op @@ -469,10 +441,8 @@ namespace zypp mutable AttrMatchList _attrMatchList; private: - /** Join patterns in \a container_r according to \a flags_r into a single \ref StrMatcher. - * The \ref StrMatcher returned will be a REGEX if more than one pattern was passed. - */ - StrMatcher joinedStrMatcher( const StrContainer & container_r, const Match & flags_r ) const; + /** Pass flags from \ref compile, as they may have been changed. */ + string createRegex( const StrContainer & container, const Match & flags ) const; private: friend Impl * rwcowClone( const Impl * rhs ); @@ -509,8 +479,13 @@ namespace zypp { _attrMatchList.clear(); - if ( _flags.mode() == Match::OTHER ) // this will never succeed... - ZYPP_THROW( MatchUnknownModeException( _flags ) ); + Match cflags( _flags ); + if ( cflags.mode() == Match::OTHER ) // this will never succeed... + ZYPP_THROW( MatchUnknownModeException( cflags ) ); + + /** Compiled search strings. */ + string rcstrings; + // 'different' - will have to iterate through all and match by ourselves (slow) // 'same' - will pass the compiled string to dataiterator_init @@ -535,8 +510,11 @@ namespace zypp StrContainer joined; invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined)); invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined)); - - _attrMatchList.push_back( AttrMatchData( _attrs.begin()->first, joinedStrMatcher( joined, _flags ) ) ); + rcstrings = createRegex(joined, cflags); + if (joined.size() > 1) // switch to regex for multiple strings + cflags.setModeRegex(); + _attrMatchList.push_back( AttrMatchData( _attrs.begin()->first, + StrMatcher( rcstrings, cflags ) ) ); } // // MULTIPLE ATTRIBUTES @@ -544,21 +522,16 @@ namespace zypp { // check whether there are any per-attribute strings bool attrvals_empty = true; - for_( ai, _attrs.begin(), _attrs.end() ) - { - if ( ai->second.empty() ) - continue; - for_( it, ai->second.begin(), ai->second.end() ) - { - if ( !it->empty() ) - { - attrvals_empty = false; - break; - } - } - if ( ! attrvals_empty ) - break; - } + for (AttrRawStrMap::const_iterator ai = _attrs.begin(); ai != _attrs.end(); ++ai) + if (!ai->second.empty()) + for(StrContainer::const_iterator it = ai->second.begin(); + it != ai->second.end(); it++) + if (!it->empty()) + { + attrvals_empty = false; + goto attremptycheckend; + } +attremptycheckend: // chceck whether the per-attribute strings are all the same bool attrvals_thesame = true; @@ -589,15 +562,18 @@ namespace zypp if (attrvals_empty) { invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined)); + rcstrings = createRegex(joined, cflags); } else { invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined)); invokeOnEach(_attrs.begin()->second.begin(), _attrs.begin()->second.end(), EmptyFilter(), MyInserter(joined)); + rcstrings = createRegex(joined, cflags); } - + if (joined.size() > 1) // switch to regex for multiple strings + cflags.setModeRegex(); // May use the same StrMatcher for all - StrMatcher matcher( joinedStrMatcher( joined, _flags ) ); + StrMatcher matcher( rcstrings, cflags ); for_( ai, _attrs.begin(), _attrs.end() ) { _attrMatchList.push_back( AttrMatchData( ai->first, matcher ) ); @@ -615,8 +591,11 @@ namespace zypp StrContainer joined; invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined)); invokeOnEach(ai->second.begin(), ai->second.end(), EmptyFilter(), MyInserter(joined)); - - _attrMatchList.push_back( AttrMatchData( ai->first, joinedStrMatcher( joined, _flags ) ) ); + string s = createRegex(joined, cflags); + if (joined.size() > 1) // switch to regex for multiple strings + cflags.setModeRegex(); + _attrMatchList.push_back( AttrMatchData( ai->first, + StrMatcher( s, cflags ) ) ); } } } @@ -636,10 +615,14 @@ namespace zypp if ( ! mstr.empty() ) joined.insert( mstr ); - // copy and exchange the StrMatcher - AttrMatchData nattr( *it ); - nattr.strMatcher = joinedStrMatcher( joined, _flags ); - _attrMatchList.push_back( std::move(nattr) ); + cflags = _flags; + rcstrings = createRegex( joined, cflags ); + if ( joined.size() > 1 ) // switch to regex for multiple strings + cflags.setModeRegex(); + + _attrMatchList.push_back( AttrMatchData( it->attr, + StrMatcher( rcstrings, cflags ), + it->predicate, it->predicateStr ) ); } else { @@ -652,7 +635,12 @@ namespace zypp // If no attributes defined at all, then add 'query all' if ( _attrMatchList.empty() ) { - _attrMatchList.push_back( AttrMatchData( sat::SolvAttr::allAttr, joinedStrMatcher( _strings, _flags ) ) ); + cflags = _flags; + rcstrings = createRegex( _strings, cflags ); + if ( _strings.size() > 1 ) // switch to regex for multiple strings + cflags.setModeRegex(); + _attrMatchList.push_back( AttrMatchData( sat::SolvAttr::allAttr, + StrMatcher( rcstrings, cflags ) ) ); } // Finally check here, whether all involved regex compile. @@ -663,62 +651,102 @@ namespace zypp //DBG << asString() << endl; } - /////////////////////////////////////////////////////////////////// - namespace + + /** + * Converts '*' and '?' wildcards within str into their regex equivalents. + */ + static string wildcards2regex(const string & str) { - /** Escape \a str_r for use in a regex. - * \a flags_r determines whether the input string is interpreted - * as regex, glob or plain string. - */ - std::string rxEscape( std::string str_r, const Match & flags_r ) + string regexed = str; + + string r_all(".*"); // regex equivalent of '*' + string r_one("."); // regex equivalent of '?' + string::size_type pos; + + // replace all "*" in input with ".*" + for (pos = 0; (pos = regexed.find("*", pos)) != std::string::npos; pos+=2) + regexed = regexed.replace(pos, 1, r_all); + + // replace all "?" in input with "." + for (pos = 0; (pos = regexed.find('?', pos)) != std::string::npos; ++pos) + regexed = regexed.replace(pos, 1, r_one); + + return regexed; + } + + string PoolQuery::Impl::createRegex( const StrContainer & container, const Match & flags ) const + { +//! macro for word boundary tags for regexes +#define WB (_match_word ? string("\\b") : string()) + string rstr; + + if (container.empty()) + return rstr; + + if (container.size() == 1) { - if ( str_r.empty() || flags_r.isModeRegex() ) - return str_r; + return WB + *container.begin() + WB; + } + + // multiple strings + + bool use_wildcards = flags.isModeGlob(); + StrContainer::const_iterator it = container.begin(); + string tmp; - if ( flags_r.isModeGlob() ) - return str::rxEscapeGlob( std::move(str_r) ); + if (use_wildcards) + tmp = wildcards2regex(*it); + else + tmp = *it; - return str::rxEscapeStr( std::move(str_r) ); + if (_require_all) + { + if ( ! flags.isModeString() ) // not match exact + tmp += ".*" + WB + tmp; + rstr = "(?=" + tmp + ")"; + } + else + { + if ( flags.isModeString() || flags.isModeGlob() ) + rstr = "^"; + rstr += WB + "(" + tmp; } - } // namespace - /////////////////////////////////////////////////////////////////// - StrMatcher PoolQuery::Impl::joinedStrMatcher( const StrContainer & container_r, const Match & flags_r ) const - { - if ( container_r.empty() ) - return StrMatcher( std::string(), flags_r ); - - if ( container_r.size() == 1 && !_match_word ) // use RX to match words - return StrMatcher( *container_r.begin(), flags_r ); - - // Convert to a regex. - // Note: Modes STRING and GLOB match whole strings (anchored ^ $) - // SUBSTRING and REGEX match substrings (match_word anchores SUBSTRING \b) - Match retflags( flags_r ); - retflags.setModeRegex(); - str::Str ret; - - if ( flags_r.isModeString() || flags_r.isModeGlob() ) - ret << "^"; - else if ( _match_word ) - ret << "\\b"; - - // (..|..|..) - char sep = '('; - for ( const::std::string & s : container_r ) + ++it; + + for (; it != container.end(); ++it) { - ret << sep << rxEscape( s, flags_r ); - if ( sep == '(' ) - sep = '|'; + if (use_wildcards) + tmp = wildcards2regex(*it); + else + tmp = *it; + + if (_require_all) + { + if ( ! flags.isModeString() ) // not match exact + tmp += ".*" + WB + tmp; + rstr += "(?=" + tmp + ")"; + } + else + { + rstr += "|" + tmp; + } } - ret << ')'; - if ( flags_r.isModeString() || flags_r.isModeGlob() ) - ret << "$"; - else if ( _match_word ) - ret << "\\b"; + if (_require_all) + { + if ( ! flags.isModeString() ) // not match exact + rstr += WB + ".*"; + } + else + { + rstr += ")" + WB; + if ( flags.isModeString() || flags.isModeGlob() ) + rstr += "$"; + } - return StrMatcher( ret, retflags ); + return rstr; +#undef WB } string PoolQuery::Impl::asString() const @@ -831,14 +859,10 @@ namespace zypp void PoolQuery::addDependency( const sat::SolvAttr & attr, const std::string & name, const Rel & op, const Edition & edition, const Arch & arch ) { - // SolvAttr::name with explicit 'kind:name' will overwrite the default _kinds - ResKind explicitKind; - if ( attr == sat::SolvAttr::name ) explicitKind = ResKind::explicitBuiltin( name ); - switch ( op.inSwitch() ) { case Rel::ANY_e: // no additional constraint on edition. - if ( arch.empty() && !explicitKind ) // no additional constraint on arch/kind + if ( arch.empty() ) // no additional constraint on arch. { addAttribute( attr, name ); return; @@ -854,15 +878,7 @@ namespace zypp // Match::OTHER indicates need to compile // (merge global search strings into name). - AttrMatchData attrMatchData( attr ); - if ( !explicitKind ) - attrMatchData.strMatcher = StrMatcher( name, Match::OTHER ); - else - { - // ResKind::explicitBuiltin call above asserts the presence of the ':' in name - attrMatchData.strMatcher = StrMatcher( strchr( name.c_str(), ':')+1, Match::OTHER ); - attrMatchData.kindPredicate = explicitKind; - } + AttrMatchData attrMatchData( attr, StrMatcher( name, Match::OTHER ) ); if ( isDependencyAttribute( attr ) ) attrMatchData.addPredicate( EditionRangePredicate( op, edition, arch ) ); @@ -895,11 +911,15 @@ namespace zypp _pimpl->_op = op; } - void PoolQuery::setMatchSubstring() { _pimpl->_flags.setModeSubstring(); _pimpl->_match_word = false; } - void PoolQuery::setMatchExact() { _pimpl->_flags.setModeString(); _pimpl->_match_word = false; } - void PoolQuery::setMatchRegex() { _pimpl->_flags.setModeRegex(); _pimpl->_match_word = false; } - void PoolQuery::setMatchGlob() { _pimpl->_flags.setModeGlob(); _pimpl->_match_word = false; } - void PoolQuery::setMatchWord() { _pimpl->_flags.setModeSubstring(); _pimpl->_match_word = true; } + void PoolQuery::setMatchSubstring() { _pimpl->_flags.setModeSubstring(); } + void PoolQuery::setMatchExact() { _pimpl->_flags.setModeString(); } + void PoolQuery::setMatchRegex() { _pimpl->_flags.setModeRegex(); } + void PoolQuery::setMatchGlob() { _pimpl->_flags.setModeGlob(); } + void PoolQuery::setMatchWord() + { + _pimpl->_match_word = true; + _pimpl->_flags.setModeRegex(); + } Match PoolQuery::flags() const { return _pimpl->_flags; } @@ -915,6 +935,10 @@ namespace zypp { _pimpl->_status_flags = flags; } + void PoolQuery::setRequireAll(bool require_all) + { _pimpl->_require_all = require_all; } + + const PoolQuery::StrContainer & PoolQuery::strings() const { return _pimpl->_strings; } @@ -957,10 +981,15 @@ namespace zypp { _pimpl->_flags.turn( Match::FILES, value ); } bool PoolQuery::matchExact() const { return _pimpl->_flags.isModeString(); } - bool PoolQuery::matchSubstring() const { return _pimpl->_flags.isModeSubstring() && !_pimpl->_match_word; } + bool PoolQuery::matchSubstring() const { return _pimpl->_flags.isModeSubstring(); } bool PoolQuery::matchGlob() const { return _pimpl->_flags.isModeGlob(); } bool PoolQuery::matchRegex() const { return _pimpl->_flags.isModeRegex(); } - bool PoolQuery::matchWord() const { return _pimpl->_flags.isModeSubstring() && _pimpl->_match_word; } + + bool PoolQuery::matchWord() const + { return _pimpl->_match_word; } + + bool PoolQuery::requireAll() const + { return _pimpl->_require_all; } PoolQuery::StatusFilter PoolQuery::statusFilterFlags() const { return _pimpl->_status_flags; } @@ -989,9 +1018,6 @@ namespace zypp { invokeOnEach( begin(), end(), fnc); } - /*DEPRECATED LEGACY:*/void PoolQuery::setRequireAll( bool ) {} - /*DEPRECATED LEGACY:*/bool PoolQuery::requireAll() const { return false; } - /////////////////////////////////////////////////////////////////// // // CLASS NAME : PoolQuery::Attr @@ -1026,7 +1052,7 @@ namespace zypp static const PoolQueryAttr kindAttr; static const PoolQueryAttr stringAttr; static const PoolQueryAttr stringTypeAttr; - static const PoolQueryAttr requireAllAttr; // LEAGACY: attribute was defined but never implemented. + static const PoolQueryAttr requireAllAttr; static const PoolQueryAttr caseSensitiveAttr; static const PoolQueryAttr installStatusAttr; static const PoolQueryAttr editionAttr; @@ -1039,7 +1065,7 @@ namespace zypp const PoolQueryAttr PoolQueryAttr::kindAttr( "type" ); const PoolQueryAttr PoolQueryAttr::stringAttr( "query_string" ); const PoolQueryAttr PoolQueryAttr::stringTypeAttr("match_type"); - const PoolQueryAttr PoolQueryAttr::requireAllAttr("require_all"); // LEAGACY: attribute was defined but never implemented. + const PoolQueryAttr PoolQueryAttr::requireAllAttr("require_all"); const PoolQueryAttr PoolQueryAttr::caseSensitiveAttr("case_sensitive"); const PoolQueryAttr PoolQueryAttr::installStatusAttr("install_status"); const PoolQueryAttr PoolQueryAttr::editionAttr("version"); @@ -1163,8 +1189,18 @@ namespace zypp } else if ( attribute==PoolQueryAttr::requireAllAttr ) { - // LEAGACY: attribute was defined but never implemented. - // Actually it should not occur outside our testcases. + if ( str::strToTrue(attrValue) ) + { + setRequireAll(true); + } + else if ( !str::strToFalse(attrValue) ) + { + setRequireAll(false); + } + else + { + WAR << "unknown boolean value " << attrValue << endl; + } } else if ( attribute==PoolQueryAttr::caseSensitiveAttr ) { @@ -1249,70 +1285,6 @@ namespace zypp } while ( true ); - // OLD STYLE VERSIONED LOCKS: - // solvable_name: kernel - // version: > 1 - // - // NEW STYLE VERSIONED LOCKS: - // complex: AttrMatchData solvable:name kernel C SolvableRange\ >\ 1\ \"\" - // or - // solvable_name: kernel > 1 - // - // Semantically equivalent as locks, but due to the different syntax - // the complex lock is wrongly handled by zypper. - // - // bsc#1112911: Unfortunately all styles are found in real-life locks-files. - // libzypp will try to make sure, when parsing the locks-file, that complex - // locks are rewritten into to OLD STYLE queries zypper can handle. - if ( !_pimpl->_attrs.count(SolvAttr::name) && _pimpl->_uncompiledPredicated.size() == 1 ) - { - // No OLD STYLE lock for SolvAttr::name and exactly one complex lock... - const AttrMatchData & attrmatch { *_pimpl->_uncompiledPredicated.begin() }; - if ( attrmatch.attr == SolvAttr::name && attrmatch.strMatcher.flags().mode() == Match::OTHER ) - { - // ...for SolvAttr::name and following the global search flags. - // A candidate for a rewrite? - - std::vector words; - str::splitEscaped( attrmatch.predicateStr, std::back_inserter(words) ); - if ( words.size() < 4 || words[3].empty() ) - { - // We have _NO_ arch rule in the complex predicate, so we can simplify it. - // - // NOTE: AFAIK it's not possible to create (or have created) a complex lock - // with arch rule with zypper means. Nevertheless, in case such a rule made it - // into a locks file, it's better to have a strange looking 'zypper locks' list - // than to lock the wrong packages. - // (and remember that you can't use "addAttribute( SolvAttr::arch, ... )" because - // attributes are `OR`ed) - - // kind - if ( attrmatch.kindPredicate ) - { - _pimpl->_kinds.clear(); // an explicit kind overwrites any global one - addKind( attrmatch.kindPredicate ); - } - - // name - addAttribute( SolvAttr::name, attrmatch.strMatcher.searchstring() ); - - // edition - std::vector words; - str::splitEscaped( attrmatch.predicateStr, std::back_inserter(words) ); - if ( ! words.empty() ) - { - if ( words[0] == "EditionRange" || words[0] == "SolvableRange" ) - { - setEdition( Edition(words[2]), Rel(words[1]) ); - } - } - - // finally remove the complex lock - _pimpl->_uncompiledPredicated.clear(); - } - } - } - return finded_something; } @@ -1372,6 +1344,19 @@ namespace zypp } } + if( requireAll() != q.requireAll() ) + { + str << "require_all: "; + if (requireAll()) + { + str << "on" << delim; + } + else + { + str << "off" << delim; + } + } + if( statusFilterFlags() != q.statusFilterFlags() ) { switch( statusFilterFlags() ) @@ -1424,9 +1409,6 @@ namespace zypp bool PoolQuery::operator==( const PoolQuery & rhs ) const { return *_pimpl == *rhs._pimpl; } - bool PoolQuery::operator<( const PoolQuery & rhs ) const - { return *_pimpl < *rhs._pimpl; } - /////////////////////////////////////////////////////////////////// namespace detail { ///////////////////////////////////////////////////////////////// @@ -1632,18 +1614,19 @@ namespace zypp } ///////////////////////////////////////////////////////////////////// sat::Solvable inSolvable( base_r.inSolvable() ); + // Kind restriction: + if ( ! _kinds.empty() && ! inSolvable.isKind( _kinds.begin(), _kinds.end() ) ) + { + base_r.nextSkipSolvable(); + return false; + } + // Edition restriction: if ( _op != Rel::ANY && !compareByRel( _op, inSolvable.edition(), _edition, Edition::Match() ) ) { base_r.nextSkipSolvable(); return false; } - - // Kind restriction: - // Delay the decision to nextSkipSolvable and return false, as there may be - // some explicit kind:name predicate which overrules the global kinds. - bool globalKindOk =( _kinds.empty() || inSolvable.isKind( _kinds.begin(), _kinds.end() ) ); - ///////////////////////////////////////////////////////////////////// // string and predicate matching: @@ -1651,38 +1634,17 @@ namespace zypp { // String matching was done by the base iterator. // Now check any predicate: - const AttrMatchData & matchData( _attrMatchList.front() ); - - if ( matchData.kindPredicate ) - { - if ( matchData.kindPredicate != inSolvable.kind() ) - { - base_r.nextSkipSolvable(); // this matchData will never match in this solvable - return false; - } - } - else if ( !globalKindOk ) - return false; // only matching kindPredicate could overwrite this - - if ( !matchData.predicate || matchData.predicate( base_r ) ) + const AttrMatchData::Predicate & predicate( _attrMatchList.front().predicate ); + if ( ! predicate || predicate( base_r ) ) return true; - return false; // no skip as there may be more occurrences in this solvable of this attr. + return false; // no skip as there may be more occurrences od this attr. } // Here: search all attributes ;( for_( mi, _attrMatchList.begin(), _attrMatchList.end() ) { const AttrMatchData & matchData( *mi ); - - if ( matchData.kindPredicate ) - { - if ( matchData.kindPredicate != inSolvable.kind() ) - continue; // this matchData does not apply - } - else if ( !globalKindOk ) - continue; // only matching kindPredicate could overwrite this - sat::LookupAttr q( matchData.attr, inSolvable ); if ( matchData.strMatcher ) // an empty searchstring matches always q.setStrMatcher( matchData.strMatcher );