This commit is contained in:
Christoph Oelckers 2015-04-08 00:40:40 +02:00
commit fe769bbdc5
10 changed files with 255 additions and 172 deletions

View file

@ -450,11 +450,10 @@ CCMD (exec)
for (int i = 1; i < argv.argc(); ++i) 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; Printf ("Could not exec \"%s\"\n", argv[i]);
case 2: Printf ("Error parsing \"%s\"\n", argv[1]); break; break;
default: break;
} }
} }
} }

View file

@ -185,9 +185,6 @@ static const char *KeyConfCommands[] =
"clearplayerclasses" "clearplayerclasses"
}; };
static TArray<FString> StoredStartupSets;
static bool RunningStoredStartups;
// CODE -------------------------------------------------------------------- // CODE --------------------------------------------------------------------
IMPLEMENT_CLASS (DWaitingCommand) 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) void C_DoCommand (const char *cmd, int keynum)
{ {
FConsoleCommand *com; FConsoleCommand *com;
@ -627,22 +612,7 @@ void C_DoCommand (const char *cmd, int keynum)
if ( (com = FindNameInHashTable (Commands, beg, len)) ) if ( (com = FindNameInHashTable (Commands, beg, len)) )
{ {
if (gamestate == GS_STARTUP && !RunningStoredStartups && if (gamestate != GS_STARTUP || ParsingKeyConf ||
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 ||
(len == 3 && strnicmp (beg, "set", 3) == 0) || (len == 3 && strnicmp (beg, "set", 3) == 0) ||
(len == 7 && strnicmp (beg, "logfile", 7) == 0) || (len == 7 && strnicmp (beg, "logfile", 7) == 0) ||
(len == 9 && strnicmp (beg, "unbindall", 9) == 0) || (len == 9 && strnicmp (beg, "unbindall", 9) == 0) ||
@ -687,15 +657,7 @@ void C_DoCommand (const char *cmd, int keynum)
} }
else else
{ // We don't know how to handle this command { // We don't know how to handle this command
if (gamestate == GS_STARTUP && !RunningStoredStartups) Printf ("Unknown command \"%.*s\"\n", (int)len, beg);
{
// Save it for later, in case a CVARINFO defines it.
StoredStartupSets.Push(beg);
}
else
{
Printf ("Unknown command \"%.*s\"\n", (int)len, beg);
}
} }
} }
} }
@ -1368,7 +1330,7 @@ CCMD (key)
// Execute any console commands specified on the command line. // Execute any console commands specified on the command line.
// These all begin with '+' as opposed to '-'. // These all begin with '+' as opposed to '-'.
void C_ExecCmdLineParams () FExecList *C_ParseCmdLineParams(FExecList *exec)
{ {
for (int currArg = 1; currArg < Args->NumArgs(); ) for (int currArg = 1; currArg < Args->NumArgs(); )
{ {
@ -1389,10 +1351,15 @@ void C_ExecCmdLineParams ()
cmdString = BuildString (cmdlen, Args->GetArgList (argstart)); cmdString = BuildString (cmdlen, Args->GetArgList (argstart));
if (!cmdString.IsEmpty()) if (!cmdString.IsEmpty())
{ {
C_DoCommand (&cmdString[1]); if (exec == NULL)
{
exec = new FExecList;
}
exec->AddCommand(&cmdString[1]);
} }
} }
} }
return exec;
} }
bool FConsoleCommand::IsAlias () bool FConsoleCommand::IsAlias ()
@ -1469,28 +1436,60 @@ void FConsoleAlias::SafeDelete ()
} }
} }
static BYTE PullinBad = 2; void FExecList::AddCommand(const char *cmd, const char *file)
static const char *PullinFile; {
extern TArray<FString> allwads; // 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; FILE *f;
char cmd[4096]; char cmd[4096];
int retval = 0; int retval = 0;
BYTE pullinSaved = PullinBad;
const char *fileSaved = PullinFile;
if ( (f = fopen (file, "r")) ) if ( (f = fopen (file, "r")) )
{ {
PullinBad = 1-usePullin; while (fgets(cmd, countof(cmd)-1, f))
PullinFile = file;
while (fgets (cmd, 4095, f))
{ {
// Comments begin with // // Comments begin with //
char *stop = cmd + strlen (cmd) - 1; char *stop = cmd + strlen(cmd) - 1;
char *comment = cmd; char *comment = cmd;
int inQuote = 0; int inQuote = 0;
@ -1517,88 +1516,78 @@ int C_ExecFile (const char *file, bool usePullin)
{ // Comment in middle of line { // Comment in middle of line
*comment = 0; *comment = 0;
} }
if (exec == NULL)
AddCommandString (cmd); {
exec = new FExecList;
}
exec->AddCommand(cmd, file);
} }
if (!feof (f)) if (!feof(f))
{ {
retval = 2; Printf("Error parsing \"%s\"\n", file);
} }
fclose (f); fclose(f);
} }
else 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) CCMD (pullin)
{ {
if (PullinBad == 2) // Actual handling for pullin is now completely special-cased above
{ Printf (TEXTCOLOR_BOLD "Pullin" TEXTCOLOR_NORMAL " is only valid from .cfg\n"
Printf ("This command is only valid from .cfg\n" "files and only when used at startup.\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");
}
}
} }

