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