Imported Upstream version 14.46.0
[platform/upstream/libzypp.git] / zypp / PoolQuery.cc
index 4e286b2..94489ff 100644 (file)
@@ -357,7 +357,6 @@ namespace zypp
     Impl()
       : _flags( Match::SUBSTRING | Match::NOCASE | Match::SKIP_KIND )
       , _match_word(false)
-      , _require_all(false)
       , _status_flags(ALL)
     {}
 
@@ -380,7 +379,6 @@ namespace zypp
     /** Sat solver search flags */
     Match _flags;
     bool _match_word;
-    bool _require_all;
 
     /** Sat solver status flags */
     StatusFilter _status_flags;
@@ -417,7 +415,6 @@ 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
@@ -441,8 +438,10 @@ namespace zypp
     mutable AttrMatchList _attrMatchList;
 
   private:
-    /** Pass flags from \ref compile, as they may have been changed. */
-    string createRegex( const StrContainer & container, const Match & flags ) const;
+    /** 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;
 
   private:
     friend Impl * rwcowClone<Impl>( const Impl * rhs );
@@ -479,13 +478,8 @@ namespace zypp
   {
     _attrMatchList.clear();
 
-    Match cflags( _flags );
-    if ( cflags.mode() == Match::OTHER ) // this will never succeed...
-      ZYPP_THROW( MatchUnknownModeException( cflags ) );
-
-    /** Compiled search strings. */
-    string rcstrings;
-
+    if ( _flags.mode() == Match::OTHER ) // this will never succeed...
+      ZYPP_THROW( MatchUnknownModeException( _flags ) );
 
     // 'different'         - will have to iterate through all and match by ourselves (slow)
     // 'same'              - will pass the compiled string to dataiterator_init
@@ -510,11 +504,8 @@ namespace zypp
       StrContainer joined;
       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();
-      _attrMatchList.push_back( AttrMatchData( _attrs.begin()->first,
-                                StrMatcher( rcstrings, cflags ) ) );
+
+      _attrMatchList.push_back( AttrMatchData( _attrs.begin()->first, joinedStrMatcher( joined, _flags ) ) );
     }
 
     // // MULTIPLE ATTRIBUTES
@@ -522,16 +513,21 @@ namespace zypp
     {
       // check whether there are any per-attribute strings
       bool attrvals_empty = true;
-      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:
+      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;
+      }
 
       // chceck whether the per-attribute strings are all the same
       bool attrvals_thesame = true;
@@ -562,18 +558,15 @@ attremptycheckend:
         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( rcstrings, cflags );
+        StrMatcher matcher( joinedStrMatcher( joined, _flags ) );
         for_( ai, _attrs.begin(), _attrs.end() )
         {
           _attrMatchList.push_back( AttrMatchData( ai->first, matcher ) );
@@ -591,11 +584,8 @@ attremptycheckend:
           StrContainer joined;
           invokeOnEach(_strings.begin(), _strings.end(), EmptyFilter(), MyInserter(joined));
           invokeOnEach(ai->second.begin(), ai->second.end(), EmptyFilter(), MyInserter(joined));
-          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 ) ) );
+
+          _attrMatchList.push_back( AttrMatchData( ai->first, joinedStrMatcher( joined, _flags ) ) );
         }
       }
     }
@@ -615,14 +605,10 @@ attremptycheckend:
           if ( ! mstr.empty() )
             joined.insert( mstr );
 
-          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 ) );
+         // copy and exchange the StrMatcher
+         AttrMatchData nattr( *it );
+         nattr.strMatcher = joinedStrMatcher( joined, _flags );
+          _attrMatchList.push_back( std::move(nattr) );
         }
         else
         {
@@ -635,12 +621,7 @@ attremptycheckend:
     // If no attributes defined at all, then add 'query all'
     if ( _attrMatchList.empty() )
     {
-      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 ) ) );
+      _attrMatchList.push_back( AttrMatchData( sat::SolvAttr::allAttr, joinedStrMatcher( _strings, _flags ) ) );
     }
 
     // Finally check here, whether all involved regex compile.
@@ -651,102 +632,62 @@ attremptycheckend:
     //DBG << asString() << endl;
   }
 
