Enhance Glob and add tests
[platform/upstream/libzypp.git] / zypp / Glob.h
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/Glob.h
10  *
11 */
12 #ifndef ZYPP_GLOB_H
13 #define ZYPP_GLOB_H
14
15 extern "C"
16 {
17 #include <glob.h>
18 }
19
20 #include <iosfwd>
21
22 #include "zypp/base/Easy.h"
23 #include "zypp/base/Flags.h"
24 #include "zypp/base/Iterator.h"
25 #include "zypp/base/NonCopyable.h"
26 #include "zypp/base/DefaultIntegral.h"
27
28 #include "zypp/Pathname.h"
29
30 ///////////////////////////////////////////////////////////////////
31 namespace zypp
32 { /////////////////////////////////////////////////////////////////
33
34   ///////////////////////////////////////////////////////////////////
35   namespace filesystem
36   { /////////////////////////////////////////////////////////////////
37
38     ///////////////////////////////////////////////////////////////////
39     //
40     //  CLASS NAME : Glob
41     //
42     /** Find pathnames matching a pattern.
43      * \code
44      * Glob glob( Glob::_BRACE );
45      * glob.add( "/somewherre/solverTestcase/ *{.xml,.xml.gz}" );
46      * \endcode
47      * \code
48      * std::list<Pathname> plist;
49      * Glob::collect( "/somewherre/solverTestcase/ *{.xml,.xml.gz}", Glob::_BRACE,
50      *                std::back_inserter( plist ) );
51      * \endcode
52      * \see Manual page glob(3)
53      */
54     class Glob : private base::NonCopyable
55     {
56       public:
57         typedef size_t size_type;
58         typedef const char * value_type;
59
60         /** Iterate NULL terminated \c char* array. */
61         class const_iterator : public boost::iterator_adaptor<
62               const_iterator                // Derived
63             , char **                       // Base
64             , value_type                    // Value
65             , boost::forward_traversal_tag  // CategoryOrTraversal
66             , const value_type              // Reference
67             >
68         {
69           public:
70             const_iterator()
71             : const_iterator::iterator_adaptor_( 0 )
72             {}
73
74             explicit const_iterator( char ** _idx )
75             : const_iterator::iterator_adaptor_( _idx && *_idx ? _idx : 0 )
76             {}
77
78           private:
79             friend class boost::iterator_core_access;
80             void increment()
81             {
82               if ( base_reference() && !*(++base_reference()) )
83                 base_reference() = 0;
84             }
85             reference dereference() const
86             { return( base() ? *base() : 0 ); }
87         };
88         ///////////////////////////////////////////////////////////////////
89
90       public:
91         /** Individual bits to combine in \ref Flags. */
92         enum Bits {
93           _ERR          = GLOB_ERR,             //!< Return on read errors.
94           _MARK         = GLOB_MARK,            //!< Append a slash to each name.
95           _NOSORT       = GLOB_NOSORT,          //!< Don't sort the names.
96           // unsupported _DOOFFS = GLOB_DOOFFS, //!< Insert PGLOB->gl_offs NULLs.
97           _NOCHECK      = GLOB_NOCHECK,         //!< If nothing matches, return the pattern.
98           // autoapplied _APPEND = GLOB_APPEND, //!< Append to results of a previous call.
99           _NOESCAPE     = GLOB_NOESCAPE,        //!< Backslashes don't quote metacharacters.
100           _PERIOD       = GLOB_PERIOD,          //!< Leading `.' can be matched by metachars.
101           // unsupported _MAGCHAR = GLOB_MAGCHAR,//!< Set in gl_flags if any metachars seen.
102           _ALTDIRFUNC   = GLOB_ALTDIRFUNC,      //!< Use gl_opendir et al functions.
103           _BRACE        = GLOB_BRACE,           //!< Expand "{a,b}" to "a" "b".
104           _NOMAGIC      = GLOB_NOMAGIC,         //!< If no magic chars, return the pattern.
105           _TILDE        = GLOB_TILDE,           //!< Expand ~user and ~ to home directories.
106           _ONLYDIR      = GLOB_ONLYDIR,         //!< Match only directories.
107           _TILDE_CHECK  = GLOB_TILDE_CHECK,     //!< Like GLOB_TILDE but return an error if the user name is not available.
108         };
109
110         /** type Flags: Type-safe OR-combination of \ref Bits. */
111         ZYPP_DECLARE_FLAGS( Flags, Bits );
112
113       public:
114         /** Default ctor optionally taking the default flags.
115          * The flags passed here are the default for \ref add.
116          * \see \ref setDefaultFlags
117         */
118         Glob( Flags flags_r = Flags() )
119         : _defaultFlags( flags_r )
120         {}
121
122         /** Ctor adding pathnames matching \a pattern_r.
123          * The flags passed here are the default for \ref add.
124          * \see \ref setDefaultFlags
125         */
126         explicit Glob( const Pathname & pattern_r, Flags flags_r = Flags() )
127         : _defaultFlags( flags_r )
128         { add( pattern_r, flags_r ); }
129         /** \overload */
130         explicit Glob( const std::string & pattern_r, Flags flags_r = Flags() )
131         : _defaultFlags( flags_r )
132         { add( pattern_r, flags_r ); }
133         /** \overload */
134         explicit Glob( const char * pattern_r, Flags flags_r = Flags() )
135         : _defaultFlags( flags_r )
136         { add( pattern_r, flags_r ); }
137
138         /** Dtor */
139         ~Glob()
140         { if ( _result ) ::globfree( &(*_result) ); }
141
142         /** Add pathnames matching \a pattern_r to the current result.
143          *
144          * Any flags passed here override the global default passed to
145          * the ctor. GLOB_APPEND is atomatically added to the flags
146          * f needed.
147          *
148          * This invalidates all iterators.
149          * \see \ref setDefaultFlags
150          * \return the value returned by ::glob().
151          */
152         int add( const Pathname & pattern_r, Flags flags_r = Flags() )
153         { return add( pattern_r.c_str(), flags_r ); }
154         /** \overload */
155         int add( const std::string & pattern_r, Flags flags_r = Flags() )
156         { return add( pattern_r.c_str(), flags_r ); }
157         /** \overload */
158         int add( const char * pattern_r, Flags flags_r = Flags() );
159
160         /** Clear all results found so far. \ref defaultFlags remain active. */
161         void clear();
162
163         /** Clear all results and reset \ref defaultFlags. */
164         void reset( Flags flags_r = Flags() )
165         { clear(); setDefaultFlags( flags_r ); }
166
167
168       public:
169         /** The default flags passed to \c ::glob(). */
170         Flags defaultFlags() const
171         { return _defaultFlags; }
172
173         /** Set the default flags passed to \c ::glob(). */
174         void setDefaultFlags( Flags flags_r = Flags() )
175         { _defaultFlags = flags_r; }
176
177         /** Returns the value returned by the last call to \c ::glob().
178          * \c Zero on successful completion. Otherwise \c GLOB_NOSPACE or \c GLOB_ABORTED
179          * or \c GLOB_NOMATCH.
180          */
181         int lastGlobReturn() const
182         { return _lastGlobReturn; }
183
184       public:
185         /** Whether matches were found. */
186         bool empty() const
187         { return ! ( _result && _result->gl_pathc ); }
188
189         /** The number of matches found so far. */
190         size_type size() const
191         { return( _result ? _result->gl_pathc : 0 ); }
192
193         /** Iterator pointing to the first result. */
194         const_iterator begin() const
195         { return( _result ? const_iterator( _result->gl_pathv ) : const_iterator() ); }
196
197         /** Iterator pointing behind the last result. */
198         const_iterator end() const
199         { return const_iterator(); }
200
201       public:
202
203         /** \name Collecting Glob results to some _OutputIterator
204          * \code
205          * std::list<Pathname> p;
206          * Glob::collect( "/bin/a*.dat}", std::back_inserter(p) );
207          * Glob::collect( "/bin/a*{.xml,.xml.gz}", Glob::_BRACE, std::back_inserter(p) );
208          * \endcode
209          */
210         //@{
211         /** Write glob result to some \c OutputIterator. */
212         template<class _OutputIterator>
213         static int collect( const Pathname & pattern_r, _OutputIterator result_r )
214         { return collect( pattern_r.c_str(), Flags(), result_r ); }
215         /** \overload */
216         template<class _OutputIterator>
217         static int collect( const std::string & pattern_r, _OutputIterator result_r )
218         { return collect( pattern_r.c_str(), Flags(), result_r ); }
219         /** \overload */
220         template<class _OutputIterator>
221         static int collect( const char * & pattern_r, _OutputIterator result_r )
222         { return collect( pattern_r, Flags(), result_r ); }
223
224         /** \overload With \ref Flags */
225         template<class _OutputIterator>
226         static int collect( const Pathname & pattern_r, Flags flags_r, _OutputIterator result_r )
227         { return collect( pattern_r.c_str(), flags_r, result_r ); }
228         /** \overload */
229         template<class _OutputIterator>
230         static int collect( const std::string & pattern_r, Flags flags_r, _OutputIterator result_r )
231         { return collect( pattern_r.c_str(), flags_r, result_r ); }
232         /** \overload */
233         template<class _OutputIterator>
234         static int collect( const char * pattern_r, Flags flags_r, _OutputIterator result_r )
235         {
236           Glob glob( pattern_r, flags_r );
237           if ( glob.lastGlobReturn() == 0 )
238             for_( it, glob.begin(), glob.end() )
239               (*result_r)++ = *it;
240           return glob.lastGlobReturn();
241         }
242         //@}
243
244       private:
245         Flags _defaultFlags;
246         scoped_ptr< ::glob_t> _result;
247         DefaultIntegral<int,0> _lastGlobReturn;
248     };
249     ///////////////////////////////////////////////////////////////////
250
251     /** \relates Glob Stream output */
252     std::ostream & operator<<( std::ostream & str, const Glob & obj );
253
254     /** \relates Glob::const_iterator Stream output */
255     inline std::ostream & operator<<( std::ostream & str, const Glob::const_iterator & obj )
256     { return str << *obj; }
257
258     ZYPP_DECLARE_OPERATORS_FOR_FLAGS( Glob::Flags );
259
260     ///////////////////////////////////////////////////////////////////
261
262     /////////////////////////////////////////////////////////////////
263   } // namespace filesystem
264   ///////////////////////////////////////////////////////////////////
265   /////////////////////////////////////////////////////////////////
266 } // namespace zypp
267 ///////////////////////////////////////////////////////////////////
268 #endif // ZYPP_GLOB_H