mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-11 15:21:51 +00:00
Try to sanitize the exec+pullin mess
- Old mess: * Execute autoexec files right away. * Execute -exec files right away. * Execute command line commands right away. - If, during any of the above, an unknown command or a set of an unknown variable is encountered, store it for later. - Pullin commands are directly executed and add to the list of files to load. * Do a little setup, including parsing CVARINFOs. * Retry saved commands in case CVARINFO added a cvar they refer to. - New, less messy, mess: * Parse autoexec files into an array. * Parse -exec files. * Parse command line commands. - During all of the above, exec commands are also parsed into the array immediately rather than being saved for execution later. - Pullin commands are parsed into a different array. The pullin command doesn't actually do anything directly anymore. * Add all the pullin files to the list of files to load. * Do a little setup, including parsing CVARINFOs. * Execute every command that was parsed in the preceding steps.
This commit is contained in:
parent
e4cadc90a5
commit
6428b399d6
4 changed files with 178 additions and 165 deletions
|
@ -450,11 +450,10 @@ CCMD (exec)
|
|||
|
||||
for (int i = 1; i < argv.argc(); ++i)
|
||||
{
|
||||
switch (C_ExecFile (argv[i], gamestate == GS_STARTUP))
|
||||
if (!C_ExecFile(argv[i]))
|
||||
{
|
||||
case 1: Printf ("Could not open \"%s\"\n", argv[1]); break;
|
||||
case 2: Printf ("Error parsing \"%s\"\n", argv[1]); break;
|
||||
default: break;
|
||||
Printf ("Could not exec \"%s\"\n", argv[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -185,9 +185,6 @@ static const char *KeyConfCommands[] =
|
|||
"clearplayerclasses"
|
||||
};
|
||||
|
||||
static TArray<FString> StoredStartupSets;
|
||||
static bool RunningStoredStartups;
|
||||
|
||||
// CODE --------------------------------------------------------------------
|
||||
|
||||
IMPLEMENT_CLASS (DWaitingCommand)
|
||||
|
@ -540,18 +537,6 @@ void ResetButtonStates ()
|
|||
}
|
||||
}
|
||||
|
||||
void C_ExecStoredSets()
|
||||
{
|
||||
assert(!RunningStoredStartups);
|
||||
RunningStoredStartups = true;
|
||||
for (unsigned i = 0; i < StoredStartupSets.Size(); ++i)
|
||||
{
|
||||
C_DoCommand(StoredStartupSets[i]);
|
||||
}
|
||||
StoredStartupSets.Clear();
|
||||
RunningStoredStartups = false;
|
||||
}
|
||||
|
||||
void C_DoCommand (const char *cmd, int keynum)
|
||||
{
|
||||
FConsoleCommand *com;
|
||||
|
@ -627,22 +612,7 @@ void C_DoCommand (const char *cmd, int keynum)
|
|||
|
||||
if ( (com = FindNameInHashTable (Commands, beg, len)) )
|
||||
{
|
||||
if (gamestate == GS_STARTUP && !RunningStoredStartups &&
|
||||
len == 3 && strnicmp(beg, "set", 3) == 0)
|
||||
{
|
||||
// Save setting of unknown cvars for later, in case a loaded wad has a
|
||||
// CVARINFO that defines it.
|
||||
FCommandLine args(beg);
|
||||
if (args.argc() > 1 && FindCVar(args[1], NULL) == NULL)
|
||||
{
|
||||
StoredStartupSets.Push(beg);
|
||||
}
|
||||
else
|
||||
{
|
||||
com->Run(args, players[consoleplayer].mo, keynum);
|
||||
}
|
||||
}
|
||||
else if (gamestate != GS_STARTUP || ParsingKeyConf ||
|
||||
if (gamestate != GS_STARTUP || ParsingKeyConf ||
|
||||
(len == 3 && strnicmp (beg, "set", 3) == 0) ||
|
||||
(len == 7 && strnicmp (beg, "logfile", 7) == 0) ||
|
||||
(len == 9 && strnicmp (beg, "unbindall", 9) == 0) ||
|
||||
|
@ -687,17 +657,9 @@ void C_DoCommand (const char *cmd, int keynum)
|
|||
}
|
||||
else
|
||||
{ // We don't know how to handle this command
|
||||
if (gamestate == GS_STARTUP && !RunningStoredStartups)
|
||||
{
|
||||
// Save it for later, in case a CVARINFO defines it.
|
||||
StoredStartupSets.Push(beg);
|
||||
}
|
||||
else
|
||||
{
|
||||
Printf ("Unknown command \"%.*s\"\n", (int)len, beg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddCommandString (char *cmd, int keynum)
|
||||
|
@ -1368,7 +1330,7 @@ CCMD (key)
|
|||
|
||||
// Execute any console commands specified on the command line.
|
||||
// These all begin with '+' as opposed to '-'.
|
||||
void C_ExecCmdLineParams ()
|
||||
FExecList *C_ParseCmdLineParams(FExecList *exec)
|
||||
{
|
||||
for (int currArg = 1; currArg < Args->NumArgs(); )
|
||||
{
|
||||
|
@ -1389,10 +1351,15 @@ void C_ExecCmdLineParams ()
|
|||
cmdString = BuildString (cmdlen, Args->GetArgList (argstart));
|
||||
if (!cmdString.IsEmpty())
|
||||
{
|
||||
C_DoCommand (&cmdString[1]);
|
||||
if (exec == NULL)
|
||||
{
|
||||
exec = new FExecList;
|
||||
}
|
||||
exec->AddCommand(&cmdString[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return exec;
|
||||
}
|
||||
|
||||
bool FConsoleCommand::IsAlias ()
|
||||
|
@ -1469,28 +1436,60 @@ void FConsoleAlias::SafeDelete ()
|
|||
}
|
||||
}
|
||||
|
||||
static BYTE PullinBad = 2;
|
||||
static const char *PullinFile;
|
||||
extern TArray<FString> allwads;
|
||||
void FExecList::AddCommand(const char *cmd, const char *file)
|
||||
{
|
||||
// Pullins are special and need to be separated from general commands.
|
||||
// They also turned out to be a really bad idea, since they make things
|
||||
// more complicated. :(
|
||||
if (file != NULL && strnicmp(cmd, "pullin", 6) == 0 && isspace(cmd[6]))
|
||||
{
|
||||
FCommandLine line(cmd);
|
||||
C_SearchForPullins(this, file, line);
|
||||
}
|
||||
// Recursive exec: Parse this file now.
|
||||
else if (strnicmp(cmd, "exec", 4) == 0 && isspace(cmd[4]))
|
||||
{
|
||||
FCommandLine argv(cmd);
|
||||
for (int i = 1; i < argv.argc(); ++i)
|
||||
{
|
||||
C_ParseExecFile(argv[i], this);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Commands.Push(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
int C_ExecFile (const char *file, bool usePullin)
|
||||
void FExecList::ExecCommands() const
|
||||
{
|
||||
for (unsigned i = 0; i < Commands.Size(); ++i)
|
||||
{
|
||||
AddCommandString(Commands[i].LockBuffer());
|
||||
Commands[i].UnlockBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
void FExecList::AddPullins(TArray<FString> &wads) const
|
||||
{
|
||||
for (unsigned i = 0; i < Pullins.Size(); ++i)
|
||||
{
|
||||
D_AddFile(wads, Pullins[i]);
|
||||
}
|
||||
}
|
||||
|
||||
FExecList *C_ParseExecFile(const char *file, FExecList *exec)
|
||||
{
|
||||
FILE *f;
|
||||
char cmd[4096];
|
||||
int retval = 0;
|
||||
|
||||
BYTE pullinSaved = PullinBad;
|
||||
const char *fileSaved = PullinFile;
|
||||
|
||||
if ( (f = fopen (file, "r")) )
|
||||
{
|
||||
PullinBad = 1-usePullin;
|
||||
PullinFile = file;
|
||||
|
||||
while (fgets (cmd, 4095, f))
|
||||
while (fgets(cmd, countof(cmd)-1, f))
|
||||
{
|
||||
// Comments begin with //
|
||||
char *stop = cmd + strlen (cmd) - 1;
|
||||
char *stop = cmd + strlen(cmd) - 1;
|
||||
char *comment = cmd;
|
||||
int inQuote = 0;
|
||||
|
||||
|
@ -1517,88 +1516,78 @@ int C_ExecFile (const char *file, bool usePullin)
|
|||
{ // Comment in middle of line
|
||||
*comment = 0;
|
||||
}
|
||||
|
||||
AddCommandString (cmd);
|
||||
}
|
||||
if (!feof (f))
|
||||
if (exec == NULL)
|
||||
{
|
||||
retval = 2;
|
||||
exec = new FExecList;
|
||||
}
|
||||
fclose (f);
|
||||
exec->AddCommand(cmd, file);
|
||||
}
|
||||
if (!feof(f))
|
||||
{
|
||||
Printf("Error parsing \"%s\"\n", file);
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = 1;
|
||||
Printf ("Could not open \"%s\"\n", file);
|
||||
}
|
||||
return exec;
|
||||
}
|
||||
|
||||
bool C_ExecFile (const char *file)
|
||||
{
|
||||
FExecList *exec = C_ParseExecFile(file, NULL);
|
||||
if (exec != NULL)
|
||||
{
|
||||
exec->ExecCommands();
|
||||
if (exec->Pullins.Size() > 0)
|
||||
{
|
||||
Printf(TEXTCOLOR_BOLD "Notice: Pullin files were ignored.\n");
|
||||
}
|
||||
delete exec;
|
||||
}
|
||||
return exec != NULL;
|
||||
}
|
||||
|
||||
void C_SearchForPullins(FExecList *exec, const char *file, FCommandLine &argv)
|
||||
{
|
||||
const char *lastSlash;
|
||||
|
||||
assert(exec != NULL);
|
||||
assert(file != NULL);
|
||||
#ifdef __unix__
|
||||
lastSlash = strrchr(file, '/');
|
||||
#else
|
||||
const char *lastSlash1, *lastSlash2;
|
||||
|
||||
lastSlash1 = strrchr(file, '/');
|
||||
lastSlash2 = strrchr(file, '\\');
|
||||
lastSlash = MAX(lastSlash1, lastSlash2);
|
||||
#endif
|
||||
|
||||
for (int i = 1; i < argv.argc(); ++i)
|
||||
{
|
||||
// Try looking for the wad in the same directory as the .cfg
|
||||
// before looking for it in the current directory.
|
||||
if (lastSlash != NULL)
|
||||
{
|
||||
FString path(file, (lastSlash - file) + 1);
|
||||
path += argv[i];
|
||||
if (FileExists(path))
|
||||
{
|
||||
exec->Pullins.Push(path);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
exec->Pullins.Push(argv[i]);
|
||||
}
|
||||
PullinBad = pullinSaved;
|
||||
PullinFile = fileSaved;
|
||||
return retval;
|
||||
}
|
||||
|
||||
CCMD (pullin)
|
||||
{
|
||||
if (PullinBad == 2)
|
||||
{
|
||||
Printf ("This command is only valid from .cfg\n"
|
||||
// Actual handling for pullin is now completely special-cased above
|
||||
Printf (TEXTCOLOR_BOLD "Pullin" TEXTCOLOR_NORMAL " is only valid from .cfg\n"
|
||||
"files and only when used at startup.\n");
|
||||
}
|
||||
else if (argv.argc() > 1)
|
||||
{
|
||||
const char *lastSlash;
|
||||
|
||||
#ifdef __unix__
|
||||
lastSlash = strrchr (PullinFile, '/');
|
||||
#else
|
||||
const char *lastSlash1, *lastSlash2;
|
||||
|
||||
lastSlash1 = strrchr (PullinFile, '/');
|
||||
lastSlash2 = strrchr (PullinFile, '\\');
|
||||
lastSlash = MAX (lastSlash1, lastSlash2);
|
||||
#endif
|
||||
|
||||
if (PullinBad)
|
||||
{
|
||||
Printf ("Not loading:");
|
||||
}
|
||||
for (int i = 1; i < argv.argc(); ++i)
|
||||
{
|
||||
if (PullinBad)
|
||||
{
|
||||
Printf (" %s", argv[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Try looking for the wad in the same directory as the .cfg
|
||||
// before looking for it in the current directory.
|
||||
char *path = argv[i];
|
||||
|
||||
if (lastSlash != NULL)
|
||||
{
|
||||
size_t pathlen = lastSlash - PullinFile + strlen (argv[i]) + 2;
|
||||
path = new char[pathlen];
|
||||
strncpy (path, PullinFile, (lastSlash - PullinFile) + 1);
|
||||
strcpy (path + (lastSlash - PullinFile) + 1, argv[i]);
|
||||
if (!FileExists (path))
|
||||
{
|
||||
delete[] path;
|
||||
path = argv[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
FixPathSeperator (path);
|
||||
}
|
||||
}
|
||||
D_AddFile (allwads, path);
|
||||
if (path != argv[i])
|
||||
{
|
||||
delete[] path;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (PullinBad)
|
||||
{
|
||||
Printf ("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,31 +39,6 @@
|
|||
class FConfigFile;
|
||||
class APlayerPawn;
|
||||
|
||||
extern bool CheckCheatmode (bool printmsg = true);
|
||||
|
||||
void C_ExecCmdLineParams ();
|
||||
void C_ExecStoredSets();
|
||||
|
||||
// Add commands to the console as if they were typed in. Can handle wait
|
||||
// and semicolon-separated commands. This function may modify the source
|
||||
// string, but the string will be restored to its original state before
|
||||
// returning. Therefore, commands passed must not be in read-only memory.
|
||||
void AddCommandString (char *text, int keynum=0);
|
||||
|
||||
// Process a single console command. Does not handle wait.
|
||||
void C_DoCommand (const char *cmd, int keynum=0);
|
||||
|
||||
int C_ExecFile (const char *cmd, bool usePullin);
|
||||
|
||||
// Write out alias commands to a file for all current aliases.
|
||||
void C_ArchiveAliases (FConfigFile *f);
|
||||
|
||||
void C_SetAlias (const char *name, const char *cmd);
|
||||
void C_ClearAliases ();
|
||||
|
||||
// build a single string out of multiple strings
|
||||
FString BuildString (int argc, FString *argv);
|
||||
|
||||
// Class that can parse command lines
|
||||
class FCommandLine
|
||||
{
|
||||
|
@ -83,6 +58,44 @@ private:
|
|||
bool noescapes;
|
||||
};
|
||||
|
||||
// Contains the contents of an exec'ed file
|
||||
struct FExecList
|
||||
{
|
||||
TArray<FString> Commands;
|
||||
TArray<FString> Pullins;
|
||||
|
||||
void AddCommand(const char *cmd, const char *file = NULL);
|
||||
void ExecCommands() const;
|
||||
void AddPullins(TArray<FString> &wads) const;
|
||||
};
|
||||
|
||||
|
||||
extern bool CheckCheatmode (bool printmsg = true);
|
||||
|
||||
FExecList *C_ParseCmdLineParams(FExecList *exec);
|
||||
|
||||
// Add commands to the console as if they were typed in. Can handle wait
|
||||
// and semicolon-separated commands. This function may modify the source
|
||||
// string, but the string will be restored to its original state before
|
||||
// returning. Therefore, commands passed must not be in read-only memory.
|
||||
void AddCommandString (char *text, int keynum=0);
|
||||
|
||||
// Process a single console command. Does not handle wait.
|
||||
void C_DoCommand (const char *cmd, int keynum=0);
|
||||
|
||||
FExecList *C_ParseExecFile(const char *file, FExecList *source);
|
||||
void C_SearchForPullins(FExecList *exec, const char *file, class FCommandLine &args);
|
||||
bool C_ExecFile(const char *file);
|
||||
|
||||
// Write out alias commands to a file for all current aliases.
|
||||
void C_ArchiveAliases (FConfigFile *f);
|
||||
|
||||
void C_SetAlias (const char *name, const char *cmd);
|
||||
void C_ClearAliases ();
|
||||
|
||||
// build a single string out of multiple strings
|
||||
FString BuildString (int argc, FString *argv);
|
||||
|
||||
typedef void (*CCmdRun) (FCommandLine &argv, APlayerPawn *instigator, int key);
|
||||
|
||||
class FConsoleCommand
|
||||
|
|
|
@ -1723,12 +1723,13 @@ bool ConsiderPatches (const char *arg)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
void D_MultiExec (DArgs *list, bool usePullin)
|
||||
FExecList *D_MultiExec (DArgs *list, FExecList *exec)
|
||||
{
|
||||
for (int i = 0; i < list->NumArgs(); ++i)
|
||||
{
|
||||
C_ExecFile (list->GetArg (i), usePullin);
|
||||
exec = C_ParseExecFile(list->GetArg(i), exec);
|
||||
}
|
||||
return exec;
|
||||
}
|
||||
|
||||
static void GetCmdLineFiles(TArray<FString> &wadfiles)
|
||||
|
@ -2291,18 +2292,24 @@ void D_DoomMain (void)
|
|||
|
||||
AddAutoloadFiles(iwad_info->Autoname);
|
||||
|
||||
// Run automatically executed files
|
||||
// Process automatically executed files
|
||||
FExecList *exec;
|
||||
execFiles = new DArgs;
|
||||
GameConfig->AddAutoexec (execFiles, gameinfo.ConfigName);
|
||||
D_MultiExec (execFiles, true);
|
||||
GameConfig->AddAutoexec(execFiles, gameinfo.ConfigName);
|
||||
exec = D_MultiExec(execFiles, NULL);
|
||||
|
||||
// Run .cfg files at the start of the command line.
|
||||
// Process .cfg files at the start of the command line.
|
||||
execFiles = Args->GatherFiles ("-exec");
|
||||
D_MultiExec (execFiles, true);
|
||||
exec = D_MultiExec(execFiles, exec);
|
||||
|
||||
C_ExecCmdLineParams (); // [RH] do all +set commands on the command line
|
||||
// [RH] process all + commands on the command line
|
||||
exec = C_ParseCmdLineParams(exec);
|
||||
|
||||
CopyFiles(allwads, pwads);
|
||||
if (exec != NULL)
|
||||
{
|
||||
exec->AddPullins(allwads);
|
||||
}
|
||||
|
||||
// Since this function will never leave we must delete this array here manually.
|
||||
pwads.Clear();
|
||||
|
@ -2324,8 +2331,13 @@ void D_DoomMain (void)
|
|||
// Now that wads are loaded, define mod-specific cvars.
|
||||
ParseCVarInfo();
|
||||
|
||||
// Try setting previously unknown cvars again, as a CVARINFO may have made them known.
|
||||
C_ExecStoredSets();
|
||||
// Actually exec command line commands and exec files.
|
||||
if (exec != NULL)
|
||||
{
|
||||
exec->ExecCommands();
|
||||
delete exec;
|
||||
exec = NULL;
|
||||
}
|
||||
|
||||
// [RH] Initialize localizable strings.
|
||||
GStrings.LoadStrings (false);
|
||||
|
|
Loading…
Reference in a new issue