From 18300448ee486438a3786d304fff773ad243dcc0 Mon Sep 17 00:00:00 2001 From: Boondorl Date: Sun, 3 Aug 2025 21:18:17 -0400 Subject: [PATCH] Added recursive paths for IWADs and file searching Adds a RecursivePath= key for checking subfolders in a given path. Only supports finding direct files and not directories. Currently configs and dehacked aren't supported. --- src/common/utility/cmdlib.cpp | 32 ++++++++++++++++++++++++++++++++ src/common/utility/cmdlib.h | 1 + src/common/utility/findfile.cpp | 19 +++++++++++++++++++ src/d_iwad.cpp | 31 +++++++++++++++++++++++++++++-- src/d_main.h | 3 ++- 5 files changed, 83 insertions(+), 3 deletions(-) diff --git a/src/common/utility/cmdlib.cpp b/src/common/utility/cmdlib.cpp index 3b8dc9981..91398519d 100644 --- a/src/common/utility/cmdlib.cpp +++ b/src/common/utility/cmdlib.cpp @@ -150,6 +150,38 @@ bool FileExists (const char *filename) return res && !isdir; } +//========================================================================== +// +// RecursiveFileExists +// +// Returns the path to the file if it was found within a subdirectory, +// otherwise returning an empty string. +// +//========================================================================== + +FString RecursiveFileExists(const FString& path, const FString& file) +{ + if (FileExists(path + "/" + file)) + return path + "/" + file; + + // If we couldn't find it in the base directory, time to start searching. + FileSys::FileList list; + if (FileSys::ScanDirectory(list, path.GetChars(), "*")) + { + for (auto& entry : list) + { + if (entry.isDirectory && !entry.isHidden && !entry.isSystem) + { + FStringf f("%s/%s", entry.FilePath.c_str(), file.GetChars()); + if (FileExists(f)) + return f; + } + } + } + + return ""; +} + //========================================================================== // // FileReadable diff --git a/src/common/utility/cmdlib.h b/src/common/utility/cmdlib.h index 88027c156..8a7ea97bd 100644 --- a/src/common/utility/cmdlib.h +++ b/src/common/utility/cmdlib.h @@ -34,6 +34,7 @@ char(&_ArraySizeHelper(T(&array)[N]))[N]; #define myoffsetof(type,identifier) ((size_t)&((type *)alignof(type))->identifier - alignof(type)) bool FileExists (const char *filename); +FString RecursiveFileExists(const FString& path, const FString& file); inline bool FileExists(const FString& filename) { return FileExists(filename.GetChars()); diff --git a/src/common/utility/findfile.cpp b/src/common/utility/findfile.cpp index d5da7b027..f2b4e4561 100644 --- a/src/common/utility/findfile.cpp +++ b/src/common/utility/findfile.cpp @@ -263,6 +263,25 @@ const char* BaseFileSearch(const char* file, const char* ext, bool lookfirstinpr } } } + else if (stricmp(key, "RecursivePath") == 0) + { + FString dir; + + dir = NicePath(value); + if (dir.IsNotEmpty()) + { + if (dir.Back() == '/') + dir.Truncate(dir.Len() - 1); + + // Folders can't be used here since those are going to be checked + // recursively, so only find actual files. + FString path = RecursiveFileExists(dir, file); + if (path.IsNotEmpty()) + { + return path.GetChars(); + } + } + } } } diff --git a/src/d_iwad.cpp b/src/d_iwad.cpp index 6a60c4e90..f4cdf724e 100644 --- a/src/d_iwad.cpp +++ b/src/d_iwad.cpp @@ -468,6 +468,11 @@ void FIWadManager::CollectSearchPaths() FString nice = NicePath(value); if (nice.Len() > 0) mSearchPaths.Push(nice); } + else if (stricmp(key, "RecursivePath") == 0) + { + FString nice = NicePath(value); + if (nice.Len() > 0) mRecursiveSearchPaths.Push(nice); + } } } mSearchPaths.Append(I_GetGogPaths()); @@ -480,6 +485,11 @@ void FIWadManager::CollectSearchPaths() FixPathSeperator(str); if (str.Back() == '/') str.Truncate(str.Len() - 1); } + for (auto& str : mRecursiveSearchPaths) + { + FixPathSeperator(str); + if (str.Back() == '/') str.Truncate(str.Len() - 1); + } } //========================================================================== @@ -490,11 +500,11 @@ void FIWadManager::CollectSearchPaths() // //========================================================================== -void FIWadManager::AddIWADCandidates(const char *dir) +void FIWadManager::AddIWADCandidates(const char *dir, bool nosubdir) { FileSys::FileList list; - if (FileSys::ScanDirectory(list, dir, "*", true)) + if (FileSys::ScanDirectory(list, dir, "*", nosubdir)) { for(auto& entry : list) { @@ -580,6 +590,11 @@ FString FIWadManager::IWADPathFileSearch(const FString &file) FString f = path + "/" + file; if(FileExists(f)) return f; } + for (const FString& path : mRecursiveSearchPaths) + { + FString f = RecursiveFileExists(path, file); + if (f.IsNotEmpty()) return f; + } return ""; } @@ -596,6 +611,10 @@ int FIWadManager::IdentifyVersion (std::vector&wadfiles, const char { AddIWADCandidates(dir.GetChars()); } + for (auto& dir : mRecursiveSearchPaths) + { + AddIWADCandidates(dir.GetChars(), false); + } unsigned numFoundWads = mFoundWads.Size(); if (iwadparm) @@ -626,6 +645,14 @@ int FIWadManager::IdentifyVersion (std::vector&wadfiles, const char mFoundWads.Push({ fullpath, "", -1 }); } } + for (const auto& dir : mRecursiveSearchPaths) + { + FString fullpath = RecursiveFileExists(dir, custwad); + if (fullpath.IsNotEmpty()) + { + mFoundWads.Push({ fullpath, "", -1 }); + } + } } if (mFoundWads.Size() != numFoundWads) diff --git a/src/d_main.h b/src/d_main.h index b5a08750c..33720fc33 100644 --- a/src/d_main.h +++ b/src/d_main.h @@ -123,6 +123,7 @@ class FIWadManager TArray mIWadInfos; TArray mIWadNames; TArray mSearchPaths; + TArray mRecursiveSearchPaths; TArray mOrderNames; TArray mFoundWads; TArray mLumpsFound; @@ -132,7 +133,7 @@ class FIWadManager int CheckIWADInfo(const char *iwad); int IdentifyVersion (std::vector& wadfiles, const char *iwad, const char *zdoom_wad, const char *optional_wad); void CollectSearchPaths(); - void AddIWADCandidates(const char *dir); + void AddIWADCandidates(const char *dir, bool nosubdir = true); void ValidateIWADs(); FString IWADPathFileSearch(const FString &file); public: