- use std::filesystem for directory traversal.

So far implemented for scanning search paths
This commit is contained in:
Christoph Oelckers 2019-10-29 19:53:46 +01:00
parent 35342526a5
commit ac87665972
14 changed files with 122 additions and 188 deletions

View file

@ -1,6 +1,11 @@
cmake_minimum_required( VERSION 2.8.7 )
cmake_minimum_required( VERSION 3.1.0 )
project(Demolition)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
if( COMMAND cmake_policy )
if( POLICY CMP0011 )
cmake_policy( SET CMP0011 NEW )

View file

@ -1,4 +1,4 @@
cmake_minimum_required( VERSION 2.8.7 )
cmake_minimum_required( VERSION 3.1.0 )
include(precompiled_headers)
@ -789,6 +789,7 @@ set (PCH_SOURCES
common/gamecvars.cpp
common/gamecontrol.cpp
common/inputstate.cpp
common/searchpaths.cpp
common/2d/v_2ddrawer.cpp
common/2d/v_draw.cpp

View file

@ -1,8 +1,4 @@
cmake_minimum_required( VERSION 2.8.7 )
if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" )
endif()
cmake_minimum_required( VERSION 3.1.0 )
if (MSVC)
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /J" )

View file

@ -475,6 +475,9 @@ GameInterface *CheckFrontend()
void ChooseGame()
{
gi = CheckFrontend();
return;
#if 0
auto dir = Args->CheckValue("-game");
if (dir && !chdir(dir))
{
@ -548,6 +551,7 @@ void ChooseGame()
}
if (gi == nullptr) exit(1);
}
#endif
}

View file