View file

@ -39,31 +39,6 @@
class FConfigFile; class FConfigFile;
class APlayerPawn; 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 that can parse command lines
class FCommandLine class FCommandLine
{ {
@ -83,6 +58,44 @@ private:
bool noescapes; 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); typedef void (*CCmdRun) (FCommandLine &argv, APlayerPawn *instigator, int key);
class FConsoleCommand class FConsoleCommand

View file

@ -219,6 +219,11 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize)
sc.ScriptError("Unknown keyword '%s'", sc.String); sc.ScriptError("Unknown keyword '%s'", sc.String);
} }
} }
if (iwad->MapInfo.IsEmpty())
{
// We must at least load the minimum defaults to allow the engine to run.
iwad->MapInfo = "mapinfo/mindefaults.txt";
}
} }
else if (sc.Compare("NAMES")) else if (sc.Compare("NAMES"))
{ {

View file

@ -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) 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) static void GetCmdLineFiles(TArray<FString> &wadfiles)
@ -2291,18 +2292,24 @@ void D_DoomMain (void)
AddAutoloadFiles(iwad_info->Autoname); AddAutoloadFiles(iwad_info->Autoname);
// Run automatically executed files // Process automatically executed files
FExecList *exec;
execFiles = new DArgs; execFiles = new DArgs;
GameConfig->AddAutoexec (execFiles, gameinfo.ConfigName); GameConfig->AddAutoexec(execFiles, gameinfo.ConfigName);
D_MultiExec (execFiles, true); 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"); 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); CopyFiles(allwads, pwads);
if (exec != NULL)
{
exec->AddPullins(allwads);
}
// Since this function will never leave we must delete this array here manually. // Since this function will never leave we must delete this array here manually.
pwads.Clear(); pwads.Clear();
@ -2310,7 +2317,7 @@ void D_DoomMain (void)
if (hashfile) if (hashfile)
{ {
Printf("Notice: File hashing is incredibly verbose. Expect loading files to take much longer then usual.\n"); Printf("Notice: File hashing is incredibly verbose. Expect loading files to take much longer than usual.\n");
} }
Printf ("W_Init: Init WADfiles.\n"); Printf ("W_Init: Init WADfiles.\n");
@ -2324,8 +2331,13 @@ void D_DoomMain (void)
// Now that wads are loaded, define mod-specific cvars. // Now that wads are loaded, define mod-specific cvars.
ParseCVarInfo(); ParseCVarInfo();
// Try setting previously unknown cvars again, as a CVARINFO may have made them known. // Actually exec command line commands and exec files.
C_ExecStoredSets(); if (exec != NULL)
{
exec->ExecCommands();
delete exec;
exec = NULL;
}
// [RH] Initialize localizable strings. // [RH] Initialize localizable strings.
GStrings.LoadStrings (false); GStrings.LoadStrings (false);

View file

