mirror of
https://github.com/ZDoom/raze-gles.git
synced 2025-01-11 18:50:46 +00:00
- brought in GZDoom's gameconfigfile so that the settings can be transitioned to a more robust implementation.
This commit is contained in:
parent
0d737ee130
commit
bc8578e153
17 changed files with 2188 additions and 61 deletions
|
@ -500,6 +500,7 @@ set( PLAT_WIN32_SOURCES
|
|||
audiolib/src/driver_directsound.cpp
|
||||
glad/src/glad_wgl.c
|
||||
platform/win32/winbits.cpp
|
||||
platform/win32/i_specialpaths.cpp
|
||||
|
||||
# This needs a rework anyway in order to consolidate the startup dialogs so don't bother to sort in properly.
|
||||
#startgtk.game.cpp
|
||||
|
@ -519,11 +520,13 @@ set( PLAT_SDL_SOURCES
|
|||
set( PLAT_UNIX_SOURCES
|
||||
platform/gtk/dynamicgtk.cpp
|
||||
platform/gtk/gtkbits.cpp
|
||||
platform/unix/i_specialpaths.cpp
|
||||
)
|
||||
|
||||
set( PLAT_OSX_SOURCES
|
||||
platform/macos/SDLMain.mm
|
||||
platform/macos/osxbits.mm
|
||||
platform/macos/i_specialpaths.mm
|
||||
)
|
||||
|
||||
set( PLAT_COCOA_SOURCES
|
||||
|
@ -782,7 +785,9 @@ set (PCH_SOURCES
|
|||
build/src/voxmodel.cpp
|
||||
|
||||
common/rts.cpp
|
||||
common/gameconfigfile.cpp
|
||||
|
||||
common/utility/cmdlib.cpp
|
||||
common/utility/m_argv.cpp
|
||||
common/utility/files.cpp
|
||||
common/utility/files_decompress.cpp
|
||||
|
|
502
source/common/gameconfigfile.cpp
Normal file
502
source/common/gameconfigfile.cpp
Normal file
|
@ -0,0 +1,502 @@
|
|||
/*
|
||||
** gameconfigfile.cpp
|
||||
** An .ini parser specifically for zdoom.ini
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 1998-2008 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OFf
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "gameconfigfile.h"
|
||||
//#include "c_cvars.h"
|
||||
//#include "c_dispatch.h"
|
||||
//#include "c_bind.h"
|
||||
#include "m_argv.h"
|
||||
#include "cmdlib.h"
|
||||
//#include "version.h"
|
||||
#include "i_specialpaths.h"
|
||||
//#include "v_font.h"
|
||||
//#include "doomstat.h"
|
||||
//#include "gi.h"
|
||||
//#include "d_main.h"
|
||||
|
||||
#define GAMENAME "Demolition"
|
||||
#define LASTRUNVERSION "1"
|
||||
|
||||
#if !defined _MSC_VER && !defined __APPLE__
|
||||
//#include "i_system.h" // for SHARE_DIR
|
||||
#endif // !_MSC_VER && !__APPLE__
|
||||
|
||||
FGameConfigFile::FGameConfigFile ()
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
FString user_docs, user_app_support, local_app_support;
|
||||
M_GetMacSearchDirectories(user_docs, user_app_support, local_app_support);
|
||||
#endif
|
||||
|
||||
FString pathname;
|
||||
|
||||
OkayToWrite = false; // Do not allow saving of the config before DoKeySetup()
|
||||
bModSetup = false;
|
||||
pathname = GetConfigPath (true);
|
||||
ChangePathName (pathname);
|
||||
LoadConfigFile ();
|
||||
|
||||
// If zdoom.ini was read from the program directory, switch
|
||||
// to the user directory now. If it was read from the user
|
||||
// directory, this effectively does nothing.
|
||||
pathname = GetConfigPath (false);
|
||||
ChangePathName (pathname);
|
||||
|
||||
// Set default IWAD search paths if none present
|
||||
if (!SetSection ("GameSearch.Directories"))
|
||||
{
|
||||
SetSection ("GameSearch.Directories", true);
|
||||
SetValueForKey ("Path", ".", true);
|
||||
SetValueForKey ("Path", "./*", true);
|
||||
#ifdef __APPLE__
|
||||
SetValueForKey ("Path", user_docs + "/*", true);
|
||||
SetValueForKey ("Path", user_app_support + "/*", true);
|
||||
SetValueForKey ("Path", "$PROGDIR", true);
|
||||
SetValueForKey ("Path", "$PROGDIR/*", true);
|
||||
SetValueForKey ("Path", local_app_support + "/*", true);
|
||||
#elif !defined(__unix__)
|
||||
SetValueForKey ("Path", "$HOME/*", true);
|
||||
SetValueForKey ("Path", "$PROGDIR", true);
|
||||
SetValueForKey ("Path", "$PROGDIR/*", true);
|
||||
#else
|
||||
SetValueForKey ("Path", "$HOME/" GAME_DIR "/*", true);
|
||||
// Arch Linux likes them in /usr/share/doom
|
||||
// Debian likes them in /usr/share/games/doom
|
||||
// I assume other distributions don't do anything radically different
|
||||
SetValueForKey ("Path", "/usr/local/share", true);
|
||||
SetValueForKey ("Path", "/usr/local/share/games", true);
|
||||
SetValueForKey ("Path", "/usr/share/doom", true);
|
||||
SetValueForKey ("Path", "/usr/share/games", true);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Set default search paths if none present
|
||||
if (!SetSection ("FileSearch.Directories"))
|
||||
{
|
||||
SetSection ("FileSearch.Directories", true);
|
||||
#ifdef __APPLE__
|
||||
SetValueForKey ("Path", user_docs, true);
|
||||
SetValueForKey ("Path", user_app_support, true);
|
||||
SetValueForKey ("Path", "$PROGDIR", true);
|
||||
SetValueForKey ("Path", local_app_support, true);
|
||||
#elif !defined(__unix__)
|
||||
SetValueForKey ("Path", "$PROGDIR", true);
|
||||
SetValueForKey ("Path", "$GAMEDIR", true);
|
||||
#else
|
||||
SetValueForKey ("Path", "$HOME/" GAME_DIR, true);
|
||||
SetValueForKey ("Path", SHARE_DIR, true);
|
||||
SetValueForKey ("Path", "/usr/local/share/doom", true);
|
||||
SetValueForKey ("Path", "/usr/local/share/games/doom", true);
|
||||
SetValueForKey ("Path", "/usr/share/doom", true);
|
||||
SetValueForKey ("Path", "/usr/share/games/doom", true);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Set default search paths if none present
|
||||
if (!SetSection("SoundfontSearch.Directories"))
|
||||
{
|
||||
SetSection("SoundfontSearch.Directories", true);
|
||||
#ifdef __APPLE__
|
||||
SetValueForKey("Path", user_docs + "/soundfonts", true);
|
||||
SetValueForKey("Path", user_app_support + "/soundfonts", true);
|
||||
SetValueForKey("Path", "$PROGDIR/soundfonts", true);
|
||||
SetValueForKey("Path", local_app_support + "/soundfonts", true);
|
||||
#elif !defined(__unix__)
|
||||
SetValueForKey("Path", "$PROGDIR/soundfonts", true);
|
||||
#else
|
||||
SetValueForKey("Path", "$HOME/" GAME_DIR "/soundfonts", true);
|
||||
SetValueForKey("Path", "/usr/local/share/" GAME_DIR "/soundfonts", true);
|
||||
SetValueForKey("Path", "/usr/local/share/games/" GAME_DIR "/soundfonts", true);
|
||||
SetValueForKey("Path", "/usr/share/" GAME_DIR "/soundfonts", true);
|
||||
SetValueForKey("Path", "/usr/share/games/" GAME_DIR "/soundfonts", true);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Add some self-documentation.
|
||||
SetSectionNote("GameSearch.Directories",
|
||||
"# These are the directories to automatically search for game data.\n"
|
||||
"# Each directory should be on a separate line, preceded by Path=\n");
|
||||
SetSectionNote("FileSearch.Directories",
|
||||
"# These are the directories to search for add-ons added with the -file\n"
|
||||
"# command line parameter, if they cannot be found with the path\n"
|
||||
"# as-is. Layout is the same as for GameSearch.Directories\n");
|
||||
SetSectionNote("SoundfontSearch.Directories",
|
||||
"# These are the directories to search for soundfonts that let listed in the menu.\n"
|
||||
"# Layout is the same as for GameSearch.Directories\n");
|
||||
}
|
||||
|
||||
FGameConfigFile::~FGameConfigFile ()
|
||||
{
|
||||
}
|
||||
|
||||
void FGameConfigFile::WriteCommentHeader (FileWriter *file) const
|
||||
{
|
||||
file->Printf ("# This file was generated by " GAMENAME " %s\n", ""/*GetVersionString()*/);
|
||||
}
|
||||
|
||||
void FGameConfigFile::DoAutoloadSetup (/*FIWadManager *iwad_man*/)
|
||||
{
|
||||
// Create auto-load sections, so users know what's available.
|
||||
// Note that this totem pole is the reverse of the order that
|
||||
// they will appear in the file.
|
||||
|
||||
double last = 0;
|
||||
if (SetSection ("LastRun"))
|
||||
{
|
||||
const char *lastver = GetValueForKey ("Version");
|
||||
if (lastver != NULL) last = atof(lastver);
|
||||
}
|
||||
|
||||
CreateSectionAtStart("Global.Autoload");
|
||||
|
||||
// The same goes for auto-exec files.
|
||||
CreateStandardAutoExec("ShadowWarrior.AutoExec", true);
|
||||
CreateStandardAutoExec("IonFury.AutoExec", true);
|
||||
CreateStandardAutoExec("RedneckRides.AutoExec", true);
|
||||
CreateStandardAutoExec("Redneck.AutoExec", true);
|
||||
CreateStandardAutoExec("WW2GI.AutoExec", true);
|
||||
CreateStandardAutoExec("Nam.AutoExec", true);
|
||||
CreateStandardAutoExec("DukeNukem3D.AutoExec", true);
|
||||
|
||||
CreateStandardAutoExec("ShadowWarrior.AutoLoad", true);
|
||||
CreateStandardAutoExec("IonFury.AutoLoad", true);
|
||||
CreateStandardAutoExec("RedneckRides.AutoLoad", true);
|
||||
CreateStandardAutoExec("Redneck.AutoLoad", true);
|
||||
CreateStandardAutoExec("WW2GI.AutoLoad", true);
|
||||
CreateStandardAutoExec("Nam.AutoLoad", true);
|
||||
CreateStandardAutoExec("DukeNukem3D.AutoLoad", true);
|
||||
|
||||
// Move search paths back to the top.
|
||||
MoveSectionToStart("SoundfontSearch.Directories");
|
||||
MoveSectionToStart("FileSearch.Directories");
|
||||
MoveSectionToStart("IWADSearch.Directories");
|
||||
|
||||
SetSectionNote("DukeNukem3D.AutoExec",
|
||||
"# Files to automatically execute when running the corresponding game.\n"
|
||||
"# Each file should be on its own line, preceded by Path=\n\n");
|
||||
SetSectionNote("Global.Autoload",
|
||||
"# Files to always load. These are loaded after the game data but before\n"
|
||||
"# any files added with -file. Place each file on its own line, preceded\n"
|
||||
"# by Path=\n");
|
||||
SetSectionNote("DukeNukem3D.Autoload",
|
||||
"# Files to automatically load depending on the game you are playing\n\n");
|
||||
}
|
||||
|
||||
void FGameConfigFile::DoGlobalSetup ()
|
||||
{
|
||||
if (SetSection ("GlobalSettings.Unknown"))
|
||||
{
|
||||
//ReadCVars (CVAR_GLOBALCONFIG);
|
||||
}
|
||||
if (SetSection ("GlobalSettings"))
|
||||
{
|
||||
//ReadCVars (CVAR_GLOBALCONFIG);
|
||||
}
|
||||
if (SetSection ("LastRun"))
|
||||
{
|
||||
const char *lastver = GetValueForKey ("Version");
|
||||
if (lastver != NULL)
|
||||
{
|
||||
//double last = atof (lastver);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FGameConfigFile::DoGameSetup (const char *gamename)
|
||||
{
|
||||
const char *key;
|
||||
const char *value;
|
||||
|
||||
sublen = countof(section) - 1 - snprintf (section, countof(section), "%s.", gamename);
|
||||
subsection = section + countof(section) - sublen - 1;
|
||||
section[countof(section) - 1] = '\0';
|
||||
|
||||
strncpy (subsection, "UnknownConsoleVariables", sublen);
|
||||
if (SetSection (section))
|
||||
{
|
||||
ReadCVars (0);
|
||||
}
|
||||
|
||||
strncpy (subsection, "ConsoleVariables", sublen);
|
||||
if (SetSection (section))
|
||||
{
|
||||
ReadCVars (0);
|
||||
}
|
||||
|
||||
// The NetServerInfo section will be read and override anything loaded
|
||||
// here when it's determined that a netgame is being played.
|
||||
#if 0
|
||||
strncpy (subsection, "LocalServerInfo", sublen);
|
||||
if (SetSection (section))
|
||||
{
|
||||
ReadCVars (0);
|
||||
}
|
||||
|
||||
strncpy (subsection, "Player", sublen);
|
||||
if (SetSection (section))
|
||||
{
|
||||
ReadCVars (0);
|
||||
}
|
||||
#endif
|
||||
strncpy (subsection, "ConsoleAliases", sublen);
|
||||
if (SetSection (section))
|
||||
{
|
||||
const char *name = NULL;
|
||||
while (NextInSection (key, value))
|
||||
{
|
||||
if (stricmp (key, "Name") == 0)
|
||||
{
|
||||
name = value;
|
||||
}
|
||||
else if (stricmp (key, "Command") == 0 && name != NULL)
|
||||
{
|
||||
//C_SetAlias (name, value); does not exist yet but will.
|
||||
name = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Moved from DoGameSetup so that it can happen after wads are loaded
|
||||
void FGameConfigFile::DoKeySetup(const char *gamename)
|
||||
{
|
||||
/*
|
||||
static const struct { const char *label; FKeyBindings *bindings; } binders[] =
|
||||
{
|
||||
{ "Bindings", &Bindings },
|
||||
{ "DoubleBindings", &DoubleBindings },
|
||||
{ "AutomapBindings", &AutomapBindings },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
*/
|
||||
const char *key, *value;
|
||||
|
||||
sublen = countof(section) - 1 - snprintf(section, countof(section), "%s.", gamename);
|
||||
subsection = section + countof(section) - sublen - 1;
|
||||
section[countof(section) - 1] = '\0';
|
||||
|
||||
//C_SetDefaultBindings ();
|
||||
|
||||
/*
|
||||
for (int i = 0; binders[i].label != NULL; ++i)
|
||||
{
|
||||
strncpy(subsection, binders[i].label, sublen);
|
||||
if (SetSection(section))
|
||||
{
|
||||
FKeyBindings *bindings = binders[i].bindings;
|
||||
bindings->UnbindAll();
|
||||
while (NextInSection(key, value))
|
||||
{
|
||||
bindings->DoBind(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
OkayToWrite = true;
|
||||
*/
|
||||
}
|
||||
|
||||
void FGameConfigFile::ReadNetVars ()
|
||||
{
|
||||
#if 0
|
||||
strncpy (subsection, "NetServerInfo", sublen);
|
||||
if (SetSection (section))
|
||||
{
|
||||
ReadCVars (0);
|
||||
}
|
||||
if (bModSetup)
|
||||
{
|
||||
mysnprintf(subsection, sublen, "NetServerInfo.Mod");
|
||||
if (SetSection(section))
|
||||
{
|
||||
ReadCVars(CVAR_MOD|CVAR_SERVERINFO|CVAR_IGNORE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Read cvars from a cvar section of the ini. Flags are the flags to give
|
||||
// to newly-created cvars that were not already defined.
|
||||
void FGameConfigFile::ReadCVars (uint32_t flags)
|
||||
{
|
||||
/*
|
||||
const char *key, *value;
|
||||
FBaseCVar *cvar;
|
||||
UCVarValue val;
|
||||
|
||||
flags |= CVAR_ARCHIVE|CVAR_UNSETTABLE|CVAR_AUTO;
|
||||
while (NextInSection (key, value))
|
||||
{
|
||||
cvar = FindCVar (key, NULL);
|
||||
if (cvar == NULL)
|
||||
{
|
||||
cvar = new FStringCVar (key, NULL, flags);
|
||||
}
|
||||
val.String = const_cast<char *>(value);
|
||||
cvar->SetGenericRep (val, CVAR_String);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void FGameConfigFile::ArchiveGameData (const char *gamename)
|
||||
{
|
||||
char section[32*3], *subsection;
|
||||
|
||||
sublen = countof(section) - 1 - snprintf (section, countof(section), "%s.", gamename);
|
||||
subsection = section + countof(section) - 1 - sublen;
|
||||
|
||||
strncpy (subsection, "Player", sublen);
|
||||
SetSection (section, true);
|
||||
ClearCurrentSection ();
|
||||
//C_ArchiveCVars (this, CVAR_ARCHIVE|CVAR_USERINFO);
|
||||
|
||||
strncpy (subsection, "ConsoleVariables", sublen);
|
||||
SetSection (section, true);
|
||||
ClearCurrentSection ();
|
||||
//C_ArchiveCVars (this, CVAR_ARCHIVE);
|
||||
|
||||
#if 0
|
||||
// Do not overwrite the serverinfo section if playing a netgame, and
|
||||
// this machine was not the initial host.
|
||||
if (!netgame || consoleplayer == 0)
|
||||
{
|
||||
strncpy (subsection, netgame ? "NetServerInfo" : "LocalServerInfo", sublen);
|
||||
SetSection (section, true);
|
||||
ClearCurrentSection ();
|
||||
//C_ArchiveCVars (this, CVAR_ARCHIVE|CVAR_SERVERINFO);
|
||||
}
|
||||
#endif
|
||||
|
||||
strncpy (subsection, "UnknownConsoleVariables", sublen);
|
||||
SetSection (section, true);
|
||||
ClearCurrentSection ();
|
||||
//C_ArchiveCVars (this, CVAR_ARCHIVE|CVAR_AUTO);
|
||||
|
||||
strncpy (subsection, "ConsoleAliases", sublen);
|
||||
SetSection (section, true);
|
||||
ClearCurrentSection ();
|
||||
//C_ArchiveAliases (this);
|
||||
|
||||
//M_SaveCustomKeys (this, section, subsection, sublen);
|
||||
|
||||
strcpy (subsection, "Bindings");
|
||||
SetSection (section, true);
|
||||
//Bindings.ArchiveBindings (this);
|
||||
|
||||
strncpy (subsection, "DoubleBindings", sublen);
|
||||
SetSection (section, true);
|
||||
//DoubleBindings.ArchiveBindings (this);
|
||||
|
||||
strncpy (subsection, "AutomapBindings", sublen);
|
||||
SetSection (section, true);
|
||||
//AutomapBindings.ArchiveBindings (this);
|
||||
}
|
||||
|
||||
void FGameConfigFile::ArchiveGlobalData ()
|
||||
{
|
||||
SetSection ("LastRun", true);
|
||||
ClearCurrentSection ();
|
||||
SetValueForKey ("Version", LASTRUNVERSION);
|
||||
|
||||
SetSection ("GlobalSettings", true);
|
||||
ClearCurrentSection ();
|
||||
//C_ArchiveCVars (this, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
|
||||
|
||||
SetSection ("GlobalSettings.Unknown", true);
|
||||
ClearCurrentSection ();
|
||||
//C_ArchiveCVars (this, CVAR_ARCHIVE|CVAR_GLOBALCONFIG|CVAR_AUTO);
|
||||
}
|
||||
|
||||
FString FGameConfigFile::GetConfigPath (bool tryProg)
|
||||
{
|
||||
const char *pathval;
|
||||
|
||||
pathval = Args->CheckValue ("-config");
|
||||
if (pathval != NULL)
|
||||
{
|
||||
return FString(pathval);
|
||||
}
|
||||
return M_GetConfigPath(tryProg);
|
||||
}
|
||||
|
||||
void FGameConfigFile::CreateStandardAutoExec(const char *section, bool start)
|
||||
{
|
||||
if (!SetSection(section))
|
||||
{
|
||||
FString path = M_GetAutoexecPath();
|
||||
SetSection (section, true);
|
||||
SetValueForKey ("Path", path.GetChars());
|
||||
}
|
||||
if (start)
|
||||
{
|
||||
MoveSectionToStart(section);
|
||||
}
|
||||
}
|
||||
|
||||
void FGameConfigFile::AddAutoexec (FArgs *list, const char *game)
|
||||
{
|
||||
char section[64];
|
||||
const char *key;
|
||||
const char *value;
|
||||
|
||||
snprintf (section, countof(section), "%s.AutoExec", game);
|
||||
|
||||
// If <game>.AutoExec section does not exist, create it
|
||||
// with a default autoexec.cfg file present.
|
||||
CreateStandardAutoExec(section, false);
|
||||
// Run any files listed in the <game>.AutoExec section
|
||||
if (!SectionIsEmpty())
|
||||
{
|
||||
while (NextInSection (key, value))
|
||||
{
|
||||
if (stricmp (key, "Path") == 0 && *value != '\0')
|
||||
{
|
||||
FString expanded_path = ExpandEnvVars(value);
|
||||
if (FileExists(expanded_path))
|
||||
{
|
||||
list->AppendArg (ExpandEnvVars(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
CCMD (whereisini)
|
||||
{
|
||||
FString path = M_GetConfigPath(false);
|
||||
Printf ("%s\n", path.GetChars());
|
||||
}
|
||||
*/
|
76
source/common/gameconfigfile.h
Normal file
76
source/common/gameconfigfile.h
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
** gameconfigfile.h
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 1998-2008 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef __GAMECONFIGFILE_H__
|
||||
#define __GAMECONFIGFILE_H__
|
||||
|
||||
#include "configfile.h"
|
||||
|
||||
class FArgs;
|
||||
class FileWriter;
|
||||
|
||||
class FGameConfigFile : public FConfigFile
|
||||
{
|
||||
public:
|
||||
FGameConfigFile ();
|
||||
~FGameConfigFile ();
|
||||
|
||||
void DoAutoloadSetup (/*FIWadManager *iwad_man*/);
|
||||
void DoGlobalSetup ();
|
||||
void DoGameSetup (const char *gamename);
|
||||
void DoKeySetup (const char *gamename);
|
||||
void DoModSetup (const char *gamename);
|
||||
void ArchiveGlobalData ();
|
||||
void ArchiveGameData (const char *gamename);
|
||||
void AddAutoexec (FArgs *list, const char *gamename);
|
||||
FString GetConfigPath (bool tryProg);
|
||||
void ReadNetVars ();
|
||||
|
||||
protected:
|
||||
void WriteCommentHeader (FileWriter *file) const;
|
||||
void CreateStandardAutoExec (const char *section, bool start);
|
||||
|
||||
private:
|
||||
void SetRavenDefaults (bool isHexen);
|
||||
void ReadCVars (unsigned flags);
|
||||
|
||||
bool bModSetup;
|
||||
|
||||
char section[64];
|
||||
char *subsection;
|
||||
size_t sublen;
|
||||
};
|
||||
|
||||
extern FGameConfigFile *GameConfig;
|
||||
|
||||
#endif //__GAMECONFIGFILE_H__
|
18
source/common/i_specialpaths.h
Normal file
18
source/common/i_specialpaths.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#include "zstring.h"
|
||||
|
||||
#ifdef __unix__
|
||||
FString GetUserFile (const char *path);
|
||||
#endif
|
||||
FString M_GetAppDataPath(bool create);
|
||||
FString M_GetAutoexecPath();
|
||||
FString M_GetConfigPath(bool for_reading);
|
||||
FString M_GetScreenshotsPath();
|
||||
FString M_GetSavegamesPath();
|
||||
FString M_GetDocumentsPath();
|
||||
|
||||
#ifdef __APPLE__
|
||||
FString M_GetMacAppSupportPath(const bool create = true);
|
||||
void M_GetMacSearchDirectories(FString& user_docs, FString& user_app_support, FString& local_app_support);
|
||||
#endif // __APPLE__
|
732
source/common/utility/cmdlib.cpp
Normal file
732
source/common/utility/cmdlib.cpp
Normal file
|
@ -0,0 +1,732 @@
|
|||
/*
|
||||
** cmdlib.cpp
|
||||
** Misc utilities (mostly file handling stuff
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 1999-2016 Randy Heit
|
||||
** Copyright 2019 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <pwd.h>
|
||||
#if !defined(__sun)
|
||||
#include <fts.h>
|
||||
#endif
|
||||
#endif
|
||||
#include "cmdlib.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
extern FString progdir;
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// IsSeperator
|
||||
//
|
||||
// Returns true if the character is a path seperator.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static inline bool IsSeperator (int c)
|
||||
{
|
||||
if (c == '/')
|
||||
return true;
|
||||
#ifdef _WIN32
|
||||
if (c == '\\' || c == ':')
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FileExists
|
||||
//
|
||||
// Returns true if the given path exists and is a readable file.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FileExists (const char *filename)
|
||||
{
|
||||
bool isdir;
|
||||
bool res = DirEntryExists(filename, &isdir);
|
||||
return res && !isdir;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DirExists
|
||||
//
|
||||
// Returns true if the given path exists and is a directory.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool DirExists(const char *filename)
|
||||
{
|
||||
bool isdir;
|
||||
bool res = DirEntryExists(filename, &isdir);
|
||||
return res && isdir;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DirEntryExists
|
||||
//
|
||||
// Returns true if the given path exists, be it a directory or a file.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool DirEntryExists(const char *pathname, bool *isdir)
|
||||
{
|
||||
if (isdir) *isdir = false;
|
||||
if (pathname == NULL || *pathname == 0)
|
||||
return false;
|
||||
|
||||
#ifndef _WIN32
|
||||
struct stat info;
|
||||
bool res = stat(pathname, &info) == 0;
|
||||
#else
|
||||
// Windows must use the wide version of stat to preserve non-standard paths.
|
||||
auto wstr = WideString(pathname);
|
||||
struct _stat64i32 info;
|
||||
bool res = _wstat64i32(wstr.c_str(), &info) == 0;
|
||||
#endif
|
||||
if (isdir) *isdir = !!(info.st_mode & S_IFDIR);
|
||||
return res;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// DefaultExtension -- FString version
|
||||
//
|
||||
// Appends the extension to a pathname if it does not already have one.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void DefaultExtension (FString &path, const char *extension)
|
||||
{
|
||||
const char *src = &path[int(path.Len())-1];
|
||||
|
||||
while (src != &path[0] && !IsSeperator(*src))
|
||||
{
|
||||
if (*src == '.')
|
||||
return; // it has an extension
|
||||
src--;
|
||||
}
|
||||
|
||||
path += extension;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ExtractFilePath
|
||||
//
|
||||
// Returns the directory part of a pathname.
|
||||
//
|
||||
// FIXME: should include the slash, otherwise
|
||||
// backing to an empty path will be wrong when appending a slash
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FString ExtractFilePath (const char *path)
|
||||
{
|
||||
const char *src;
|
||||
|
||||
src = path + strlen(path) - 1;
|
||||
|
||||
//
|
||||
// back up until a \ or the start
|
||||
//
|
||||
while (src != path && !IsSeperator(*(src-1)))
|
||||
src--;
|
||||
|
||||
return FString(path, src - path);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ExtractFileBase
|
||||
//
|
||||
// Returns the file part of a pathname, optionally including the extension.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FString ExtractFileBase (const char *path, bool include_extension)
|
||||
{
|
||||
const char *src, *dot;
|
||||
|
||||
src = path + strlen(path) - 1;
|
||||
|
||||
if (src >= path)
|
||||
{
|
||||
// back up until a / or the start
|
||||
while (src != path && !IsSeperator(*(src-1)))
|
||||
src--;
|
||||
|
||||
// Check for files with drive specification but no path
|
||||
#if defined(_WIN32)
|
||||
if (src == path && src[0] != 0)
|
||||
{
|
||||
if (src[1] == ':')
|
||||
src += 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!include_extension)
|
||||
{
|
||||
dot = src;
|
||||
while (*dot && *dot != '.')
|
||||
{
|
||||
dot++;
|
||||
}
|
||||
return FString(src, dot - src);
|
||||
}
|
||||
else
|
||||
{
|
||||
return FString(src);
|
||||
}
|
||||
}
|
||||
return FString();
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// IsNum
|
||||
//
|
||||
// [RH] Returns true if the specified string is a valid decimal number
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool IsNum (const char *str)
|
||||
{
|
||||
while (*str)
|
||||
{
|
||||
if (((*str < '0') || (*str > '9')) && (*str != '-'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
str++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// CheckWildcards
|
||||
//
|
||||
// [RH] Checks if text matches the wildcard pattern using ? or *
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool CheckWildcards (const char *pattern, const char *text)
|
||||
{
|
||||
if (pattern == NULL || text == NULL)
|
||||
return true;
|
||||
|
||||
while (*pattern)
|
||||
{
|
||||
if (*pattern == '*')
|
||||
{
|
||||
char stop = tolower (*++pattern);
|
||||
while (*text && tolower(*text) != stop)
|
||||
{
|
||||
text++;
|
||||
}
|
||||
if (*text && tolower(*text) == stop)
|
||||
{
|
||||
if (CheckWildcards (pattern, text++))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
pattern--;
|
||||
}
|
||||
}
|
||||
else if (*pattern == '?' || tolower(*pattern) == tolower(*text))
|
||||
{
|
||||
pattern++;
|
||||
text++;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return (*pattern | *text) == 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// CreatePath
|
||||
//
|
||||
// Creates a directory including all levels necessary
|
||||
//
|
||||
//==========================================================================
|
||||
#ifdef _WIN32
|
||||
void DoCreatePath(const char *fn)
|
||||
{
|
||||
char drive[_MAX_DRIVE];
|
||||
char dir[_MAX_DIR];
|
||||
_splitpath_s(fn, drive, sizeof drive, dir, sizeof dir, nullptr, 0, nullptr, 0);
|
||||
|
||||
if ('\0' == *dir)
|
||||
{
|
||||
// Root/current/parent directory always exists
|
||||
return;
|
||||
}
|
||||
|
||||
char path[_MAX_PATH];
|
||||
_makepath_s(path, sizeof path, drive, dir, nullptr, nullptr);
|
||||
|
||||
if ('\0' == *path)
|
||||
{
|
||||
// No need to process empty relative path
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove trailing path separator(s)
|
||||
for (size_t i = strlen(path); 0 != i; --i)
|
||||
{
|
||||
char& lastchar = path[i - 1];
|
||||
|
||||
if ('/' == lastchar || '\\' == lastchar)
|
||||
{
|
||||
lastchar = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Create all directories for given path
|
||||
if ('\0' != *path)
|
||||
{
|
||||
DoCreatePath(path);
|
||||
_mkdir(path);
|
||||
}
|
||||
}
|
||||
|
||||
void CreatePath(const char *fn)
|
||||
{
|
||||
char c = fn[strlen(fn)-1];
|
||||
|
||||
if (c != '\\' && c != '/')
|
||||
{
|
||||
FString name(fn);
|
||||
name += '/';
|
||||
DoCreatePath(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
DoCreatePath(fn);
|
||||
}
|
||||
}
|
||||
#else
|
||||
void CreatePath(const char *fn)
|
||||
{
|
||||
char *copy, *p;
|
||||
|
||||
if (fn[0] == '/' && fn[1] == '\0')
|
||||
{
|
||||
return;
|
||||
}
|
||||
p = copy = strdup(fn);
|
||||
do
|
||||
{
|
||||
p = strchr(p + 1, '/');
|
||||
if (p != NULL)
|
||||
{
|
||||
*p = '\0';
|
||||
}
|
||||
if (!DirEntryExists(copy) && mkdir(copy, 0755) == -1)
|
||||
{
|
||||
// failed
|
||||
free(copy);
|
||||
return;
|
||||
}
|
||||
if (p != NULL)
|
||||
{
|
||||
*p = '/';
|
||||
}
|
||||
} while (p);
|
||||
free(copy);
|
||||
}
|
||||
#endif
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// strbin -- In-place version
|
||||
//
|
||||
// [RH] Replaces the escape sequences in a string with actual escaped characters.
|
||||
// This operation is done in-place. The result is the new length of the string.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int strbin (char *str)
|
||||
{
|
||||
char *start = str;
|
||||
char *p = str, c;
|
||||
int i;
|
||||
|
||||
while ( (c = *p++) ) {
|
||||
if (c != '\\') {
|
||||
*str++ = c;
|
||||
} else {
|
||||
switch (*p) {
|
||||
case 'a':
|
||||
*str++ = '\a';
|
||||
break;
|
||||
case 'b':
|
||||
*str++ = '\b';
|
||||
break;
|
||||
case 'c':
|
||||
*str++ = '\034'; // TEXTCOLOR_ESCAPE
|
||||
break;
|
||||
case 'f':
|
||||
*str++ = '\f';
|
||||
break;
|
||||
case 'n':
|
||||
*str++ = '\n';
|
||||
break;
|
||||
case 't':
|
||||
*str++ = '\t';
|
||||
break;
|
||||
case 'r':
|
||||
*str++ = '\r';
|
||||
break;
|
||||
case 'v':
|
||||
*str++ = '\v';
|
||||
break;
|
||||
case '?':
|
||||
*str++ = '\?';
|
||||
break;
|
||||
case '\n':
|
||||
break;
|
||||
case 'x':
|
||||
case 'X':
|
||||
c = 0;
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
p++;
|
||||
if (*p >= '0' && *p <= '9')
|
||||
c = (c << 4) + *p-'0';
|
||||
else if (*p >= 'a' && *p <= 'f')
|
||||
c = (c << 4) + 10 + *p-'a';
|
||||
else if (*p >= 'A' && *p <= 'F')
|
||||
c = (c << 4) + 10 + *p-'A';
|
||||
else
|
||||
{
|
||||
p--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*str++ = c;
|
||||
break;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
c = *p - '0';
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
p++;
|
||||
if (*p >= '0' && *p <= '7')
|
||||
c = (c << 3) + *p - '0';
|
||||
else
|
||||
{
|
||||
p--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*str++ = c;
|
||||
break;
|
||||
default:
|
||||
*str++ = *p;
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
*str = 0;
|
||||
return int(str - start);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// strbin1 -- String-creating version
|
||||
//
|
||||
// [RH] Replaces the escape sequences in a string with actual escaped characters.
|
||||
// The result is a new string.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FString strbin1 (const char *start)
|
||||
{
|
||||
FString result;
|
||||
const char *p = start;
|
||||
char c;
|
||||
int i;
|
||||
|
||||
while ( (c = *p++) ) {
|
||||
if (c != '\\') {
|
||||
result << c;
|
||||
} else {
|
||||
switch (*p) {
|
||||
case 'a':
|
||||
result << '\a';
|
||||
break;
|
||||
case 'b':
|
||||
result << '\b';
|
||||
break;
|
||||
case 'c':
|
||||
result << '\034'; // TEXTCOLOR_ESCAPE
|
||||
break;
|
||||
case 'f':
|
||||
result << '\f';
|
||||
break;
|
||||
case 'n':
|
||||
result << '\n';
|
||||
break;
|
||||
case 't':
|
||||
result << '\t';
|
||||
break;
|
||||
case 'r':
|
||||
result << '\r';
|
||||
break;
|
||||
case 'v':
|
||||
result << '\v';
|
||||
break;
|
||||
case '?':
|
||||
result << '\?';
|
||||
break;
|
||||
case '\n':
|
||||
break;
|
||||
case 'x':
|
||||
case 'X':
|
||||
c = 0;
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
p++;
|
||||
if (*p >= '0' && *p <= '9')
|
||||
c = (c << 4) + *p-'0';
|
||||
else if (*p >= 'a' && *p <= 'f')
|
||||
c = (c << 4) + 10 + *p-'a';
|
||||
else if (*p >= 'A' && *p <= 'F')
|
||||
c = (c << 4) + 10 + *p-'A';
|
||||
else
|
||||
{
|
||||
p--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
result << c;
|
||||
break;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
c = *p - '0';
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
p++;
|
||||
if (*p >= '0' && *p <= '7')
|
||||
c = (c << 3) + *p - '0';
|
||||
else
|
||||
{
|
||||
p--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
result << c;
|
||||
break;
|
||||
default:
|
||||
result << *p;
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// ExpandEnvVars
|
||||
//
|
||||
// Expands environment variable references in a string. Intended primarily
|
||||
// for use with IWAD search paths in config files.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FString ExpandEnvVars(const char *searchpathstring)
|
||||
{
|
||||
static const char envvarnamechars[] =
|
||||
"01234567890"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"_"
|
||||
"abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
if (searchpathstring == NULL)
|
||||
return FString("");
|
||||
|
||||
const char *dollar = strchr(searchpathstring, '$');
|
||||
if (dollar == NULL)
|
||||
{
|
||||
return FString(searchpathstring);
|
||||
}
|
||||
|
||||
const char *nextchars = searchpathstring;
|
||||
FString out = FString(searchpathstring, dollar - searchpathstring);
|
||||
while ( (dollar != NULL) && (*nextchars != 0) )
|
||||
{
|
||||
size_t length = strspn(dollar + 1, envvarnamechars);
|
||||
if (length != 0)
|
||||
{
|
||||
FString varname = FString(dollar + 1, length);
|
||||
if (stricmp(varname, "progdir") == 0)
|
||||
{
|
||||
out += progdir;
|
||||
}
|
||||
else
|
||||
{
|
||||
char *varvalue = getenv(varname);
|
||||
if ( (varvalue != NULL) && (strlen(varvalue) != 0) )
|
||||
{
|
||||
out += varvalue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
out += '$';
|
||||
}
|
||||
nextchars = dollar + length + 1;
|
||||
dollar = strchr(nextchars, '$');
|
||||
if (dollar != NULL)
|
||||
{
|
||||
out += FString(nextchars, dollar - nextchars);
|
||||
}
|
||||
}
|
||||
if (*nextchars != 0)
|
||||
{
|
||||
out += nextchars;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// NicePath
|
||||
//
|
||||
// Handles paths with leading ~ characters on Unix as well as environment
|
||||
// variable substitution. On Windows, this is identical to ExpandEnvVars.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
FString NicePath(const char *path)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return ExpandEnvVars(path);
|
||||
#else
|
||||
if (path == NULL || *path == '\0')
|
||||
{
|
||||
return FString("");
|
||||
}
|
||||
if (*path != '~')
|
||||
{
|
||||
return ExpandEnvVars(path);
|
||||
}
|
||||
|
||||
passwd *pwstruct;
|
||||
const char *slash;
|
||||
|
||||
if (path[1] == '/' || path[1] == '\0')
|
||||
{ // Get my home directory
|
||||
pwstruct = getpwuid(getuid());
|
||||
slash = path + 1;
|
||||
}
|
||||
else
|
||||
{ // Get somebody else's home directory
|
||||
slash = strchr(path, '/');
|
||||
if (slash == NULL)
|
||||
{
|
||||
slash = path + strlen(path);
|
||||
}
|
||||
FString who(path, slash - path);
|
||||
pwstruct = getpwnam(who);
|
||||
}
|
||||
if (pwstruct == NULL)
|
||||
{
|
||||
return ExpandEnvVars(path);
|
||||
}
|
||||
FString where(pwstruct->pw_dir);
|
||||
if (*slash != '\0')
|
||||
{
|
||||
where += ExpandEnvVars(slash);
|
||||
}
|
||||
return where;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool IsAbsPath(const char *name)
|
||||
{
|
||||
if (IsSeperator(name[0])) return true;
|
||||
#ifdef _WIN32
|
||||
/* [A-Za-z]: (for Windows) */
|
||||
if (isalpha(name[0]) && name[1] == ':') return true;
|
||||
#endif /* _WIN32 */
|
||||
return 0;
|
||||
}
|
56
source/common/utility/cmdlib.h
Normal file
56
source/common/utility/cmdlib.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
// cmdlib.h
|
||||
|
||||
#ifndef __CMDLIB__
|
||||
#define __CMDLIB__
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include "zstring.h"
|
||||
|
||||
template <typename T, size_t N>
|
||||
char(&_ArraySizeHelper(T(&array)[N]))[N];
|
||||
|
||||
#define countof( array ) (sizeof( _ArraySizeHelper( array ) ))
|
||||
|
||||
// the dec offsetof macro doesnt work very well...
|
||||
#define myoffsetof(type,identifier) ((size_t)&((type *)alignof(type))->identifier - alignof(type))
|
||||
|
||||
bool FileExists (const char *filename);
|
||||
bool DirExists(const char *filename);
|
||||
bool DirEntryExists (const char *pathname, bool *isdir = nullptr);
|
||||
|
||||
extern FString progdir;
|
||||
|
||||
void DefaultExtension (FString &path, const char *extension);
|
||||
|
||||
FString ExtractFilePath (const char *path);
|
||||
FString ExtractFileBase (const char *path, bool keep_extension=false);
|
||||
|
||||
struct FScriptPosition;
|
||||
bool IsNum (const char *str); // [RH] added
|
||||
|
||||
bool CheckWildcards (const char *pattern, const char *text);
|
||||
|
||||
int strbin (char *str);
|
||||
FString strbin1 (const char *start);
|
||||
|
||||
void CreatePath(const char * fn);
|
||||
|
||||
FString ExpandEnvVars(const char *searchpathstring);
|
||||
FString NicePath(const char *path);
|
||||
|
||||
struct FFileList
|
||||
{
|
||||
FString Filename;
|
||||
bool isDirectory;
|
||||
};
|
||||
|
||||
bool IsAbsPath(const char*);
|
||||
|
||||
|
||||
#endif
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
#include <string.h>
|
||||
#include "m_argv.h"
|
||||
#include "zstring.h"
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
|
@ -84,7 +85,7 @@ FArgs::FArgs(int argc, const char** argv)
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
FArgs::FArgs(int argc, const std::string *argv)
|
||||
FArgs::FArgs(int argc, FString *argv)
|
||||
{
|
||||
AppendArgs(argc, argv);
|
||||
}
|
||||
|
@ -111,7 +112,7 @@ FArgs &FArgs::operator=(const FArgs &other)
|
|||
|
||||
void FArgs::SetArgs(int argc, char **argv)
|
||||
{
|
||||
Argv.resize(argc);
|
||||
Argv.Resize(argc);
|
||||
for (int i = 0; i < argc; ++i)
|
||||
{
|
||||
Argv[i] = argv[i];
|
||||
|
@ -126,7 +127,7 @@ void FArgs::SetArgs(int argc, char **argv)
|
|||
|
||||
void FArgs::FlushArgs()
|
||||
{
|
||||
Argv.clear();
|
||||
Argv.Clear();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
@ -140,9 +141,9 @@ void FArgs::FlushArgs()
|
|||
|
||||
int FArgs::CheckParm(const char *check, int start) const
|
||||
{
|
||||
for (unsigned i = start; i < Argv.size(); ++i)
|
||||
for (unsigned i = start; i < Argv.Size(); ++i)
|
||||
{
|
||||
if (0 == stricmp(check, Argv[i].c_str()))
|
||||
if (0 == stricmp(check, Argv[i]))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
@ -159,7 +160,7 @@ int FArgs::CheckParm(const char *check, int start) const
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
int FArgs::CheckParmList(const char *check, const std::string **strings, int start) const
|
||||
int FArgs::CheckParmList(const char *check, FString **strings, int start) const
|
||||
{
|
||||
unsigned int i, parmat = CheckParm(check, start);
|
||||
|
||||
|
@ -171,7 +172,7 @@ int FArgs::CheckParmList(const char *check, const std::string **strings, int sta
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
for (i = ++parmat; i < Argv.size(); ++i)
|
||||
for (i = ++parmat; i < Argv.Size(); ++i)
|
||||
{
|
||||
if (Argv[i][0] == '-' || Argv[i][1] == '+')
|
||||
{
|
||||
|
@ -198,10 +199,10 @@ const char *FArgs::CheckValue(const char *check) const
|
|||
{
|
||||
int i = CheckParm(check);
|
||||
|
||||
if (i > 0 && i < (int)Argv.size() - 1)
|
||||
if (i > 0 && i < (int)Argv.Size() - 1)
|
||||
{
|
||||
i++;
|
||||
return Argv[i][0] != '+' && Argv[i][0] != '-' ? Argv[i].c_str() : nullptr;
|
||||
return Argv[i][0] != '+' && Argv[i][0] != '-' ? Argv[i].GetChars() : nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -218,21 +219,21 @@ const char *FArgs::CheckValue(const char *check) const
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
std::string FArgs::TakeValue(const char *check)
|
||||
FString FArgs::TakeValue(const char *check)
|
||||
{
|
||||
int i = CheckParm(check);
|
||||
std::string out;
|
||||
FString out;
|
||||
|
||||
if (i > 0 && i < (int)Argv.size())
|
||||
if (i > 0 && i < (int)Argv.Size())
|
||||
{
|
||||
if (i < (int)Argv.size() - 1 && Argv[i+1][0] != '+' && Argv[i+1][0] != '-')
|
||||
if (i < (int)Argv.Size() - 1 && Argv[i+1][0] != '+' && Argv[i+1][0] != '-')
|
||||
{
|
||||
out = Argv[i+1];
|
||||
Argv.erase(Argv.begin() + i, Argv.begin() + (i+2)); // Delete the parm and its value.
|
||||
Argv.Delete(i, 2); // Delete the parm and its value.
|
||||
}
|
||||
else
|
||||
{
|
||||
Argv.erase(Argv.begin() + i); // Just delete the parm, since it has no value.
|
||||
Argv.Delete(i); // Just delete the parm, since it has no value.
|
||||
}
|
||||
}
|
||||
return out;
|
||||
|
@ -248,13 +249,13 @@ void FArgs::RemoveArgs(const char *check)
|
|||
{
|
||||
int i = CheckParm(check);
|
||||
|
||||
if (i > 0 && i < (int)Argv.size() - 1)
|
||||
if (i > 0 && i < (int)Argv.Size() - 1)
|
||||
{
|
||||
do
|
||||
{
|
||||
RemoveArg(i);
|
||||
}
|
||||
while (Argv[i][0] != '+' && Argv[i][0] != '-' && i < (int)Argv.size() - 1);
|
||||
while (Argv[i][0] != '+' && Argv[i][0] != '-' && i < (int)Argv.Size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -268,20 +269,20 @@ void FArgs::RemoveArgs(const char *check)
|
|||
|
||||
const char *FArgs::GetArg(int arg) const
|
||||
{
|
||||
return ((unsigned)arg < Argv.size()) ? Argv[arg].c_str() : nullptr;
|
||||
return ((unsigned)arg < Argv.Size()) ? Argv[arg].GetChars() : nullptr;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FArgs :: GetArgList
|
||||
//
|
||||
// Returns a pointer to the std::string at a particular position.
|
||||
// Returns a pointer to the FString at a particular position.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
const std::string *FArgs::GetArgList(int arg) const
|
||||
FString *FArgs::GetArgList(int arg) const
|
||||
{
|
||||
return ((unsigned)arg < Argv.size()) ? &Argv[arg] : nullptr;
|
||||
return ((unsigned)arg < Argv.Size()) ? &Argv[arg] : nullptr;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
@ -292,7 +293,7 @@ const std::string *FArgs::GetArgList(int arg) const
|
|||
|
||||
int FArgs::NumArgs() const
|
||||
{
|
||||
return (int)Argv.size();
|
||||
return (int)Argv.Size();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
@ -304,26 +305,27 @@ int FArgs::NumArgs() const
|
|||
//
|
||||
//===========================================================================
|
||||
|
||||
void FArgs::AppendArg(std::string arg)
|
||||
void FArgs::AppendArg(FString arg)
|
||||
{
|
||||
Argv.push_back(arg);
|
||||
Argv.Push(arg);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FArgs :: AppendArgs
|
||||
//
|
||||
// Adds an array of std::strings to argv.
|
||||
// Adds an array of FStrings to argv.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
void FArgs::AppendArgs(int argc, const std::string *argv)
|
||||
void FArgs::AppendArgs(int argc, const FString *argv)
|
||||
{
|
||||
if (argv != nullptr && argc > 0)
|
||||
if (argv != NULL && argc > 0)
|
||||
{
|
||||
Argv.Grow(argc);
|
||||
for (int i = 0; i < argc; ++i)
|
||||
{
|
||||
Argv.push_back(argv[i]);
|
||||
Argv.Push(argv[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -338,7 +340,7 @@ void FArgs::AppendArgs(int argc, const std::string *argv)
|
|||
|
||||
void FArgs::RemoveArg(int argindex)
|
||||
{
|
||||
Argv.erase(Argv.begin() + argindex);
|
||||
Argv.Delete(argindex);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
|
@ -354,19 +356,19 @@ void FArgs::RemoveArg(int argindex)
|
|||
|
||||
void FArgs::CollectFiles(const char *param, const char *extension)
|
||||
{
|
||||
std::vector<std::string> work;
|
||||
TArray<FString> work;
|
||||
unsigned int i;
|
||||
size_t extlen = extension == nullptr ? 0 : strlen(extension);
|
||||
|
||||
// Step 1: Find suitable arguments before the first switch.
|
||||
i = 1;
|
||||
while (i < Argv.size() && Argv[i][0] != '-' && Argv[i][0] != '+')
|
||||
while (i < Argv.Size() && Argv[i][0] != '-' && Argv[i][0] != '+')
|
||||
{
|
||||
bool useit;
|
||||
|
||||
if (extlen > 0)
|
||||
{ // Argument's extension must match.
|
||||
size_t len = Argv[i].length();
|
||||
size_t len = Argv[i].Len();
|
||||
useit = (len >= extlen && stricmp(&Argv[i][len - extlen], extension) == 0);
|
||||
}
|
||||
else
|
||||
|
@ -375,8 +377,8 @@ void FArgs::CollectFiles(const char *param, const char *extension)
|
|||
}
|
||||
if (useit)
|
||||
{
|
||||
work.push_back(Argv[i]);
|
||||
RemoveArg(i);
|
||||
work.Push(Argv[i]);
|
||||
Argv.Delete(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -387,11 +389,11 @@ void FArgs::CollectFiles(const char *param, const char *extension)
|
|||
// Step 2: Find each occurence of -param and add its arguments to work.
|
||||
while ((i = CheckParm(param, i)) > 0)
|
||||
{
|
||||
RemoveArg(i);
|
||||
while (i < Argv.size() && Argv[i][0] != '-' && Argv[i][0] != '+')
|
||||
Argv.Delete(i);
|
||||
while (i < Argv.Size() && Argv[i][0] != '-' && Argv[i][0] != '+')
|
||||
{
|
||||
work.push_back(Argv[i]);
|
||||
RemoveArg(i);
|
||||
work.Push(Argv[i]);
|
||||
Argv.Delete(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -404,10 +406,10 @@ void FArgs::CollectFiles(const char *param, const char *extension)
|
|||
#endif
|
||||
|
||||
// Step 3: Add work back to Argv, as long as it's non-empty.
|
||||
if (work.size() > 0)
|
||||
if (work.Size() > 0)
|
||||
{
|
||||
Argv.push_back(param);
|
||||
AppendArgs(work.size(), &work[0]);
|
||||
Argv.Push(param);
|
||||
AppendArgs(work.Size(), &work[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -423,7 +425,7 @@ void FArgs::CollectFiles(const char *param, const char *extension)
|
|||
|
||||
FArgs *FArgs::GatherFiles(const char *param) const
|
||||
{
|
||||
const std::string *files;
|
||||
FString *files;
|
||||
int filecount;
|
||||
|
||||
filecount = CheckParmList(param, &files);
|
||||
|
|
|
@ -34,8 +34,8 @@
|
|||
#ifndef __M_ARGV_H__
|
||||
#define __M_ARGV_H__
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "tarray.h"
|
||||
#include "zstring.h"
|
||||
|
||||
//
|
||||
// MISC
|
||||
|
@ -47,12 +47,12 @@ public:
|
|||
FArgs(const FArgs &args);
|
||||
FArgs(int argc, char **argv);
|
||||
FArgs(int argc, const char** argv);
|
||||
FArgs(int argc, const std::string *argv);
|
||||
FArgs(int argc, FString *argv);
|
||||
|
||||
FArgs &operator=(const FArgs &other);
|
||||
|
||||
void AppendArg(std::string arg);
|
||||
void AppendArgs(int argc, const std::string *argv);
|
||||
void AppendArg(FString arg);
|
||||
void AppendArgs(int argc, const FString *argv);
|
||||
void RemoveArg(int argindex);
|
||||
void RemoveArgs(const char *check);
|
||||
void SetArgs(int argc, char **argv);
|
||||
|
@ -61,16 +61,16 @@ public:
|
|||
void SetArg(int argnum, const char *arg);
|
||||
|
||||
int CheckParm(const char *check, int start=1) const; // Returns the position of the given parameter in the arg list (0 if not found).
|
||||
int CheckParmList(const char *check, const std::string **strings, int start=1) const;
|
||||
int CheckParmList(const char *check, FString **strings, int start=1) const;
|
||||
const char *CheckValue(const char *check) const;
|
||||
const char *GetArg(int arg) const;
|
||||
const std::string *GetArgList(int arg) const;
|
||||
std::string TakeValue(const char *check);
|
||||
FString *GetArgList(int arg) const;
|
||||
FString TakeValue(const char *check);
|
||||
int NumArgs() const;
|
||||
void FlushArgs();
|
||||
|
||||
private:
|
||||
std::vector<std::string> Argv;
|
||||
TArray<FString> Argv;
|
||||
};
|
||||
|
||||
extern FArgs *Args;
|
||||
|
|
|
@ -6332,7 +6332,7 @@ int G_FPSLimit(void)
|
|||
EDUKE32_STATIC_ASSERT(sizeof(actor_t)%4 == 0);
|
||||
EDUKE32_STATIC_ASSERT(sizeof(DukePlayer_t)%4 == 0);
|
||||
|
||||
int app_main()
|
||||
int app_main(int argc, const char * const*argv)
|
||||
{
|
||||
#ifndef NETCODE_DISABLE
|
||||
if (enet_initialize() != 0)
|
||||
|
|
|
@ -1724,8 +1724,6 @@ void G_SetupFilenameBasedMusic(char *nameBuf, const char *fileName)
|
|||
|
||||
for (auto & ext : exts)
|
||||
{
|
||||
buildvfs_kfd kFile;
|
||||
|
||||
Bmemcpy(p+1, ext, Bstrlen(ext) + 1);
|
||||
|
||||
if (testkopen(nameBuf, 0))
|
||||
|
|
|
@ -1463,8 +1463,6 @@ void gameDisplay3DRScreen()
|
|||
if (testkopen("3dr.ivf", 0) || testkopen("3dr.anm", 0))
|
||||
{
|
||||
Anim_Play("3dr.anm");
|
||||
kclose(i);
|
||||
Anim_Play("3dr.anm");
|
||||
G_FadePalette(0, 0, 0, 252);
|
||||
I_ClearAllInput();
|
||||
}
|
||||
|
|
222
source/platform/macos/i_specialpaths.mm
Normal file
222
source/platform/macos/i_specialpaths.mm
Normal file
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
** i_specialpaths.mm
|
||||
** Gets special system folders where data should be stored. (macOS version)
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2013-2016 Randy Heit
|
||||
** Copyright 2016 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#import <Foundation/NSFileManager.h>
|
||||
|
||||
#include "cmdlib.h"
|
||||
#include "m_misc.h"
|
||||
#include "version.h" // for GAMENAME
|
||||
|
||||
|
||||
static FString GetSpecialPath(const NSSearchPathDirectory kind, const BOOL create = YES, const NSSearchPathDomainMask domain = NSUserDomainMask)
|
||||
{
|
||||
NSURL* url = [[NSFileManager defaultManager] URLForDirectory:kind
|
||||
inDomain:domain
|
||||
appropriateForURL:nil
|
||||
create:create
|
||||
error:nil];
|
||||
char utf8path[PATH_MAX];
|
||||
|
||||
if ([url getFileSystemRepresentation:utf8path
|
||||
maxLength:sizeof utf8path])
|
||||
{
|
||||
return utf8path;
|
||||
}
|
||||
|
||||
return FString();
|
||||
}
|
||||
|
||||
FString M_GetMacAppSupportPath(const bool create)
|
||||
{
|
||||
return GetSpecialPath(NSApplicationSupportDirectory, create);
|
||||
}
|
||||
|
||||
void M_GetMacSearchDirectories(FString& user_docs, FString& user_app_support, FString& local_app_support)
|
||||
{
|
||||
FString path = GetSpecialPath(NSDocumentDirectory);
|
||||
user_docs = path.IsEmpty()
|
||||
? "~/" GAME_DIR
|
||||
: (path + "/" GAME_DIR);
|
||||
|
||||
#define LIBRARY_APPSUPPORT "/Library/Application Support/"
|
||||
|
||||
path = M_GetMacAppSupportPath();
|
||||
user_app_support = path.IsEmpty()
|
||||
? "~" LIBRARY_APPSUPPORT GAME_DIR
|
||||
: (path + "/" GAME_DIR);
|
||||
|
||||
path = GetSpecialPath(NSApplicationSupportDirectory, YES, NSLocalDomainMask);
|
||||
local_app_support = path.IsEmpty()
|
||||
? LIBRARY_APPSUPPORT GAME_DIR
|
||||
: (path + "/" GAME_DIR);
|
||||
|
||||
#undef LIBRARY_APPSUPPORT
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetAppDataPath macOS
|
||||
//
|
||||
// Returns the path for the AppData folder.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetAppDataPath(bool create)
|
||||
{
|
||||
FString path = M_GetMacAppSupportPath(create);
|
||||
|
||||
if (path.IsEmpty())
|
||||
{
|
||||
path = progdir;
|
||||
}
|
||||
|
||||
path += "/" GAMENAMELOWERCASE;
|
||||
if (create) CreatePath(path);
|
||||
return path;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetAutoexecPath macOS
|
||||
//
|
||||
// Returns the expected location of autoexec.cfg.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetAutoexecPath()
|
||||
{
|
||||
FString path = GetSpecialPath(NSDocumentDirectory);
|
||||
|
||||
if (path.IsNotEmpty())
|
||||
{
|
||||
path += "/" GAME_DIR "/autoexec.cfg";
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetConfigPath macOS
|
||||
//
|
||||
// Returns the path to the config file. On Windows, this can vary for reading
|
||||
// vs writing. i.e. If $PROGDIR/zdoom-<user>.ini does not exist, it will try
|
||||
// to read from $PROGDIR/zdoom.ini, but it will never write to zdoom.ini.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetConfigPath(bool for_reading)
|
||||
{
|
||||
FString path = GetSpecialPath(NSLibraryDirectory);
|
||||
|
||||
if (path.IsNotEmpty())
|
||||
{
|
||||
// There seems to be no way to get Preferences path via NSFileManager
|
||||
path += "/Preferences/";
|
||||
CreatePath(path);
|
||||
|
||||
if (!DirExists(path))
|
||||
{
|
||||
path = FString();
|
||||
}
|
||||
}
|
||||
|
||||
return path + GAMENAMELOWERCASE ".ini";
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetScreenshotsPath macOS
|
||||
//
|
||||
// Returns the path to the default screenshots directory.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetScreenshotsPath()
|
||||
{
|
||||
FString path = GetSpecialPath(NSDocumentDirectory);
|
||||
|
||||
if (path.IsEmpty())
|
||||
{
|
||||
path = "~/";
|
||||
}
|
||||
else
|
||||
{
|
||||
path += "/" GAME_DIR "/Screenshots/";
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetSavegamesPath macOS
|
||||
//
|
||||
// Returns the path to the default save games directory.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetSavegamesPath()
|
||||
{
|
||||
FString path = GetSpecialPath(NSDocumentDirectory);
|
||||
|
||||
if (path.IsNotEmpty())
|
||||
{
|
||||
path += "/" GAME_DIR "/Savegames/";
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetDocumentsPath macOS
|
||||
//
|
||||
// Returns the path to the default documents directory.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetDocumentsPath()
|
||||
{
|
||||
FString path = GetSpecialPath(NSDocumentDirectory);
|
||||
|
||||
if (path.IsNotEmpty())
|
||||
{
|
||||
path += "/" GAME_DIR "/";
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
187
source/platform/unix/i_specialpaths.cpp
Normal file
187
source/platform/unix/i_specialpaths.cpp
Normal file
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
** i_specialpaths.cpp
|
||||
** Gets special system folders where data should be stored. (Unix version)
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2013-2016 Randy Heit
|
||||
** Copyright 2016 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include "i_system.h"
|
||||
#include "cmdlib.h"
|
||||
#include "doomerrors.h"
|
||||
|
||||
#include "version.h" // for GAMENAME
|
||||
|
||||
|
||||
FString GetUserFile (const char *file)
|
||||
{
|
||||
FString path;
|
||||
struct stat info;
|
||||
|
||||
path = NicePath("$HOME/" GAME_DIR "/");
|
||||
|
||||
if (stat (path, &info) == -1)
|
||||
{
|
||||
struct stat extrainfo;
|
||||
|
||||
// Sanity check for $HOME/.config
|
||||
FString configPath = NicePath("$HOME/.config/");
|
||||
if (stat (configPath, &extrainfo) == -1)
|
||||
{
|
||||
if (mkdir (configPath, S_IRUSR | S_IWUSR | S_IXUSR) == -1)
|
||||
{
|
||||
I_FatalError ("Failed to create $HOME/.config directory:\n%s", strerror(errno));
|
||||
}
|
||||
}
|
||||
else if (!S_ISDIR(extrainfo.st_mode))
|
||||
{
|
||||
I_FatalError ("$HOME/.config must be a directory");
|
||||
}
|
||||
|
||||
// This can be removed after a release or two
|
||||
// Transfer the old zdoom directory to the new location
|
||||
bool moved = false;
|
||||
FString oldpath = NicePath("$HOME/." GAMENAMELOWERCASE "/");
|
||||
if (stat (oldpath, &extrainfo) != -1)
|
||||
{
|
||||
if (rename(oldpath, path) == -1)
|
||||
{
|
||||
I_Error ("Failed to move old " GAMENAMELOWERCASE " directory (%s) to new location (%s).",
|
||||
oldpath.GetChars(), path.GetChars());
|
||||
}
|
||||
else
|
||||
moved = true;
|
||||
}
|
||||
|
||||
if (!moved && mkdir (path, S_IRUSR | S_IWUSR | S_IXUSR) == -1)
|
||||
{
|
||||
I_FatalError ("Failed to create %s directory:\n%s",
|
||||
path.GetChars(), strerror (errno));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!S_ISDIR(info.st_mode))
|
||||
{
|
||||
I_FatalError ("%s must be a directory", path.GetChars());
|
||||
}
|
||||
}
|
||||
path += file;
|
||||
return path;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetAppDataPath Unix
|
||||
//
|
||||
// Returns the path for the AppData folder.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetAppDataPath(bool create)
|
||||
{
|
||||
// Don't use GAME_DIR and such so that ZDoom and its child ports can
|
||||
// share the node cache.
|
||||
FString path = NicePath("$HOME/.config/" GAMENAMELOWERCASE);
|
||||
if (create)
|
||||
{
|
||||
CreatePath(path);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetAutoexecPath Unix
|
||||
//
|
||||
// Returns the expected location of autoexec.cfg.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetAutoexecPath()
|
||||
{
|
||||
return GetUserFile("autoexec.cfg");
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetConfigPath Unix
|
||||
//
|
||||
// Returns the path to the config file. On Windows, this can vary for reading
|
||||
// vs writing. i.e. If $PROGDIR/zdoom-<user>.ini does not exist, it will try
|
||||
// to read from $PROGDIR/zdoom.ini, but it will never write to zdoom.ini.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetConfigPath(bool for_reading)
|
||||
{
|
||||
return GetUserFile(GAMENAMELOWERCASE ".ini");
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetScreenshotsPath Unix
|
||||
//
|
||||
// Returns the path to the default screenshots directory.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetScreenshotsPath()
|
||||
{
|
||||
return NicePath("$HOME/" GAME_DIR "/screenshots/");
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetSavegamesPath Unix
|
||||
//
|
||||
// Returns the path to the default save games directory.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetSavegamesPath()
|
||||
{
|
||||
return NicePath("$HOME/" GAME_DIR);
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetDocumentsPath Unix
|
||||
//
|
||||
// Returns the path to the default documents directory.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetDocumentsPath()
|
||||
{
|
||||
return NicePath("$HOME/" GAME_DIR);
|
||||
}
|
336
source/platform/win32/i_specialpaths.cpp
Normal file
336
source/platform/win32/i_specialpaths.cpp
Normal file
|
@ -0,0 +1,336 @@
|
|||
/*
|
||||
** i_specialpaths.cpp
|
||||
** Gets special system folders where data should be stored. (Windows version)
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2013-2016 Randy Heit
|
||||
** Copyright 2016 Christoph Oelckers
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <lmcons.h>
|
||||
#include <shlobj.h>
|
||||
|
||||
#include "i_specialpaths.h"
|
||||
#include "printf.h"
|
||||
#include "cmdlib.h"
|
||||
//#include "version.h" // for GAMENAME
|
||||
|
||||
// Stuff that needs to be set up later.
|
||||
extern FString progdir;
|
||||
static bool batchrun;
|
||||
#define GAMENAMELOWERCASE "demolition"
|
||||
#define GAMENAME "Demolition"
|
||||
#define GAME_DIR "demolition"
|
||||
|
||||
// Vanilla MinGW does not have folder ids
|
||||
#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
|
||||
static const GUID FOLDERID_LocalAppData = { 0xf1b32785, 0x6fba, 0x4fcf, 0x9d, 0x55, 0x7b, 0x8e, 0x7f, 0x15, 0x70, 0x91 };
|
||||
static const GUID FOLDERID_RoamingAppData = { 0x3eb685db, 0x65f9, 0x4cf6, 0xa0, 0x3a, 0xe3, 0xef, 0x65, 0x72, 0x9f, 0x3d };
|
||||
static const GUID FOLDERID_SavedGames = { 0x4c5c32ff, 0xbb9d, 0x43b0, 0xb5, 0xb4, 0x2d, 0x72, 0xe5, 0x4e, 0xaa, 0xa4 };
|
||||
static const GUID FOLDERID_Documents = { 0xfdd39ad0, 0x238f, 0x46af, 0xad, 0xb4, 0x6c, 0x85, 0x48, 0x03, 0x69, 0xc7 };
|
||||
static const GUID FOLDERID_Pictures = { 0x33e28130, 0x4e1e, 0x4676, 0x83, 0x5a, 0x98, 0x39, 0x5c, 0x3b, 0xc3, 0xbb };
|
||||
#endif
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// IsProgramDirectoryWritable
|
||||
//
|
||||
// If the program directory is writable, then dump everything in there for
|
||||
// historical reasons. Otherwise, known folders get used instead.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool UseKnownFolders()
|
||||
{
|
||||
// Cache this value so the semantics don't change during a single run
|
||||
// of the program. (e.g. Somebody could add write access while the
|
||||
// program is running.)
|
||||
static int iswritable = -1;
|
||||
HANDLE file;
|
||||
|
||||
if (iswritable >= 0)
|
||||
{
|
||||
return !iswritable;
|
||||
}
|
||||
std::wstring testpath = progdir.WideString() + L"writest";
|
||||
file = CreateFile(testpath.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL,
|
||||
CREATE_ALWAYS,
|
||||
FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL);
|
||||
if (file != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(file);
|
||||
if (!batchrun) Printf("Using program directory for storage\n");
|
||||
iswritable = true;
|
||||
return false;
|
||||
}
|
||||
if (!batchrun) Printf("Using known folders for storage\n");
|
||||
iswritable = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// GetKnownFolder
|
||||
//
|
||||
// Returns the known_folder if SHGetKnownFolderPath is available, otherwise
|
||||
// returns the shell_folder using SHGetFolderPath.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool GetKnownFolder(int shell_folder, REFKNOWNFOLDERID known_folder, bool create, FString &path)
|
||||
{
|
||||
PWSTR wpath;
|
||||
if (FAILED(SHGetKnownFolderPath(known_folder, create ? KF_FLAG_CREATE : 0, NULL, &wpath)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
path = wpath;
|
||||
CoTaskMemFree(wpath);
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetAppDataPath Windows
|
||||
//
|
||||
// Returns the path for the AppData folder.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetAppDataPath(bool create)
|
||||
{
|
||||
FString path;
|
||||
|
||||
if (!GetKnownFolder(CSIDL_LOCAL_APPDATA, FOLDERID_LocalAppData, create, path))
|
||||
{ // Failed (e.g. On Win9x): use program directory
|
||||
path = progdir;
|
||||
}
|
||||
// Don't use GAME_DIR and such so that demolition and its child ports can
|
||||
// share the node cache.
|
||||
path += "/" GAMENAMELOWERCASE;
|
||||
path.Substitute("//", "/"); // needed because progdir ends with a slash.
|
||||
if (create)
|
||||
{
|
||||
CreatePath(path);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetAutoexecPath Windows
|
||||
//
|
||||
// Returns the expected location of autoexec.cfg.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetAutoexecPath()
|
||||
{
|
||||
return "$PROGDIR/autoexec.cfg";
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetConfigPath Windows
|
||||
//
|
||||
// Returns the path to the config file. On Windows, this can vary for reading
|
||||
// vs writing. i.e. If $PROGDIR/demolition-<user>.ini does not exist, it will try
|
||||
// to read from $PROGDIR/demolition.ini, but it will never write to demolition.ini.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetConfigPath(bool for_reading)
|
||||
{
|
||||
FString path;
|
||||
HRESULT hr;
|
||||
|
||||
path.Format("%s" GAMENAMELOWERCASE "_portable.ini", progdir.GetChars());
|
||||
if (FileExists(path))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
path = "";
|
||||
|
||||
// Construct a user-specific config name
|
||||
if (UseKnownFolders() && GetKnownFolder(CSIDL_APPDATA, FOLDERID_RoamingAppData, true, path))
|
||||
{
|
||||
path += "/" GAME_DIR;
|
||||
CreatePath(path);
|
||||
path += "/" GAMENAMELOWERCASE ".ini";
|
||||
}
|
||||
else
|
||||
{ // construct "$PROGDIR/demolition-$USER.ini"
|
||||
WCHAR uname[UNLEN+1];
|
||||
DWORD unamelen = UNLEN;
|
||||
|
||||
path = progdir;
|
||||
hr = GetUserNameW(uname, &unamelen);
|
||||
if (SUCCEEDED(hr) && uname[0] != 0)
|
||||
{
|
||||
// Is it valid for a user name to have slashes?
|
||||
// Check for them and substitute just in case.
|
||||
auto probe = uname;
|
||||
while (*probe != 0)
|
||||
{
|
||||
if (*probe == '\\' || *probe == '/')
|
||||
*probe = '_';
|
||||
++probe;
|
||||
}
|
||||
path << GAMENAMELOWERCASE "-" << FString(uname) << ".ini";
|
||||
}
|
||||
else
|
||||
{ // Couldn't get user name, so just use demolition.ini
|
||||
path += GAMENAMELOWERCASE ".ini";
|
||||
}
|
||||
}
|
||||
|
||||
// If we are reading the config file, check if it exists. If not, fallback
|
||||
// to $PROGDIR/demolition.ini
|
||||
if (for_reading)
|
||||
{
|
||||
if (!FileExists(path))
|
||||
{
|
||||
path = progdir;
|
||||
path << GAMENAMELOWERCASE ".ini";
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetScreenshotsPath Windows
|
||||
//
|
||||
// Returns the path to the default screenshots directory.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
// I'm not sure when FOLDERID_Screenshots was added, but it was probably
|
||||
// for Windows 8, since it's not in the v7.0 Windows SDK.
|
||||
static const GUID MyFOLDERID_Screenshots = { 0xb7bede81, 0xdf94, 0x4682, 0xa7, 0xd8, 0x57, 0xa5, 0x26, 0x20, 0xb8, 0x6f };
|
||||
|
||||
FString M_GetScreenshotsPath()
|
||||
{
|
||||
FString path;
|
||||
|
||||
if (!UseKnownFolders())
|
||||
{
|
||||
return progdir;
|
||||
}
|
||||
else if (GetKnownFolder(-1, MyFOLDERID_Screenshots, true, path))
|
||||
{
|
||||
path << "/" GAMENAME;
|
||||
}
|
||||
else if (GetKnownFolder(CSIDL_MYPICTURES, FOLDERID_Pictures, true, path))
|
||||
{
|
||||
path << "/Screenshots/" GAMENAME;
|
||||
}
|
||||
else
|
||||
{
|
||||
return progdir;
|
||||
}
|
||||
CreatePath(path);
|
||||
return path;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetSavegamesPath Windows
|
||||
//
|
||||
// Returns the path to the default save games directory.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetSavegamesPath()
|
||||
{
|
||||
FString path;
|
||||
|
||||
if (!UseKnownFolders())
|
||||
{
|
||||
return progdir;
|
||||
}
|
||||
// Try standard Saved Games folder
|
||||
else if (GetKnownFolder(-1, FOLDERID_SavedGames, true, path))
|
||||
{
|
||||
path << "/" GAMENAME;
|
||||
}
|
||||
// Try defacto My Documents/My Games folder
|
||||
else if (GetKnownFolder(CSIDL_PERSONAL, FOLDERID_Documents, true, path))
|
||||
{
|
||||
// I assume since this isn't a standard folder, it doesn't have
|
||||
// a localized name either.
|
||||
path << "/My Games/" GAMENAME;
|
||||
CreatePath(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
path = progdir;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// M_GetDocumentsPath Windows
|
||||
//
|
||||
// Returns the path to the default documents directory.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
FString M_GetDocumentsPath()
|
||||
{
|
||||
FString path;
|
||||
|
||||
// A portable INI means that this storage location should also be portable.
|
||||
path.Format("%s" GAMENAME "_portable.ini", progdir.GetChars());
|
||||
if (FileExists(path))
|
||||
{
|
||||
return progdir;
|
||||
}
|
||||
|
||||
if (!UseKnownFolders())
|
||||
{
|
||||
return progdir;
|
||||
}
|
||||
// Try defacto My Documents/My Games folder
|
||||
else if (GetKnownFolder(CSIDL_PERSONAL, FOLDERID_Documents, true, path))
|
||||
{
|
||||
// I assume since this isn't a standard folder, it doesn't have
|
||||
// a localized name either.
|
||||
path << "/My Games/" GAMENAME;
|
||||
CreatePath(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
path = progdir;
|
||||
}
|
||||
return path;
|
||||
}
|
|
@ -3555,8 +3555,6 @@ void Net_SendUserMapName(void)
|
|||
|
||||
void Net_ReceiveUserMapName(uint8_t *pbuf, int32_t packbufleng)
|
||||
{
|
||||
int32_t i;
|
||||
|
||||
Bstrcpy(boardfilename,(char *)pbuf+1);
|
||||
boardfilename[packbufleng-1] = 0;
|
||||
Bcorrectfilename(boardfilename,0);
|
||||
|
|
|
@ -157,7 +157,6 @@ static int osdcmd_changelevel(osdcmdptr_t parm)
|
|||
|
||||
static int osdcmd_map(osdcmdptr_t parm)
|
||||
{
|
||||
int32_t i;
|
||||
char filename[BMAX_PATH];
|
||||
|
||||
const int32_t wildcardp = parm->numparms==1 &&
|
||||
|
|
|
@ -2279,8 +2279,6 @@ void G_SetupFilenameBasedMusic(char *nameBuf, const char *fileName, int levelNum
|
|||
|
||||
for (auto & ext : exts)
|
||||
{
|
||||
int32_t kFile;
|
||||
|
||||
Bmemcpy(p+1, ext, Bstrlen(ext) + 1);
|
||||
|
||||
if (testkopen(nameBuf, 0))
|
||||
|
|
Loading…
Reference in a new issue