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)
{
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;
}
}
}

View file

@ -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,18 +657,10 @@ 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,25 +1436,57 @@ 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;
@ -1517,88 +1516,78 @@ int C_ExecFile (const char *file, bool usePullin)
{ // Comment in middle of line
*comment = 0;
}
AddCommandString (cmd);
if (exec == NULL)
{
exec = new FExecList;
}
exec->AddCommand(cmd, file);
}
if (!feof(f))
{
retval = 2;
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");
}
}
}

View file

@ -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

View file

@ -219,6 +219,11 @@ void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize)
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"))
{

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)
{
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);
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();
@ -2310,7 +2317,7 @@ void D_DoomMain (void)
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");
@ -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);

View file

@ -80,7 +80,8 @@ const char *SpecialMapthingNames[] = {
struct MapinfoEdMapItem
{
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];
// These are for error reporting. We must store the file information because it's no longer available when these items get resolved.
FString filename;
@ -180,14 +181,15 @@ void FMapInfoParser::ParseDoomEdNums()
editem.special = -1;
}
memset(editem.args, 0, sizeof(editem.args));
editem.argsdefined = false;
int minargs = 0;
int maxargs = 5;
FString specialname;
if (sc.CheckString(","))
{
// todo: parse a special or args
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.
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;
if (!sc.CheckNumber())
{
sc.MustGetString();
@ -264,6 +266,7 @@ void InitActorNumsFromMapinfo()
FDoomEdEntry ent;
ent.Type = cls;
ent.Special = pair->Value.special;
ent.ArgsDefined = pair->Value.argsdefined;
memcpy(ent.Args, pair->Value.args, sizeof(ent.Args));
DoomEdMap.Insert(pair->Key, ent);
}

View file

@ -282,7 +282,8 @@ struct FActorInfo
struct FDoomEdEntry
{
const PClass *Type;
int Special;
short Special;
bool ArgsDefined;
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
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));
}

View file

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