-
-  /**
-   * Converts '*' and '?' wildcards within str into their regex equivalents.
-   */
-  static string wildcards2regex(const string & str)
-  {
-    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
+  ///////////////////////////////////////////////////////////////////
+  namespace
   {
-//! 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)
+    /** 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 )
     {
-      return WB + *container.begin() + WB;
-    }
-
-    // multiple strings
+      if ( str_r.empty() || flags_r.isModeRegex() )
+       return str_r;
 
-    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;
-
-    if (_require_all)
-    {
-      if ( ! flags.isModeString() ) // not match exact
-        tmp += ".*" + WB + tmp;
-      rstr = "(?=" + tmp + ")";
+      return str::rxEscapeStr( std::move(str_r) );
     }
-    else
-    {
-      if ( flags.isModeString() || flags.isModeGlob() )
-        rstr = "^";
-      rstr += WB + "(" + tmp;
-    }
-
-    ++it;
+  } // namespace
+  ///////////////////////////////////////////////////////////////////
 
-    for (; it != container.end(); ++it)
+  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 )
     {
-      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 << sep << rxEscape( s, flags_r );
+      if ( sep == '(' )
+       sep = '|';
     }
+    ret << ')';
 
-    if (_require_all)
-    {
-      if ( ! flags.isModeString() ) // not match exact
-        rstr += WB + ".*";
-    }
-    else
-    {
-      rstr += ")" + WB;
-      if ( flags.isModeString() || flags.isModeGlob() )
-        rstr += "$";
-    }
+    if ( flags_r.isModeString() || flags_r.isModeGlob() )
+      ret << "$";
+    else if ( _match_word )
+      ret << "\\b";
 
-    return rstr;
-#undef WB
+    return StrMatcher( ret, retflags );
   }
 
   string PoolQuery::Impl::asString() const
@@ -911,15 +852,11 @@ attremptycheckend:
     _pimpl->_op = op;
   }
 
-  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();
-  }
+  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; }
 
   Match PoolQuery::flags() const
   { return _pimpl->_flags; }
@@ -935,10 +872,6 @@ attremptycheckend:
   { _pimpl->_status_flags = flags; }
 
 
-  void PoolQuery::setRequireAll(bool require_all)
-  { _pimpl->_require_all = require_all; }
-
-
   const PoolQuery::StrContainer &
   PoolQuery::strings() const
   { return _pimpl->_strings; }
@@ -981,15 +914,10 @@ attremptycheckend:
   { _pimpl->_flags.turn( Match::FILES, value ); }
 
   bool PoolQuery::matchExact() const           { return _pimpl->_flags.isModeString(); }
-  bool PoolQuery::matchSubstring() const       { return _pimpl->_flags.isModeSubstring(); }
+  bool PoolQuery::matchSubstring() const       { return _pimpl->_flags.isModeSubstring() && !_pimpl->_match_word; }
   bool PoolQuery::matchGlob() const            { return _pimpl->_flags.isModeGlob(); }
   bool PoolQuery::matchRegex() const           { return _pimpl->_flags.isModeRegex(); }
-
-  bool PoolQuery::matchWord() const
-  { return _pimpl->_match_word; }
-
-  bool PoolQuery::requireAll() const
-  { return _pimpl->_require_all; }
+  bool PoolQuery::matchWord() const            { return _pimpl->_flags.isModeSubstring() && _pimpl->_match_word; }
 
   PoolQuery::StatusFilter PoolQuery::statusFilterFlags() const
   { return _pimpl->_status_flags; }
@@ -1018,6 +946,9 @@ attremptycheckend:
   { invokeOnEach( begin(), end(), fnc); }
 
 
+  /*DEPRECATED LEGACY:*/void PoolQuery::setRequireAll( bool ) {}
+  /*DEPRECATED LEGACY:*/bool PoolQuery::requireAll() const    { return false; }
+
   ///////////////////////////////////////////////////////////////////
   //
   //  CLASS NAME : PoolQuery::Attr
@@ -1052,7 +983,7 @@ attremptycheckend:
     static const PoolQueryAttr kindAttr;
     static const PoolQueryAttr stringAttr;
     static const PoolQueryAttr stringTypeAttr;
-    static const PoolQueryAttr requireAllAttr;
+    static const PoolQueryAttr requireAllAttr; // LEAGACY: attribute was defined but never implemented.
     static const PoolQueryAttr caseSensitiveAttr;
     static const PoolQueryAttr installStatusAttr;
     static const PoolQueryAttr editionAttr;
@@ -1065,7 +996,7 @@ attremptycheckend:
   const PoolQueryAttr PoolQueryAttr::kindAttr( "type" );
   const PoolQueryAttr PoolQueryAttr::stringAttr( "query_string" );
   const PoolQueryAttr PoolQueryAttr::stringTypeAttr("match_type");
-  const PoolQueryAttr PoolQueryAttr::requireAllAttr("require_all");
+  const PoolQueryAttr PoolQueryAttr::requireAllAttr("require_all");    // LEAGACY: attribute was defined but never implemented.
   const PoolQueryAttr PoolQueryAttr::caseSensitiveAttr("case_sensitive");
   const PoolQueryAttr PoolQueryAttr::installStatusAttr("install_status");
   const PoolQueryAttr PoolQueryAttr::editionAttr("version");
@@ -1189,18 +1120,8 @@ attremptycheckend:
       }
       else if ( attribute==PoolQueryAttr::requireAllAttr )
       {
-        if ( str::strToTrue(attrValue) )
-        {
-          setRequireAll(true);
-        }
-        else if ( !str::strToFalse(attrValue) )
-        {
-          setRequireAll(false);
-        }
-        else
-        {
-          WAR << "unknown boolean value " << attrValue << endl;
-        }
+       // LEAGACY: attribute was defined but never implemented.
+       // Actually it should not occur outside our testcases.
       }
       else if ( attribute==PoolQueryAttr::caseSensitiveAttr )
       {
@@ -1344,19 +1265,6 @@ attremptycheckend:
       }
     }
 
-    if( requireAll() != q.requireAll() )
-    {
-      str << "require_all: ";
-      if (requireAll())
-      {
-        str << "on" << delim;
-      }
-      else
-      {
-        str << "off" << delim;
-      }
-    }
-
     if( statusFilterFlags() != q.statusFilterFlags() )
     {
       switch( statusFilterFlags() )