]> git.cworth.org Git - vogl/blob - src/voglcore/vogl_find_files.cpp
Initial vogl checkin
[vogl] / src / voglcore / vogl_find_files.cpp
1 /**************************************************************************
2  *
3  * Copyright 2013-2014 RAD Game Tools and Valve Software
4  * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  *
25  **************************************************************************/
26
27 // File: vogl_win32_find_files.cpp
28 #include "vogl_core.h"
29 #include "vogl_find_files.h"
30 #include "vogl_file_utils.h"
31 #include "vogl_strutils.h"
32
33 #ifdef VOGL_USE_WIN32_API
34 #include "vogl_winhdr.h"
35
36 #elif defined(__GNUC__)
37 #include <fnmatch.h>
38 #include <dirent.h>
39 #endif
40
41 namespace vogl
42 {
43 #ifdef VOGL_USE_WIN32_API
44     bool find_files::find(const char *pBasepath, const char *pFilespec, uint flags)
45     {
46         m_last_error = S_OK;
47         m_files.resize(0);
48
49         return find_internal(pBasepath, "", pFilespec, flags, 0);
50     }
51
52     bool find_files::find(const char *pSpec, uint flags)
53     {
54         dynamic_string find_name(pSpec);
55
56         if (!file_utils::full_path(find_name))
57             return false;
58
59         dynamic_string find_pathname, find_filename;
60         if (!file_utils::split_path(find_name.get_ptr(), find_pathname, find_filename))
61             return false;
62
63         return find(find_pathname.get_ptr(), find_filename.get_ptr(), flags);
64     }
65
66     bool find_files::find_internal(const char *pBasepath, const char *pRelpath, const char *pFilespec, uint flags, int level)
67     {
68         WIN32_FIND_DATAA find_data;
69
70         dynamic_string filename;
71
72         dynamic_string_array child_paths;
73         if (flags & cFlagRecursive)
74         {
75             if (strlen(pRelpath))
76                 file_utils::combine_path(filename, pBasepath, pRelpath, "*");
77             else
78                 file_utils::combine_path(filename, pBasepath, "*");
79
80             HANDLE handle = FindFirstFileA(filename.get_ptr(), &find_data);
81             if (handle == INVALID_HANDLE_VALUE)
82             {
83                 HRESULT hres = GetLastError();
84                 if ((level == 0) && (hres != NO_ERROR) && (hres != ERROR_FILE_NOT_FOUND))
85                 {
86                     m_last_error = hres;
87                     return false;
88                 }
89             }
90             else
91             {
92                 do
93                 {
94                     const bool is_dir = (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
95
96                     bool skip = !is_dir;
97                     if (is_dir)
98                         skip = (strcmp(find_data.cFileName, ".") == 0) || (strcmp(find_data.cFileName, "..") == 0);
99
100                     if (find_data.dwFileAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_TEMPORARY))
101                         skip = true;
102
103                     if (find_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
104                     {
105                         if ((flags & cFlagAllowHidden) == 0)
106                             skip = true;
107                     }
108
109                     if (!skip)
110                     {
111                         dynamic_string child_path(find_data.cFileName);
112                         if ((!child_path.count_char('?')) && (!child_path.count_char('*')))
113                             child_paths.push_back(child_path);
114                     }
115
116                 } while (FindNextFileA(handle, &find_data) != 0);
117
118                 HRESULT hres = GetLastError();
119
120                 FindClose(handle);
121                 handle = INVALID_HANDLE_VALUE;
122
123                 if (hres != ERROR_NO_MORE_FILES)
124                 {
125                     m_last_error = hres;
126                     return false;
127                 }
128             }
129         }
130
131         if (strlen(pRelpath))
132             file_utils::combine_path(filename, pBasepath, pRelpath, pFilespec);
133         else
134             file_utils::combine_path(filename, pBasepath, pFilespec);
135
136         HANDLE handle = FindFirstFileA(filename.get_ptr(), &find_data);
137         if (handle == INVALID_HANDLE_VALUE)
138         {
139             HRESULT hres = GetLastError();
140             if ((level == 0) && (hres != NO_ERROR) && (hres != ERROR_FILE_NOT_FOUND))
141             {
142                 m_last_error = hres;
143                 return false;
144             }
145         }
146         else
147         {
148             do
149             {
150                 const bool is_dir = (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
151
152                 bool skip = false;
153                 if (is_dir)
154                     skip = (strcmp(find_data.cFileName, ".") == 0) || (strcmp(find_data.cFileName, "..") == 0);
155
156                 if (find_data.dwFileAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_TEMPORARY))
157                     skip = true;
158
159                 if (find_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
160                 {
161                     if ((flags & cFlagAllowHidden) == 0)
162                         skip = true;
163                 }
164
165                 if (!skip)
166                 {
167                     if (((is_dir) && (flags & cFlagAllowDirs)) || ((!is_dir) && (flags & cFlagAllowFiles)))
168                     {
169                         m_files.resize(m_files.size() + 1);
170                         file_desc &file = m_files.back();
171                         file.m_is_dir = is_dir;
172                         file.m_base = pBasepath;
173                         file.m_name = find_data.cFileName;
174                         file.m_rel = pRelpath;
175                         if (strlen(pRelpath))
176                             file_utils::combine_path(file.m_fullname, pBasepath, pRelpath, find_data.cFileName);
177                         else
178                             file_utils::combine_path(file.m_fullname, pBasepath, find_data.cFileName);
179                     }
180                 }
181
182             } while (FindNextFileA(handle, &find_data) != 0);
183
184             HRESULT hres = GetLastError();
185
186             FindClose(handle);
187
188             if (hres != ERROR_NO_MORE_FILES)
189             {
190                 m_last_error = hres;
191                 return false;
192             }
193         }
194
195         for (uint i = 0; i < child_paths.size(); i++)
196         {
197             dynamic_string child_path;
198             if (strlen(pRelpath))
199                 file_utils::combine_path(child_path, pRelpath, child_paths[i].get_ptr());
200             else
201                 child_path = child_paths[i];
202
203             if (!find_internal(pBasepath, child_path.get_ptr(), pFilespec, flags, level + 1))
204                 return false;
205         }
206
207         return true;
208     }
209 #elif defined(__GNUC__)
210     bool find_files::find(const char *pBasepath, const char *pFilespec, uint flags)
211     {
212         m_files.resize(0);
213         return find_internal(pBasepath, "", pFilespec, flags, 0);
214     }
215
216     bool find_files::find(const char *pSpec, uint flags)
217     {
218         dynamic_string find_name(pSpec);
219
220         if (!file_utils::full_path(find_name))
221             return false;
222
223         dynamic_string find_pathname, find_filename;
224         if (!file_utils::split_path(find_name.get_ptr(), find_pathname, find_filename))
225             return false;
226
227         return find(find_pathname.get_ptr(), find_filename.get_ptr(), flags);
228     }
229
230     bool find_files::find_internal(const char *pBasepath, const char *pRelpath, const char *pFilespec, uint flags, int level)
231     {
232         dynamic_string pathname;
233         if (strlen(pRelpath))
234             file_utils::combine_path(pathname, pBasepath, pRelpath);
235         else
236             pathname = pBasepath;
237
238         if (!pathname.is_empty())
239         {
240             char c = pathname.back();
241             if (c != '/')
242                 pathname += "/";
243         }
244
245         DIR *dp = opendir(pathname.get_ptr());
246
247         if (!dp)
248             return level ? true : false;
249
250         dynamic_string_array paths;
251
252         for (;;)
253         {
254             struct dirent *ep = readdir(dp);
255             if (!ep)
256                 break;
257             if ((strcmp(ep->d_name, ".") == 0) || (strcmp(ep->d_name, "..") == 0))
258                 continue;
259
260             const bool is_directory = (ep->d_type & DT_DIR) != 0;
261             const bool is_file = (ep->d_type & DT_REG) != 0;
262
263             dynamic_string filename(ep->d_name);
264
265             if (is_directory)
266             {
267                 if (flags & cFlagRecursive)
268                 {
269                     paths.push_back(filename);
270                 }
271             }
272
273             if (((is_file) && (flags & cFlagAllowFiles)) || ((is_directory) && (flags & cFlagAllowDirs)))
274             {
275                 if (0 == fnmatch(pFilespec, filename.get_ptr(), 0))
276                 {
277                     m_files.resize(m_files.size() + 1);
278                     file_desc &file = m_files.back();
279                     file.m_is_dir = is_directory;
280                     file.m_base = pBasepath;
281                     file.m_rel = pRelpath;
282                     file.m_name = filename;
283                     file.m_fullname = pathname + filename;
284                 }
285             }
286         }
287
288         closedir(dp);
289         dp = NULL;
290
291         if (flags & cFlagRecursive)
292         {
293             for (uint i = 0; i < paths.size(); i++)
294             {
295                 dynamic_string childpath;
296                 if (strlen(pRelpath))
297                     file_utils::combine_path(childpath, pRelpath, paths[i].get_ptr());
298                 else
299                     childpath = paths[i];
300
301                 if (!find_internal(pBasepath, childpath.get_ptr(), pFilespec, flags, level + 1))
302                     return false;
303             }
304         }
305
306         return true;
307     }
308 #else
309 #error Unimplemented
310 #endif
311
312 } // namespace vogl