@ -80,7 +80,8 @@ const char *SpecialMapthingNames[] = {
struct MapinfoEdMapItem struct MapinfoEdMapItem
{ {
FName classname; // DECORATE is read after MAPINFO so we do not have the actual classes available here yet. FName classname; // DECORATE is read after MAPINFO so we do not have the actual classes available here yet.
int special; short special;
bool argsdefined;
int args[5]; int args[5];
// These are for error reporting. We must store the file information because it's no longer available when these items get resolved. // These are for error reporting. We must store the file information because it's no longer available when these items get resolved.
FString filename; FString filename;
@ -180,14 +181,15 @@ void FMapInfoParser::ParseDoomEdNums()
editem.special = -1; editem.special = -1;
} }
memset(editem.args, 0, sizeof(editem.args)); memset(editem.args, 0, sizeof(editem.args));
editem.argsdefined = false;
int minargs = 0; int minargs = 0;
int maxargs = 5; int maxargs = 5;
FString specialname; FString specialname;
if (sc.CheckString(",")) if (sc.CheckString(","))
{ {
// todo: parse a special or args editem.argsdefined = true; // mark args as used - if this is done we need to prevent assignment of map args in P_SpawnMapThing.
if (editem.special < 0) editem.special = 0; // mark args as used - if this is done we need to prevent assignment of map args in P_SpawnMapThing. if (editem.special < 0) editem.special = 0;
if (!sc.CheckNumber()) if (!sc.CheckNumber())
{ {
sc.MustGetString(); sc.MustGetString();
@ -264,6 +266,7 @@ void InitActorNumsFromMapinfo()
FDoomEdEntry ent; FDoomEdEntry ent;
ent.Type = cls; ent.Type = cls;
ent.Special = pair->Value.special; ent.Special = pair->Value.special;
ent.ArgsDefined = pair->Value.argsdefined;
memcpy(ent.Args, pair->Value.args, sizeof(ent.Args)); memcpy(ent.Args, pair->Value.args, sizeof(ent.Args));
DoomEdMap.Insert(pair->Key, ent); DoomEdMap.Insert(pair->Key, ent);
} }

View file

@ -282,7 +282,8 @@ struct FActorInfo
struct FDoomEdEntry struct FDoomEdEntry
{ {
const PClass *Type; const PClass *Type;
int Special; short Special;
bool ArgsDefined;
int Args[5]; int Args[5];
}; };

View file

@ -4617,9 +4617,9 @@ AActor *P_SpawnMapThing (FMapThing *mthing, int position)
} }
// copy args to mapthing so that we have them in one place for the rest of this function // copy args to mapthing so that we have them in one place for the rest of this function
if (mentry->Type != NULL && mentry->Special >= 0) if (mentry->ArgsDefined)
{ {
mthing->special = mentry->Special; if (mentry->Type!= NULL) mthing->special = mentry->Special;
memcpy(mthing->args, mentry->Args, sizeof(mthing->args)); memcpy(mthing->args, mentry->Args, sizeof(mthing->args));
} }

View file

@ -6,6 +6,7 @@ IWad
Autoname = "square.square" Autoname = "square.square"
Game = "Doom" Game = "Doom"
Config = "Square" Config = "Square"
Mapinfo = "mapinfo/mindefaults.txt"
MustContain = "SQU-IWAD", "E1A1" MustContain = "SQU-IWAD", "E1A1"
BannerColors = "ff ff ff", "80 00 80" BannerColors = "ff ff ff", "80 00 80"
} }
@ -16,6 +17,7 @@ IWad
Autoname = "square.squareware" Autoname = "square.squareware"
Game = "Doom" Game = "Doom"
Config = "Square" Config = "Square"
Mapinfo = "mapinfo/mindefaults.txt"
MustContain = "SQU-SWE1", "E1A1" MustContain = "SQU-SWE1", "E1A1"
BannerColors = "ff ff ff", "80 00 80" BannerColors = "ff ff ff", "80 00 80"
} }

View file

@ -0,0 +1,59 @@
// defines the minimum needed entries to let an unknown IWAD run
gameinfo
{
titlepage = "-NOFLAT-"
titletime = 999
infopage = "-NOFLAT-"
titlemusic = ""
advisorytime = 0
chatsound = ""
finalemusic = ""
finaleflat = "-NOFLAT-"
finalepage = "-NOFLAT-"
quitsound = ""
borderflat = "-NOFLAT-"
border = DoomBorder
telefogheight = 0
defkickback = 100
skyflatname = "F_SKY1"
translator = "xlat/doom.txt"
defaultbloodcolor = "68 00 00"
defaultbloodparticlecolor = "ff 00 00"
backpacktype = "Backpack"
armoricons = "AICNA0", 0.75, "AICNC0"
statusbar = "sbarinfo/doom.txt"
intermissionmusic = ""
intermissioncounter = true
dimcolor = "6f 00 6b"
dimamount = 0.8
definventorymaxamount = 25
defaultrespawntime = 12
defaultdropstyle = 1
endoom = "ENDOOM"
player5start = 4001
pickupcolor = "c0 c0 c0"
quitmessages = "Do you want to quit?"
menufontcolor_title = "purple"
menufontcolor_label = "default"
menufontcolor_value = "gray"
menufontcolor_action = "gray"
menufontcolor_header = "blue"
menufontcolor_highlight = "lightblue"
menufontcolor_selection = "purple"
menubackbutton = "M_BACK_D"
playerclasses = "DoomPlayer"
pausesign = "-NOFLAT-"
gibfactor = 1
cursorpic = "doomcurs"
textscreenx = 10
textscreeny = 10
defaultendsequence = "Inter_Cast"
maparrow = "maparrows/arrow.txt", "maparrows/ddtarrow.txt"
statscreen_mapnamefont = "BigFont"
statscreen_finishedpatch = "WIF"
statscreen_enteringpatch = "WIENTER"
}
include "mapinfo/common.txt"