Imported Upstream version 14.45.0
[platform/upstream/libzypp.git] / zypp / base / StrMatcher.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/base/StrMatcher.cc
10  *
11 */
12 extern "C"
13 {
14 #include <solv/repo.h>
15 }
16
17 #include <iostream>
18 #include <sstream>
19
20 #include "zypp/base/LogTools.h"
21 #include "zypp/base/Gettext.h"
22 #include "zypp/base/String.h"
23
24 #include "zypp/base/StrMatcher.h"
25
26 using std::endl;
27
28 ///////////////////////////////////////////////////////////////////
29 namespace zypp
30 {
31   ///////////////////////////////////////////////////////////////////
32   //    class Match
33   ///////////////////////////////////////////////////////////////////
34
35   const int Match::_modemask = SEARCH_STRINGMASK;
36   const int Match::_flagmask = ~_modemask;
37
38   // option flags
39   const Match Match::NOCASE             (SEARCH_NOCASE);
40
41   // sat::LookupAttr option flags
42   const Match Match::NO_STORAGE_SOLVABLE(SEARCH_NO_STORAGE_SOLVABLE);
43   const Match Match::SUB                (SEARCH_SUB);
44   const Match Match::ARRAYSENTINEL      (SEARCH_ARRAYSENTINEL);
45   const Match Match::DISABLED_REPOS     (SEARCH_DISABLED_REPOS);
46   const Match Match::COMPLETE_FILELIST  (SEARCH_COMPLETE_FILELIST);
47   const Match Match::SKIP_KIND          (SEARCH_SKIP_KIND);
48   const Match Match::FILES              (SEARCH_FILES);
49   const Match Match::CHECKSUMS          (SEARCH_CHECKSUMS);
50
51   Match::Mode Match::mode() const
52   {
53     switch ( modeval() )
54     {
55       case 0:                   return NOTHING;         break;
56       case SEARCH_STRING:       return STRING;          break;
57       case SEARCH_STRINGSTART:  return STRINGSTART;     break;
58       case SEARCH_STRINGEND:    return STRINGEND;       break;
59       case SEARCH_SUBSTRING:    return SUBSTRING;       break;
60       case SEARCH_GLOB:         return GLOB;            break;
61       case SEARCH_REGEX:        return REGEX;           break;
62     }
63     return OTHER;
64   }
65
66   int Match::modeval( Mode mode_r )
67   {
68     switch ( mode_r )
69     {
70       case NOTHING:     return 0;                       break;
71       case STRING:      return SEARCH_STRING;           break;
72       case STRINGSTART: return SEARCH_STRINGSTART;      break;
73       case STRINGEND:   return SEARCH_STRINGEND;        break;
74       case SUBSTRING:   return SEARCH_SUBSTRING;        break;
75       case GLOB:        return SEARCH_GLOB;             break;
76       case REGEX:       return SEARCH_REGEX;            break;
77       case OTHER:       return SEARCH_STRINGMASK;       break;
78     }
79     return SEARCH_STRINGMASK;
80   }
81
82   std::string Match::asString() const
83   { std::ostringstream str; str << *this; return str.str(); }
84
85   std::ostream & operator<<( std::ostream & str, Match::Mode obj )
86   {
87     switch ( obj )
88     {
89 #define OUTS(V) case Match::V: return str << #V; break
90       OUTS( NOTHING );
91       OUTS( STRING );
92       OUTS( STRINGSTART );
93       OUTS( STRINGEND );
94       OUTS( SUBSTRING );
95       OUTS( GLOB );
96       OUTS( REGEX );
97       OUTS( OTHER );
98 #undef OUTS
99     }
100     return str << "Match::Mode::UNKNOWN";
101   }
102
103   std::ostream & operator<<( std::ostream & str, const Match & obj )
104   {
105     if ( ! obj )
106       return str << "NOTHING";
107
108     const char * sep = "|";
109     Match::Mode mode( obj.mode() );
110     switch ( mode )
111     {
112       case Match::NOTHING:
113         sep = 0; // suppress 'NOTHING|'
114         break;
115       case Match::OTHER:
116         str << mode<<"("<<obj.modeval()<<")"; // check whether libsolv has introduced new modes!
117         break;
118       default:
119         str << mode;
120         break;
121     }
122
123     int val = obj.flagval();
124     if ( val )
125     {
126 #define OUTS(V) if ( val & Match::V.get() ) { val &= ~Match::V.get(); if ( sep ) str << sep; else sep = "|"; str << #V; }
127       OUTS( NOCASE );
128       OUTS( NO_STORAGE_SOLVABLE );
129       OUTS( SUB );
130       OUTS( ARRAYSENTINEL );
131       OUTS( DISABLED_REPOS );
132       OUTS( COMPLETE_FILELIST );
133       OUTS( SKIP_KIND );
134       OUTS( FILES );
135       OUTS( CHECKSUMS );
136 #undef OUTS
137       if ( val )
138       {
139         if ( sep ) str << sep;
140         str << zypp::str::hexstring( val ); // check whether libsolv has introduced new flags.
141       }
142     }
143     return str;
144   }
145
146   ///////////////////////////////////////////////////////////////////
147   //    class MatchException
148   ///////////////////////////////////////////////////////////////////
149
150   MatchUnknownModeException::MatchUnknownModeException( const Match & mode_r, const std::string & msg_r )
151   : MatchException( msg_r.empty() ? str::form(_("Unknown match mode '%s'"), mode_r.asString().c_str() )
152                                   : str::form(_("Unknown match mode '%s' for pattern '%s'"), mode_r.asString().c_str(), msg_r.c_str() ) )
153   {}
154
155   MatchInvalidRegexException::MatchInvalidRegexException( const std::string & regex_r, int regcomp_r )
156   : MatchException( regcomp_r ? str::form(_("Invalid regular expression '%s': regcomp returned %d"), regex_r.c_str(), regcomp_r )
157                               : str::form(_("Invalid regular expression '%s'"), regex_r.c_str() ) )
158   {}
159
160   ///////////////////////////////////////////////////////////////////
161   /// \class StrMatcher::Impl
162   /// \brief StrMatcher implementation.
163   ///
164   /// \note Take care to release any allocated regex by calling
165   /// \c ::datamatcher_free.
166   ///////////////////////////////////////////////////////////////////
167   struct StrMatcher::Impl
168   {
169     Impl()
170     {}
171
172     Impl( const std::string & search_r, const Match & flags_r )
173     : _search( search_r )
174     , _flags( flags_r )
175     {}
176
177     ~Impl()
178     { invalidate(); }
179
180     /** Compile the pattern. */
181     void compile() const
182     {
183       if ( !_matcher )
184       {
185         if ( _flags.mode() == Match::OTHER )
186           ZYPP_THROW( MatchUnknownModeException( _flags, _search ) );
187
188         _matcher.reset( new ::_Datamatcher );
189         int res = ::datamatcher_init( _matcher.get(), _search.c_str(), _flags.get() );
190         if ( res )
191         {
192           _matcher.reset();
193           ZYPP_THROW( MatchInvalidRegexException( _search, res ) );
194         }
195       }
196     }
197
198     /** Whether the pattern is already compiled. */
199     bool isCompiled() const
200     { return _matcher != nullptr; }
201
202     /** Return whether string matches. */
203     bool doMatch( const char * string_r ) const
204     {
205       compile(); // nop if already compiled.
206
207       if ( ! string_r )
208         return false; // NULL never matches
209         return ::datamatcher_match( _matcher.get(), string_r );
210     }
211
212     /** The current searchstring. */
213     const std::string & searchstring() const
214     { return _search; }
215
216     /** Set a new searchstring. */
217     void setSearchstring( const std::string & string_r )
218     { invalidate(); _search = string_r; }
219
220     /** The current search flags. */
221     const Match & flags() const
222     { return _flags; }
223
224     /** Set new search flags. */
225     void setFlags( const Match & flags_r )
226     { invalidate(); _flags = flags_r; }
227
228   private:
229     /** Has to be called if _search or _flags change. */
230     void invalidate()
231     {
232       if ( _matcher )
233         ::datamatcher_free( _matcher.get() );
234       _matcher.reset();
235     }
236
237   private:
238     std::string _search;
239     Match       _flags;
240     mutable scoped_ptr< ::_Datamatcher> _matcher;
241
242   private:
243     friend Impl * rwcowClone<Impl>( const Impl * rhs );
244     /** clone for RWCOW_pointer */
245     Impl * clone() const
246     { return new Impl( _search, _flags ); }
247   };
248
249   /** \relates StrMatcher::Impl Stream output */
250   inline std::ostream & operator<<( std::ostream & str, const StrMatcher::Impl & obj )
251   {
252     return str << "\"" << obj.searchstring() << "\"{" << obj.flags() << "}";
253   }
254
255   ///////////////////////////////////////////////////////////////////
256   //    class StrMatcher
257   ///////////////////////////////////////////////////////////////////
258
259   StrMatcher::StrMatcher()
260   : _pimpl( new Impl )
261   {}
262
263   StrMatcher::StrMatcher( const std::string & search_r )
264   : _pimpl( new Impl( search_r, Match::STRING ) )
265   {}
266
267   StrMatcher::StrMatcher( const std::string & search_r, const Match & flags_r )
268   : _pimpl( new Impl( search_r, flags_r ) )
269   {}
270
271   StrMatcher::StrMatcher( const std::string & search_r, const Match::Mode & flags_r )
272   : _pimpl( new Impl( search_r, flags_r ) )
273   {}
274
275   StrMatcher::StrMatcher( const std::string & search_r, int flags_r )
276   : _pimpl( new Impl( search_r, Match(flags_r) ) )
277   {}
278
279   void StrMatcher::compile() const
280   { return _pimpl->compile(); }
281
282   bool StrMatcher::isCompiled() const
283   { return _pimpl->isCompiled(); }
284
285   bool StrMatcher::doMatch( const char * string_r ) const
286   { return _pimpl->doMatch( string_r ); }
287
288   const std::string & StrMatcher::searchstring() const
289   { return _pimpl->searchstring(); }
290
291   void StrMatcher::setSearchstring( const std::string & string_r )
292   { _pimpl->setSearchstring( string_r ); }
293
294   void StrMatcher::setSearchstring( const std::string & string_r, const Match & flags_r )
295   {
296     _pimpl->setSearchstring( string_r );
297     _pimpl->setFlags( flags_r );
298   }
299
300   const Match & StrMatcher::flags() const
301   { return _pimpl->flags(); }
302
303   void StrMatcher::setFlags( const Match & flags_r )
304   { _pimpl->setFlags( flags_r ); }
305
306   std::ostream & operator<<( std::ostream & str, const StrMatcher & obj )
307   { return str << *obj._pimpl; }
308
309   bool operator==( const StrMatcher & lhs, const StrMatcher & rhs )
310   {
311     return ( lhs.flags() == rhs.flags()
312           && lhs.searchstring() == rhs.searchstring() );
313   }
314
315   bool operator<( const StrMatcher & lhs, const StrMatcher & rhs )
316   {
317     if ( lhs.flags().get() != rhs.flags().get() )
318       return ( lhs.flags().get() < rhs.flags().get() );
319
320     return ( lhs.searchstring() < rhs.searchstring() );
321   }
322
323 } // namespace zypp
324 ///////////////////////////////////////////////////////////////////