Line data Source code
1 : // Snap Websites Servers -- glob a directory and enumerate the files
2 : // Copyright (c) 2016-2019 Made to Order Software Corp. All Rights Reserved
3 : //
4 : // https://snapwebsites.org/
5 : // contact@m2osw.com
6 : //
7 : // This program is free software; you can redistribute it and/or modify
8 : // it under the terms of the GNU General Public License as published by
9 : // the Free Software Foundation; either version 2 of the License, or
10 : // (at your option) any later version.
11 : //
12 : // This program is distributed in the hope that it will be useful,
13 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : // GNU General Public License for more details.
16 : //
17 : // You should have received a copy of the GNU General Public License
18 : // along with this program; if not, write to the Free Software
19 : // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 : //
21 :
22 : // self
23 : //
24 : #include "glob_dir.h"
25 :
26 : // snapwebsites lib
27 : //
28 : #include "log.h"
29 :
30 :
31 : // last include
32 : //
33 : #include <snapdev/poison.h>
34 :
35 :
36 :
37 : namespace snap
38 : {
39 :
40 :
41 : namespace
42 : {
43 :
44 :
45 0 : int glob_err_callback(char const * epath, int eerrno)
46 : {
47 0 : SNAP_LOG_ERROR("an error occurred while reading directory under \"")
48 0 : (epath)
49 0 : ("\". Got error: ")
50 0 : (eerrno)
51 0 : (", ")
52 0 : (strerror(eerrno))
53 0 : (".");
54 :
55 : // do not abort on a directory read error...
56 0 : return 0;
57 : }
58 :
59 :
60 : }
61 : // no name namespace
62 :
63 :
64 : /** \class glob_dir
65 : * \brief Enumerate the contents of a directory using a wildcard.
66 : *
67 : * This class encapsulates and hides a Unix 'C' `glob_t` structure.
68 : *
69 : * It allows enumeration of a single folder at the first level
70 : * using a path containing a Unix shell compatible wildcard.
71 : */
72 :
73 :
74 : /** \brief Create an empty directory.
75 : *
76 : * The default constructor creates an empty directory. You are expected
77 : * to call the set_path() function at least once before attempting to
78 : * enumerate files.
79 : *
80 : * \sa set_path()
81 : */
82 0 : glob_dir::glob_dir()
83 : {
84 : // Empty
85 0 : }
86 :
87 :
88 : /** \brief Create a glob_dir from a path and flags.
89 : *
90 : * This constructor calls set_path() immediately using the two parameters
91 : * passed to it.
92 : *
93 : * \param[in] path The path including the Unix shell wildcards.
94 : * \param[in] flags A set of GLOB_... flags.
95 : * \param[in] allow_empty Just return on an empty glob().
96 : *
97 : * \sa set_path()
98 : */
99 0 : glob_dir::glob_dir( char const * path, int const flags, bool allow_empty )
100 : {
101 0 : set_path( path, flags, allow_empty );
102 0 : }
103 :
104 :
105 : /** \brief Create a glob_dir from a path and flags.
106 : *
107 : * This constructor calls set_path() immediately using the two parameters
108 : * passed to it.
109 : *
110 : * \param[in] path The path including the Unix shell wildcards.
111 : * \param[in] flags A set of GLOB_... flags.
112 : * \param[in] allow_empty Just return on an empty glob().
113 : *
114 : * \sa set_path()
115 : */
116 0 : glob_dir::glob_dir( std::string const & path, int const flags, bool allow_empty )
117 : {
118 0 : set_path( path, flags, allow_empty );
119 0 : }
120 :
121 :
122 : /** \brief Create a glob_dir from a path and flags.
123 : *
124 : * This constructor calls set_path() immediately using the two parameters
125 : * passed to it.
126 : *
127 : * \param[in] path The path including the Unix shell wildcards.
128 : * \param[in] flags A set of GLOB_... flags.
129 : * \param[in] allow_empty Just return on an empty glob().
130 : *
131 : * \sa set_path()
132 : */
133 0 : glob_dir::glob_dir( QString const & path, int const flags, bool allow_empty )
134 : {
135 0 : set_path( path, flags, allow_empty );
136 0 : }
137 :
138 :
139 : /** \brief Set the path to read with glob().
140 : *
141 : * This function is an overload which accepts a bare pointer as input.
142 : *
143 : * \param[in] path The path including the Unix shell wildcards.
144 : * \param[in] flags A set of GLOB_... flags.
145 : * \param[in] allow_empty Just return on an empty glob().
146 : */
147 0 : void glob_dir::set_path( char const * path, int const flags, bool allow_empty )
148 : {
149 0 : if(path != nullptr)
150 : {
151 0 : set_path(std::string(path), flags, allow_empty);
152 : }
153 0 : }
154 :
155 :
156 : /** \brief Set the path to read with glob().
157 : *
158 : * This function passes the \p path parameter to the glob() function and
159 : * saves the results in an internally managed glob_t structure.
160 : *
161 : * The flags are as specified in the glob(3) function (try `man glob`).
162 : *
163 : * The path is expected to already include a wildcard. Without a wildcard,
164 : * it probably won't work as expected.
165 : *
166 : * The function doesn't return anything. Instead it will memorize the
167 : * results and enumerate them once the enumerate_glob() function is called.
168 : *
169 : * \note
170 : * Do not worry about the globfree(), this class handles that part internally.
171 : *
172 : * \todo
173 : * Offer another function to retrieve a vector of strings instead of only an
174 : * enumeration function.
175 : *
176 : * \param[in] path The path including the Unix shell wildcards.
177 : * \param[in] flags A set of GLOB_... flags.
178 : * \param[in] allow_empty Just return on an empty glob().
179 : */
180 0 : void glob_dir::set_path( std::string const & path, int const flags, bool allow_empty )
181 : {
182 0 : f_dir = glob_pointer_t( new glob_t );
183 0 : *f_dir = glob_t();
184 0 : int const r(glob(path.c_str(), flags, glob_err_callback, f_dir.get()));
185 0 : if(r != 0)
186 : {
187 : // do nothing when errors occur
188 : //
189 0 : QString err_msg;
190 0 : switch(r)
191 : {
192 0 : case GLOB_NOSPACE:
193 0 : err_msg = "glob() did not have enough memory to alllocate its buffers.";
194 0 : break;
195 :
196 0 : case GLOB_ABORTED:
197 0 : err_msg = "glob() was aborted after a read error.";
198 0 : break;
199 :
200 0 : case GLOB_NOMATCH:
201 0 : if(allow_empty)
202 : {
203 0 : return;
204 : }
205 0 : err_msg = QString("glob() could not find any files matching the specified glob pattern: \"%1\".")
206 0 : .arg(QString::fromUtf8(path.c_str()));
207 0 : break;
208 :
209 0 : default:
210 0 : err_msg = QString("unknown glob() error code: %1.").arg(r);
211 0 : break;
212 :
213 : }
214 0 : throw glob_dir_exception( r, err_msg );
215 : }
216 : }
217 :
218 :
219 : /** \brief Set the path to read with glob().
220 : *
221 : * This function is an overload with a QString. See the set_path() function
222 : * with an std::string for more details.
223 : *
224 : * \param[in] path The path including the Unix shell wildcards.
225 : * \param[in] flags A set of GLOB_... flags.
226 : * \param[in] allow_empty Just return on an empty glob().
227 : */
228 0 : void glob_dir::set_path( QString const & path, int const flags, bool allow_empty )
229 : {
230 0 : set_path(path.toUtf8().data(), flags, allow_empty);
231 0 : }
232 :
233 :
234 : /** \brief Enumerate full filenames with an std::string.
235 : *
236 : * This function enumerates all the filenames found in this glob
237 : * calling your callback once per file. This function expects
238 : * an std::string. You can also enumerate using a QString.
239 : *
240 : * \param[in] func The function to call on each filename.
241 : */
242 0 : void glob_dir::enumerate_glob( std::function<void (std::string path)> func ) const
243 : {
244 0 : if(f_dir != nullptr)
245 : {
246 0 : for(size_t idx(0); idx < f_dir->gl_pathc; ++idx)
247 : {
248 0 : func(f_dir->gl_pathv[idx]);
249 : }
250 : }
251 0 : }
252 :
253 :
254 : /** \brief Enumerate full filenames with a QString.
255 : *
256 : * This function enumerates all the filenames found in this glob
257 : * calling your callback once per file. This function expects
258 : * a QString. You can also enumerate using an std::string.
259 : *
260 : * \param[in] func The function to call on each filename.
261 : */
262 0 : void glob_dir::enumerate_glob( std::function<void (QString path)> func ) const
263 : {
264 0 : if(f_dir != nullptr)
265 : {
266 0 : for(size_t idx(0); idx < f_dir->gl_pathc; ++idx)
267 : {
268 0 : func(QString::fromUtf8(f_dir->gl_pathv[idx]));
269 : }
270 : }
271 0 : }
272 :
273 :
274 :
275 :
276 6 : } // namespace snap
277 : // vim: ts=4 sw=4 et
|