1 /**************************************************************************
3 * Copyright 2013-2014 RAD Game Tools and Valve Software
4 * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
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:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
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
25 **************************************************************************/
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"
33 #ifdef VOGL_USE_WIN32_API
34 #include "vogl_winhdr.h"
36 #elif defined(__GNUC__)
43 #ifdef VOGL_USE_WIN32_API
44 bool find_files::find(const char *pBasepath, const char *pFilespec, uint flags)
49 return find_internal(pBasepath, "", pFilespec, flags, 0);
52 bool find_files::find(const char *pSpec, uint flags)
54 dynamic_string find_name(pSpec);
56 if (!file_utils::full_path(find_name))
59 dynamic_string find_pathname, find_filename;
60 if (!file_utils::split_path(find_name.get_ptr(), find_pathname, find_filename))
63 return find(find_pathname.get_ptr(), find_filename.get_ptr(), flags);
66 bool find_files::find_internal(const char *pBasepath, const char *pRelpath, const char *pFilespec, uint flags, int level)
68 WIN32_FIND_DATAA find_data;
70 dynamic_string filename;
72 dynamic_string_array child_paths;
73 if (flags & cFlagRecursive)
76 file_utils::combine_path(filename, pBasepath, pRelpath, "*");
78 file_utils::combine_path(filename, pBasepath, "*");
80 HANDLE handle = FindFirstFileA(filename.get_ptr(), &find_data);
81 if (handle == INVALID_HANDLE_VALUE)
83 HRESULT hres = GetLastError();
84 if ((level == 0) && (hres != NO_ERROR) && (hres != ERROR_FILE_NOT_FOUND))
94 const bool is_dir = (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
98 skip = (strcmp(find_data.cFileName, ".") == 0) || (strcmp(find_data.cFileName, "..") == 0);
100 if (find_data.dwFileAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_TEMPORARY))
103 if (find_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
105 if ((flags & cFlagAllowHidden) == 0)
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);
116 } while (FindNextFileA(handle, &find_data) != 0);
118 HRESULT hres = GetLastError();
121 handle = INVALID_HANDLE_VALUE;
123 if (hres != ERROR_NO_MORE_FILES)
131 if (strlen(pRelpath))
132 file_utils::combine_path(filename, pBasepath, pRelpath, pFilespec);
134 file_utils::combine_path(filename, pBasepath, pFilespec);
136 HANDLE handle = FindFirstFileA(filename.get_ptr(), &find_data);
137 if (handle == INVALID_HANDLE_VALUE)
139 HRESULT hres = GetLastError();
140 if ((level == 0) && (hres != NO_ERROR) && (hres != ERROR_FILE_NOT_FOUND))
150 const bool is_dir = (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
154 skip = (strcmp(find_data.cFileName, ".") == 0) || (strcmp(find_data.cFileName, "..") == 0);
156 if (find_data.dwFileAttributes & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_TEMPORARY))
159 if (find_data.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
161 if ((flags & cFlagAllowHidden) == 0)
167 if (((is_dir) && (flags & cFlagAllowDirs)) || ((!is_dir) && (flags & cFlagAllowFiles)))
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);
178 file_utils::combine_path(file.m_fullname, pBasepath, find_data.cFileName);
182 } while (FindNextFileA(handle, &find_data) != 0);
184 HRESULT hres = GetLastError();
188 if (hres != ERROR_NO_MORE_FILES)
195 for (uint i = 0; i < child_paths.size(); i++)
197 dynamic_string child_path;
198 if (strlen(pRelpath))
199 file_utils::combine_path(child_path, pRelpath, child_paths[i].get_ptr());
201 child_path = child_paths[i];
203 if (!find_internal(pBasepath, child_path.get_ptr(), pFilespec, flags, level + 1))
209 #elif defined(__GNUC__)
210 bool find_files::find(const char *pBasepath, const char *pFilespec, uint flags)
213 return find_internal(pBasepath, "", pFilespec, flags, 0);
216 bool find_files::find(const char *pSpec, uint flags)
218 dynamic_string find_name(pSpec);
220 if (!file_utils::full_path(find_name))
223 dynamic_string find_pathname, find_filename;
224 if (!file_utils::split_path(find_name.get_ptr(), find_pathname, find_filename))
227 return find(find_pathname.get_ptr(), find_filename.get_ptr(), flags);
230 bool find_files::find_internal(const char *pBasepath, const char *pRelpath, const char *pFilespec, uint flags, int level)
232 dynamic_string pathname;
233 if (strlen(pRelpath))
234 file_utils::combine_path(pathname, pBasepath, pRelpath);
236 pathname = pBasepath;
238 if (!pathname.is_empty())
240 char c = pathname.back();
245 DIR *dp = opendir(pathname.get_ptr());
248 return level ? true : false;
250 dynamic_string_array paths;
254 struct dirent *ep = readdir(dp);
257 if ((strcmp(ep->d_name, ".") == 0) || (strcmp(ep->d_name, "..") == 0))
260 const bool is_directory = (ep->d_type & DT_DIR) != 0;
261 const bool is_file = (ep->d_type & DT_REG) != 0;
263 dynamic_string filename(ep->d_name);
267 if (flags & cFlagRecursive)
269 paths.push_back(filename);
273 if (((is_file) && (flags & cFlagAllowFiles)) || ((is_directory) && (flags & cFlagAllowDirs)))
275 if (0 == fnmatch(pFilespec, filename.get_ptr(), 0))
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;
291 if (flags & cFlagRecursive)
293 for (uint i = 0; i < paths.size(); i++)
295 dynamic_string childpath;
296 if (strlen(pRelpath))
297 file_utils::combine_path(childpath, pRelpath, paths[i].get_ptr());
299 childpath = paths[i];
301 if (!find_internal(pBasepath, childpath.get_ptr(), pFilespec, flags, level + 1))