6b4114a38877ed4d1dbc70e1681fade18531037a
[platform/upstream/libzypp.git] / zypp / base / StrMatcher.h
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/base/StrMatcher.h
10  *
11 */
12 #ifndef ZYPP_BASE_STRMATCHER_H
13 #define ZYPP_BASE_STRMATCHER_H
14
15 #include <iosfwd>
16 #include <string>
17
18 #include "zypp/base/PtrTypes.h"
19 #include "zypp/base/Exception.h"
20
21 ///////////////////////////////////////////////////////////////////
22 namespace zypp
23 {
24   ///////////////////////////////////////////////////////////////////
25   /// \class Match
26   /// \brief String matching option flags as used e.g. by \ref StrMatcher.
27   ///
28   /// \code
29   /// Match mode( Match::GLOB | Match::NOCASE );
30   /// \endcode
31   ///////////////////////////////////////////////////////////////////
32   class Match
33   {
34   private:
35     static const int _modemask;
36     static const int _flagmask;
37
38   public:
39     /** Mode flags (mutual exclusive). */
40     enum Mode
41     {
42       NOTHING,          //!< Match nothing
43       STRING,           //!< Excat matching
44       STRINGSTART,      //!< Match at string start
45       STRINGEND,        //!< Match at string end
46       SUBSTRING,        //!< Match substring
47       GLOB,             //!< Glob
48       REGEX,            //!< Regular Expression
49       OTHER             //!< Something else.
50     };
51
52     /** \name \ref Option flags
53      * Most flags are actually \ref sat::LookupAttr specific, as they tell
54      * how to retrieve the attribute values from solv-files. The plain
55      * \ref StrMatcher will ignore those flags and use the ones related
56      * to string matching only.
57      */
58     //@{
59       static const Match NOCASE;                //!< If set, match case insensitive.
60     //@}
61
62     /** \name \ref sat::LookupAttr option flags
63      * These flags are actually \ref sat::LookupAttr specific, as they tell
64      * how to retrieve the attribute values from solv-files. The plain
65      * \ref StrMatcher will ignore these flags and use the ones related
66      * to string matching only.
67      */
68     //@{
69       static const Match NO_STORAGE_SOLVABLE;   //!< LookupAttr: internal
70       static const Match SUB;                   //!< LookupAttr: internal
71       static const Match ARRAYSENTINEL;         //!< LookupAttr: internal
72       static const Match DISABLED_REPOS;        //!< LookupAttr: internal
73       static const Match COMPLETE_FILELIST;     //!< LookupAttr: internal
74       static const Match SKIP_KIND;             //!< LookupAttr: skip any \c kind: prefix when looking at a \ref Solvable name.
75       static const Match FILES;                 //!< LookupAttr: match full path when matching in filelists, otherwise just the basenames.
76       static const Match CHECKSUMS;             //!< LookupAttr: also look for matches in checksums
77     //@}
78
79   public:
80     /** Default ctor \c 0 or \ref NOTHING. */
81     Match()
82     : _val( 0 )
83     {}
84
85     /** Ctor from \ref Mode value. */
86     Match( Mode val_r )
87     : _val( modeval( val_r ) )
88     {}
89
90     /** Just in case one needs it. */
91     explicit Match( int val_r )
92     : _val( val_r )
93     {}
94
95     /** Evaluate in a boolean context <tt>( != 0 )</tt>. */
96     explicit operator bool() const
97     { return _val; }
98
99   public:
100     /** Test whether \c all of the \a rhs bits are set (same mode if \a rhs has one). */
101     bool test( const Match & rhs ) const
102     { return ( ( flagval() & rhs.flagval() ) == rhs.flagval() ) && ( !rhs.modeval() || rhs.modeval() == modeval() ); }
103
104     /** Whether at least one of the \a rhs bits is set (or the same mode). */
105     bool testAnyOf( const Match & rhs ) const
106     { return ( flagval() & rhs.flagval() ) || ( rhs.modeval() && rhs.modeval() == modeval() ); }
107
108     /** Set all of the \a rhs bits (setting a new mode if \a rhs has one). */
109     void set( const Match & rhs )
110     {
111       if ( rhs.modeval() )
112         _val = rhs._val | flagval(); // also set the rhs mode
113         else
114           _val |= rhs._val; // just set the flags
115     }
116
117     /** Unset all of the \a rhs bits (unsets mode if the same as \a rhs). */
118     void unset( const Match & rhs )
119     {
120       if ( modeval() == rhs.modeval() )
121         _val = flagval() & ~rhs.flagval(); // also unset mode
122         else
123           _val &= ~rhs.flagval(); // just unset falgs
124     }
125
126     /** Depending on the value of \a onoff, set or unset flags. */
127     void turn( const Match & rhs, bool onoff )
128     { onoff ? set( rhs ) : unset( rhs ); }
129
130     /** Add flags. */
131     Match & operator|=( const Match & rhs )
132     { set( rhs ); return *this; }
133
134     /** Remove flags.*/
135     Match & operator-=( const Match & rhs )
136     { unset( rhs ); return *this; }
137
138   public:
139     /** Return the \c mode part. */
140     Mode mode() const;
141
142     /** Return the \c flags part. */
143     Match flags() const
144     { return Match( flagval() ); }
145
146   public:
147     /** \name Low level integer representation. */
148     //@{
149       /** Return the integer representation. */
150       int get() const           { return _val; }
151       /** Return the modes integer representation. */
152       int modeval() const       { return _val & _modemask; }
153       /** Return the flags integer representation. */
154       int flagval() const       { return _val & _flagmask; }
155       //@}
156
157   public:
158     /** \name Mode flag manip/query convenience. */
159     //@{
160       /** Whether this has mode \a rhs */
161       bool isMode( Mode rhs ) const
162       { return modeval() == modeval( rhs ); }
163       /** Whether this has mode \ref STRING. */
164       bool isModeString() const
165       { return isMode( STRING ); }
166       /** Whether this has mode \ref STRINGSTART. */
167       bool isModeStringstart() const
168       { return isMode( STRINGSTART ); }
169       /** Whether this has mode \ref STRINGEND. */
170       bool isModeStringend() const
171       { return isMode( STRINGEND ); }
172       /** Whether this has mode \ref SUBSTRING. */
173       bool isModeSubstring() const
174       { return isMode( SUBSTRING ); }
175       /** Whether this has mode \ref GLOB. */
176       bool isModeGlob() const
177       { return isMode( GLOB ); }
178       /** Whether this has mode \ref REGEX. */
179       bool isModeRegex() const
180       { return isMode( REGEX ); }
181
182       /** Set the mode part to \a rhs . */
183       void setMode( Mode rhs )
184       { _val = modeval( rhs ) | flagval(); }
185       /** Set the mode \ref STRING. */
186       void setModeString()
187       { setMode( STRING ); }
188       /** Set the mode \ref STRINGSTART. */
189       void setModeStringstart()
190       { setMode( STRINGSTART ); }
191       /** Set the mode \ref STRINGEND. */
192       void setModeStringend()
193       { setMode( STRINGEND ); }
194       /** Set the mode \ref SUBSTRING. */
195       void setModeSubstring()
196       { setMode( SUBSTRING ); }
197       /** Set the mode \ref GLOB. */
198       void setModeGlob()
199       { setMode( GLOB ); }
200       /** Set the mode \ref REGEX. */
201       void setModeRegex()
202       { setMode( REGEX ); }
203       //@}
204
205       /** String representation. */
206       std::string asString() const;
207
208   private:
209     /** Numeric value for enum (short for <tt>Match(m).get()</tt>). */
210     static int modeval( Mode mode_r );
211
212   private:
213     int _val;
214   };
215
216   /** \relates Match */
217   inline bool operator==( const Match & lhs, const Match & rhs )
218   { return lhs.get() == rhs.get(); }
219   /** \relates Match */
220   inline bool operator!=( const Match & lhs, const Match & rhs )
221   { return lhs.get() != rhs.get(); }
222
223   /** \relates Match */
224   inline Match operator|( const Match & lhs, const Match & rhs )
225   { return Match(lhs) |= rhs; }
226   /** \relates Match \overload to disambiguate 'int|int'. */
227   inline Match operator|( Match::Mode lhs, Match::Mode rhs )
228   { return Match(lhs) |= rhs; }
229
230   /** \relates Match */
231   inline Match operator-( const Match & lhs, const Match & rhs )
232   { return Match(lhs) -= rhs; }
233   /** \relates Match \overload to disambiguate 'int-int'. */
234   inline Match operator-( Match::Mode lhs, Match::Mode rhs )
235   { return Match(lhs) -= rhs; }
236
237   /** \relates Match::Mode Stream output */
238   std::ostream & operator<<( std::ostream & str, Match::Mode obj );
239
240   /** \relates Match Stream output */
241   std::ostream & operator<<( std::ostream & str, const Match & obj );
242
243   ///////////////////////////////////////////////////////////////////
244   /// \class MatchException
245   /// \brief Exceptions thrown from attribute matching.
246   ///////////////////////////////////////////////////////////////////
247   struct MatchException : public Exception
248   {
249     /** Supplied message. */
250     explicit MatchException( const std::string & msg_r ) : Exception( msg_r ) {}
251   };
252
253   ///////////////////////////////////////////////////////////////////
254   /// \class MatchUnknownModeException
255   /// \brief Unknown match mode.
256   ///////////////////////////////////////////////////////////////////
257   struct MatchUnknownModeException : public MatchException
258   {
259     /** Supplied message. */
260     explicit MatchUnknownModeException( const std::string & msg_r ) : MatchException( msg_r ) {}
261
262     /** Build message including the \a mode and optional the pattern string. */
263     MatchUnknownModeException( const Match & mode_r, const std::string & msg_r = std::string() );
264   };
265
266   ///////////////////////////////////////////////////////////////////
267   /// \class MatchInvalidRegexException
268   /// \brief Invalid regular expression (failed ::regcomp).
269   ///////////////////////////////////////////////////////////////////
270   struct MatchInvalidRegexException : public MatchException
271   {
272     /** Supplied message. */
273     explicit MatchInvalidRegexException( const std::string & msg_r ) : MatchException( msg_r ) {}
274
275     /** Build message including the \a regex and \c ::regcomp returncode (use \c 0 if unknown). */
276     MatchInvalidRegexException( const std::string & regex_r, int regcomp_r );
277   };
278
279   ///////////////////////////////////////////////////////////////////
280   /// \class StrMatcher
281   /// \brief String matching (STRING|SUBSTRING|GLOB|REGEX).
282   ///
283   /// Used by e.g. \ref PoolQuery and \ref LookupAttr for queries,
284   /// but it can also be used for matching arbitrary strings.
285   ///
286   /// \code
287   ///  StrMatcher matches( "foo", Match::SUBSTRING );
288   ///  for_( it, stringlist.begin(), stringlist().end() )
289   ///  {
290   ///    if ( matches( *it ) )
291   ///      cout << *it << " has substring 'foo'" << endl;
292   ///  }
293   /// \endcode
294   ///
295   /// \Note Those flags are always set: <tt>REG_EXTENDED | REG_NOSUB | REG_NEWLINE</tt>
296   ///////////////////////////////////////////////////////////////////
297   class StrMatcher
298   {
299     friend std::ostream & operator<<( std::ostream & str, const StrMatcher & obj );
300
301   public:
302     typedef MatchException Exception;
303
304   public:
305     /** Implementation  */
306     class Impl;
307
308   public:
309     /** Default ctor matches nothing. */
310     StrMatcher();
311
312     /** Ctor from string matches in \ref Match::STRING mode per default. */
313     StrMatcher( const std::string & search_r );
314
315     /** Ctor taking string and \ref Match flags. */
316     StrMatcher( const std::string & search_r, const Match & flags_r );
317
318     /** Ctor taking string and \ref Match::Mode.
319      * Needed because we want them to be treated as \ref Match,
320      * and not as \ref int as the compiler woud do.
321      */
322     StrMatcher( const std::string & search_r, const Match::Mode & flags_r );
323
324     /** Low level interface wraps \a flags into \ref Match. */
325     StrMatcher( const std::string & search_r, int flags_r );
326
327     /** Evaluate in a boolean context <tt>( ! searchstring().empty() )</tt>. */
328     explicit operator bool() const
329     { return !searchstring().empty(); }
330
331   public:
332     /** Return whether string matches.
333      * You can use it with any class that impements \c c_str.
334      * (\c std::string, \ref Pathname, \ref IdString, ...).
335      * \Note \c NULL never matches.
336      */
337     template<class _Tp>
338     bool operator()( const _Tp & string_r ) const
339     { return doMatch( string_r.c_str() ); }
340     /** \overload */
341     bool operator()( const char * string_r ) const
342     { return doMatch( string_r ); }
343
344   public:
345     /** The current searchstring. */
346     const std::string & searchstring() const;
347
348     /** Set a new searchstring. */
349     void setSearchstring( const std::string & string_r );
350
351     /** Set a new searchstring and flags. */
352     void setSearchstring( const std::string & string_r, const Match & flags_r );
353
354     /** The current search flags. */
355     const Match & flags() const;
356
357     /** Set new search flags. */
358     void setFlags( const Match & flags_r );
359
360   public:
361     /** Compile the pattern e.g. in case of \c REGEX.
362      * \throws MatchUnknownModeException If the \ref Match flag more than
363      *         one mode bit set.
364      * \throws MatchInvalidRegexException If \ref Match::REGEX is set
365      *         and \ref searchstring is not a valid regular expression.
366      */
367     void compile() const;
368
369     /** Whether the \ref StrMatcher is already compiled. */
370     bool isCompiled() const;
371
372     /** Return whether string matches.
373      * Compiles the \ref StrMatcher if this was not yet done.
374      * \throws MatchException Any of the exceptions thrown by \ref StrMatcher::compile.
375      */
376     bool doMatch( const char * string_r ) const;
377
378   private:
379     /** Pointer to implementation */
380     RWCOW_pointer<Impl> _pimpl;
381   };
382
383   /** \relates StrMatcher Stream output */
384   std::ostream & operator<<( std::ostream & str, const StrMatcher & obj );
385
386   /** \relates StrMatcher */
387   bool operator==( const StrMatcher & lhs, const StrMatcher & rhs );
388
389   /** \relates StrMatcher */
390   inline bool operator!=( const StrMatcher & lhs, const StrMatcher & rhs )
391   { return !( lhs == rhs ); }
392
393   /** \relates StrMatcher Arbitrary order for std::container. */
394   bool operator<( const StrMatcher & lhs, const StrMatcher & rhs );
395
396 } // namespace zypp
397 ///////////////////////////////////////////////////////////////////
398 #endif // ZYPP_BASE_STRMATCHER_H