@ -126,7 +126,7 @@ int FDirectory::AddDirectory(const char *dirpath)
dirmatch += '*';
if ((handle = _wfindfirst(wdirmatch, &fileinfo)) == -1)
if ((handle = _wfindfirst(dirmatch.c_str(), &fileinfo)) == -1)
{
Printf("Could not scan '%s': %s\n", dirpath, strerror(errno));
}
@ -157,7 +157,7 @@ int FDirectory::AddDirectory(const char *dirpath)
}
else
{
if (strstr(fileinfo.name, ".orig") || strstr(fileinfo.name, ".bak"))
if (strstr(fi, ".orig") || strstr(fi, ".bak"))
{
// We shouldn't add backup files to the lump directory
continue;

View file

@ -554,10 +554,14 @@ CCMD (whereisini)
FGameConfigFile* GameConfig;
static FString GameName;
void G_LoadConfig(const char* game)
void G_LoadConfig()
{
OSD_Init();
GameConfig = new FGameConfigFile();
}
void G_ReadConfig(const char* game)
{
GameConfig->DoGlobalSetup();
GameConfig->DoGameSetup(game);
GameConfig->DoKeySetup(game);

View file

@ -72,7 +72,8 @@ private:
};
extern FGameConfigFile *GameConfig;
void G_LoadConfig(const char*);
void G_LoadConfig();
void G_ReadConfig(const char*);
void G_SaveConfig();
#endif //__GAMECONFIGFILE_H__

View file

@ -17,6 +17,7 @@
InputState inputState;
void SetClipshapes();
TArray<FString> CollectSearchPaths();
struct GameFuncNameDesc
{
@ -295,9 +296,6 @@ void UserConfig::ProcessOptions()
void CONFIG_Init()
{
LumpFilter = currentGame;
if (LumpFilter.Compare("Redneck") == 0) LumpFilter = "Redneck.Redneck";
else if (LumpFilter.Compare("RedneckRides") == 0) LumpFilter = "Redneck.RidesAgain";
SetClipshapes();
// This must be done before initializing any data, so doing it late in the startup process won't work.
@ -307,10 +305,22 @@ void CONFIG_Init()
}
userConfig.ProcessOptions();
CONFIG_ReadCombatMacros();
G_LoadConfig();
// Startup dialog must be presented here so that everything can be set up before reading the keybinds.
G_LoadConfig(currentGame);
TArray<FString> paths = CollectSearchPaths();
for (auto& path : paths)
{
OutputDebugStringA(path);
OutputDebugStringA("\r\n");
}
LumpFilter = currentGame;
if (LumpFilter.Compare("Redneck") == 0) LumpFilter = "Redneck.Redneck";
else if (LumpFilter.Compare("RedneckRides") == 0) LumpFilter = "Redneck.RidesAgain";
CONFIG_ReadCombatMacros();
G_ReadConfig(currentGame);
if (userConfig.CommandName.IsNotEmpty())
{
@ -318,7 +328,6 @@ void CONFIG_Init()
}
int index = 0;
for(auto &gf : gamefuncs)
{

View file

@ -12,6 +12,10 @@ FString M_GetScreenshotsPath();
FString M_GetSavegamesPath();
FString M_GetDocumentsPath();
#ifdef _WIN32
int ReadRegistryValue(char const* const SubKey, char const* const Value, char* const Output, unsigned long* OutputSize);
#endif
#ifdef __APPLE__
FString M_GetMacAppSupportPath(const bool create = true);
void M_GetMacSearchDirectories(FString& user_docs, FString& user_app_support, FString& local_app_support);

View file

@ -21,42 +21,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include <filesystem>
#include "i_specialpaths.h"
#include "compat.h"
#include "gameconfigfile.h"
#include "cmdlib.h"
#include "utf8.h"
//
// Search path management
//
namespace fs = std::filesystem;
#if defined _WIN32
//-------------------------------------------------------------------------
//
//
//
//-------------------------------------------------------------------------
static int G_ReadRegistryValue(char const * const SubKey, char const * const Value, char * const Output, DWORD * OutputSize)
{
// KEY_WOW64_32KEY gets us around Wow6432Node on 64-bit builds
REGSAM const wow64keys[] = { KEY_WOW64_32KEY, KEY_WOW64_64KEY };
for (auto &wow64key : wow64keys)
{
HKEY hkey;
LONG keygood = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NULL, 0, KEY_READ | wow64key, &hkey);
if (keygood != ERROR_SUCCESS)
continue;
LONG retval = SHGetValueA(hkey, SubKey, Value, NULL, Output, OutputSize);
RegCloseKey(hkey);
if (retval == ERROR_SUCCESS)
return 1;
}
return 0;
}
#elif defined (__APPLE__) || defined (__FreeBSD__) || defined(__OpenBSD__) || defined (__linux__)
#ifndef _WIN32
//-------------------------------------------------------------------------
//
//
@ -346,14 +324,14 @@ void G_AddExternalSearchPaths(TArray<FString> &searchpaths)
// Duke Nukem 3D: 20th Anniversary World Tour (Steam)
bufsize = sizeof(buf);
if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 434050)", "InstallLocation", buf, &bufsize))
if (ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 434050)", "InstallLocation", buf, &bufsize))
{
searchpaths.Push(buf);
}
// Duke Nukem 3D: Megaton Edition (Steam)
bufsize = sizeof(buf);
if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 225140)", "InstallLocation", buf, &bufsize))
if (ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 225140)", "InstallLocation", buf, &bufsize))
{
char * const suffix = buf + bufsize - 1;
size_t const remaining = sizeof(buf) - bufsize;
@ -370,7 +348,7 @@ void G_AddExternalSearchPaths(TArray<FString> &searchpaths)
// Duke Nukem 3D (3D Realms Anthology (Steam) / Kill-A-Ton Collection 2015)
bufsize = sizeof(buf);
if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 359850)", "InstallLocation", buf, &bufsize))
if (ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 359850)", "InstallLocation", buf, &bufsize))
{
char * const suffix = buf + bufsize - 1;
size_t const remaining = sizeof(buf) - bufsize;
@ -381,25 +359,25 @@ void G_AddExternalSearchPaths(TArray<FString> &searchpaths)
// Duke Nukem 3D: Atomic Edition (GOG.com)
bufsize = sizeof(buf);
if (G_ReadRegistryValue("SOFTWARE\\GOG.com\\GOGDUKE3D", "PATH", buf, &bufsize))
if (ReadRegistryValue("SOFTWARE\\GOG.com\\GOGDUKE3D", "PATH", buf, &bufsize))
{
searchpaths.Push(buf);
}
// Duke Nukem 3D (3D Realms Anthology)
bufsize = sizeof(buf);
if (G_ReadRegistryValue("SOFTWARE\\3DRealms\\Duke Nukem 3D", NULL, buf, &bufsize))
if (ReadRegistryValue("SOFTWARE\\3DRealms\\Duke Nukem 3D", NULL, buf, &bufsize))
{
char * const suffix = buf + bufsize - 1;
size_t const remaining = sizeof(buf) - bufsize;
Bstrncpy(suffix, "/Duke Nukem 3D", remaining);
strncpy(suffix, "/Duke Nukem 3D", remaining);
searchpaths.Push(buf);
}
// 3D Realms Anthology
bufsize = sizeof(buf);
if (G_ReadRegistryValue("SOFTWARE\\3DRealms\\Anthology", NULL, buf, &bufsize))
if (ReadRegistryValue("SOFTWARE\\3DRealms\\Anthology", NULL, buf, &bufsize))
{
char * const suffix = buf + bufsize - 1;
size_t const remaining = sizeof(buf) - bufsize;
@ -410,7 +388,7 @@ void G_AddExternalSearchPaths(TArray<FString> &searchpaths)
// NAM (Steam)
bufsize = sizeof(buf);
if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 329650)", "InstallLocation", buf, &bufsize))
if (ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 329650)", "InstallLocation", buf, &bufsize))
{
char * const suffix = buf + bufsize - 1;
size_t const remaining = sizeof(buf) - bufsize;
@ -421,7 +399,7 @@ void G_AddExternalSearchPaths(TArray<FString> &searchpaths)
// WWII GI (Steam)
bufsize = sizeof(buf);
if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 376750)", "InstallLocation", buf, &bufsize))
if (ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 376750)", "InstallLocation", buf, &bufsize))
{
char * const suffix = buf + bufsize - 1;
size_t const remaining = sizeof(buf) - bufsize;
@ -432,35 +410,35 @@ void G_AddExternalSearchPaths(TArray<FString> &searchpaths)
// Redneck Rampage (GOG.com)
bufsize = sizeof(buf);
if (G_ReadRegistryValue("SOFTWARE\\GOG.com\\GOGREDNECKRAMPAGE", "PATH", buf, &bufsize))
if (ReadRegistryValue("SOFTWARE\\GOG.com\\GOGREDNECKRAMPAGE", "PATH", buf, &bufsize))
{
searchpaths.Push(buf);
}
// Redneck Rampage Rides Again (GOG.com)
bufsize = sizeof(buf);
if (G_ReadRegistryValue("SOFTWARE\\GOG.com\\GOGCREDNECKRIDESAGAIN", "PATH", buf, &bufsize))
if (ReadRegistryValue("SOFTWARE\\GOG.com\\GOGCREDNECKRIDESAGAIN", "PATH", buf, &bufsize))
{
searchpaths.Push(buf);
}
// Blood: One Unit Whole Blood (Steam)
bufsize = sizeof(buf);
if (G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 299030)", "InstallLocation", buf, &bufsize))
if (ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 299030)", "InstallLocation", buf, &bufsize))
{
searchpaths.Push(buf);
}
// Blood: One Unit Whole Blood (GOG.com)
bufsize = sizeof(buf);
if (G_ReadRegistryValue("SOFTWARE\\GOG.com\\GOGONEUNITONEBLOOD", "PATH", buf, &bufsize))
if (ReadRegistryValue("SOFTWARE\\GOG.com\\GOGONEUNITONEBLOOD", "PATH", buf, &bufsize))
{
searchpaths.Push(buf);
}
// Blood: Fresh Supply (Steam)
bufsize = sizeof(buf);
if (!found && G_ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 1010750)", "InstallLocation", buf, &bufsize))
if (ReadRegistryValue(R"(SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Steam App 1010750)", "InstallLocation", buf, &bufsize))
{
searchpaths.Push(buf);
strncat(buf, R"(\addons\Cryptic Passage)", 23);
@ -469,7 +447,7 @@ void G_AddExternalSearchPaths(TArray<FString> &searchpaths)
// Blood: Fresh Supply (GOG.com)
bufsize = sizeof(buf);
if (!found && G_ReadRegistryValue(R"(SOFTWARE\Wow6432Node\GOG.com\Games\1374469660)", "path", buf, &bufsize))
if (ReadRegistryValue(R"(SOFTWARE\Wow6432Node\GOG.com\Games\1374469660)", "path", buf, &bufsize))
{
searchpaths.Push(buf);
strncat(buf, R"(\addons\Cryptic Passage)", 23);
@ -478,18 +456,7 @@ void G_AddExternalSearchPaths(TArray<FString> &searchpaths)
}
#endif
//-------------------------------------------------------------------------
//
//
//
//-------------------------------------------------------------------------
void AddExpandedPath(TArray<FString> &searchpaths, const char *basepath)
{
}
#ifdef _WIN32
//==========================================================================
//
// Windows version
@ -498,109 +465,29 @@ void AddExpandedPath(TArray<FString> &searchpaths, const char *basepath)
void CollectSubdirectories(TArray<FString> &searchpath, const char *dirmatch)
{
struct _wfinddata_t fileinfo;
intptr_t handle;
FString dirpath;
int count = 0;
auto wdirmatch = WideString(dirmatch);
dirpath.Truncate(dirpath.Len()-1); // remove the '*'
if ((handle = _wfindfirst(wdirmatch, &fileinfo)) == -1)
try
{
// silently ignore non-existent paths
return;
}
else
{
do
FString dirpath = MakeUTF8(dirmatch); // convert into clean UTF-8
dirpath.Truncate(dirpath.Len() - 1); // remove the '*'
fs::path path = fs::u8path(dirpath.GetChars());
if (fs::exists(path) && fs::is_directory(path))
{
if (fileinfo.attrib & _A_HIDDEN)
for (const auto& entry : fs::directory_iterator(path))
{
// Skip hidden files and directories. (Prevents SVN bookkeeping
// info from being included.)
continue;
}
FString fi = FString(fileinfo.name);
if (fileinfo.attrib & _A_SUBDIR)
{
if (fi[0] == '.' &&
(fi[1] == '\0' ||
(fi[1] == '.' && fi[2] == '\0')))
if (fs::is_directory(entry.status()))
{
// Do not record . and .. directories.
continue;
auto filename = entry.path().filename().u8string();
FString newdir = dirpath + filename.c_str();
searchpath.Push(newdir);
}
FString newdir = dirpath + fi;
count += AddDirectory(newdir);
}
} while (_wfindnext(handle, &fileinfo) == 0);
_findclose(handle);
}
}
return count;
}
#else
//==========================================================================
//
// add_dirs
// 4.4BSD version
//
//==========================================================================
void FDirectory::AddDirectory(const char *dirpath)
{
char *argv [2] = { NULL, NULL };
argv[0] = new char[strlen(dirpath)+1];
strcpy(argv[0], dirpath);
FTS *fts;
FTSENT *ent;
fts = fts_open(argv, FTS_LOGICAL, NULL);
if (fts == NULL)
catch (fs::filesystem_error &)
{
return 0;
// Just ignore this path if it caused an error.
}
const size_t namepos = strlen(dirpath);
FString pathfix;
while ((ent = fts_read(fts)) != NULL)
{
if (ent->fts_info != FTS_D)
{
// We're only interested in getting directories.
continue;
}
fts_set(fts, ent, FTS_SKIP);
if (ent->fts_name[0] == '.')
{
// Skip hidden directories. (Prevents SVN bookkeeping
// info from being included.)
}
// Some implementations add an extra separator between
// root of the hierarchy and entity's path.
// It needs to be removed in order to resolve
// lumps' relative paths properly.
const char* path = ent->fts_path;
if ('/' == path[namepos])
{
pathfix = FString(path, namepos);
pathfix.AppendCStrPart(&path[namepos + 1], ent->fts_pathlen - namepos - 1);
path = pathfix.GetChars();
}
searchpaths.Push(path);
}
fts_close(fts);
delete[] argv[0];
}
#endif
//==========================================================================
//
@ -612,7 +499,7 @@ void FDirectory::AddDirectory(const char *dirpath)
TArray<FString> CollectSearchPaths()
{
TArray<FString> searchpths;
TArray<FString> searchpaths;
if (GameConfig->SetSection("GameSearch.Directories"))
{
@ -627,31 +514,33 @@ TArray<FString> CollectSearchPaths()
if (nice.Len() > 0)
{
#ifdef _WIN32
if (isalpha(nice[0] && nice[1] == ':' && nice[2] != '/') continue; // ignore drive relative paths because they are meaningless.
if (isalpha(nice[0] && nice[1] == ':' && nice[2] != '/')) continue; // ignore drive relative paths because they are meaningless.
#endif
// A path ending with "/*" means to add all subdirectories.
if (nice[nice.Len()-2] == '/' && nice[nice.Len()-1] == '*')
{
AddExpandedPath(searchpaths, nice);
CollectSubdirectories(searchpaths, nice);
}
// Checking Steam via a list entry allows easy removal if not wanted.
else if (nice.CompareNoCase("$STEAM"))
else if (nice.CompareNoCase("$STEAM") == 0)
{
G_AddExternalSearchPaths(searchpaths);
}
else
{
mSearchPaths.Push(nice);
searchpaths.Push(nice);
}
}
}
}
}
// Unify and remove trailing slashes
for (auto &str : mSearchPaths)
for (auto &str : searchpaths)
{
str.Substitute("\\", "/");
str.Substitute("//", "/"); // Double slashes can happen when constructing paths so just get rid of them here.
if (str.Back() == '/') str.Truncate(str.Len() - 1);
}
return searchpaths;
}

View file

@ -1,8 +1,4 @@
cmake_minimum_required( VERSION 2.8.7 )
if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" )
endif()
cmake_minimum_required( VERSION 3.1.0 )
if (MSVC)
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /J" )

View file

@ -36,6 +36,7 @@
#include <windows.h>
#include <lmcons.h>
#include <shlobj.h>
#include <Shlwapi.h>
#include "i_specialpaths.h"
#include "printf.h"
@ -334,3 +335,35 @@ FString M_GetDocumentsPath()
}
return path;
}
//===========================================================================
//
// ReadRegistryValue Windows
//
// Reads a value from the registry
//
//===========================================================================
int ReadRegistryValue(char const* const SubKey, char const* const Value, char* const Output, unsigned long* OutputSize)
{
// KEY_WOW64_32KEY gets us around Wow6432Node on 64-bit builds
REGSAM const wow64keys[] = { KEY_WOW64_32KEY, KEY_WOW64_64KEY };
for (auto& wow64key : wow64keys)
{
HKEY hkey;
LONG keygood = RegOpenKeyExA(HKEY_LOCAL_MACHINE, NULL, 0, KEY_READ | wow64key, &hkey);
if (keygood != ERROR_SUCCESS)
continue;
LONG retval = SHGetValueA(hkey, SubKey, Value, NULL, Output, OutputSize);
RegCloseKey(hkey);
if (retval == ERROR_SUCCESS)
return 1;
}
return 0;
}

View file

@ -1,8 +1,4 @@
cmake_minimum_required( VERSION 2.8.7 )
if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" )
endif()
cmake_minimum_required( VERSION 3.1.0 )
if (MSVC)
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /J" )

View file

@ -1,8 +1,4 @@
cmake_minimum_required( VERSION 2.8.7 )
if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" )
endif()
cmake_minimum_required( VERSION 3.1.0 )
if (MSVC)
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /J" )