- copied some CCMD improvements from Raze

* no longer uses copystring function.
* ability to dynamically register CCMDs.
This commit is contained in:
Christoph Oelckers 2020-04-11 18:04:07 +02:00
parent d63a6baa5d
commit b7ff7302e5
4 changed files with 99 additions and 44 deletions

View file

@ -33,13 +33,13 @@
*/
class FConfigFile;
struct osdfuncparm_t;
struct CCmdFuncParm;
// Class that can parse command lines
class FCommandLine
{
friend int OSD_RegisterFunction(const char* pszName, const char* pszDesc, int (*func)(osdfuncparm_t const* const));
friend int C_RegisterFunction(const char* name, const char* help, int (*func)(CCmdFuncParm const* const));
public:
FCommandLine (const char *commandline, bool no_escapes = false);
~FCommandLine ();

View file

@ -58,25 +58,9 @@
#include "c_buttons.h"
// MACROS ------------------------------------------------------------------
// TYPES -------------------------------------------------------------------
class UnsafeExecutionScope
{
const bool wasEnabled;
public:
explicit UnsafeExecutionScope(const bool enable = true)
: wasEnabled(UnsafeExecutionContext)
{
UnsafeExecutionContext = enable;
}
~UnsafeExecutionScope()
{
UnsafeExecutionContext = wasEnabled;
}
};
class FDelayedCommand
{
public:
@ -182,7 +166,6 @@ void C_ClearDelayedCommands()
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
static long ParseCommandLine (const char *args, int *argc, char **argv, bool no_escapes);
static FConsoleCommand *FindNameInHashTable (FConsoleCommand **table, const char *name, size_t namelen);
static FConsoleCommand *ScanChainForName (FConsoleCommand *start, const char *name, size_t namelen, FConsoleCommand **prev);
@ -337,18 +320,6 @@ void C_DoCommand (const char *cmd, int keynum)
}
}
// This is only accessible to the special menu item to run CCMDs.
DEFINE_ACTION_FUNCTION(DOptionMenuItemCommand, DoCommand)
{
if (CurrentMenu == nullptr) return 0;
PARAM_PROLOGUE;
PARAM_STRING(cmd);
PARAM_BOOL(unsafe);
UnsafeExecutionScope scope(unsafe);
C_DoCommand(cmd);
return 0;
}
void AddCommandString (const char *text, int keynum)
{
// Operate on a local copy instead of messing around with the data that's being passed in here.
@ -508,7 +479,7 @@ FConsoleCommand::FConsoleCommand (const char *name, CCmdRun runFunc)
int ag = strcmp (name, "kill");
if (ag == 0)
ag=0;
m_Name = copystring (name);
m_Name = name;
if (!AddToHash (Commands))
Printf ("Adding CCMD %s twice.\n", name);
@ -522,7 +493,6 @@ FConsoleCommand::~FConsoleCommand ()
if (m_Next)
m_Next->m_Prev = m_Prev;
C_RemoveTabCommand (m_Name);
delete[] m_Name;
}
void FConsoleCommand::Run(FCommandLine &argv, int key)
@ -620,7 +590,7 @@ FString BuildString (int argc, FString *argv)
void FConsoleCommand::PrintCommand()
{
Printf("%s\n", m_Name);
Printf("%s\n", m_Name.GetChars());
}
FString SubstituteAliasParams (FString &command, FCommandLine &args)
@ -745,11 +715,11 @@ void FConsoleAlias::PrintAlias ()
{
if (m_Command[0].IsNotEmpty())
{
Printf (TEXTCOLOR_YELLOW "%s : %s\n", m_Name, m_Command[0].GetChars());
Printf (TEXTCOLOR_YELLOW "%s : %s\n", m_Name.GetChars(), m_Command[0].GetChars());
}
if (m_Command[1].IsNotEmpty())
{
Printf (TEXTCOLOR_ORANGE "%s : %s\n", m_Name, m_Command[1].GetChars());
Printf (TEXTCOLOR_ORANGE "%s : %s\n", m_Name.GetChars(), m_Command[1].GetChars());
}
}
@ -846,7 +816,7 @@ CCMD (alias)
}
else
{
Printf ("%s is a normal command\n", alias->m_Name);
Printf ("%s is a normal command\n", alias->m_Name.GetChars());
}
}
}
@ -862,7 +832,7 @@ CCMD (alias)
}
else
{
Printf ("%s is a normal command\n", alias->m_Name);
Printf ("%s is a normal command\n", alias->m_Name.GetChars());
alias = NULL;
}
}
@ -952,7 +922,7 @@ void FConsoleAlias::Run (FCommandLine &args, int key)
{
if (bRunning)
{
Printf ("Alias %s tried to recurse.\n", m_Name);
Printf ("Alias %s tried to recurse.\n", m_Name.GetChars());
return;
}
@ -1160,6 +1130,37 @@ void C_SearchForPullins(FExecList *exec, const char *file, FCommandLine &argv)
}
}
static TArray<FConsoleCommand*> dynccmds; // This needs to be explicitly deleted before shutdown - the names in here may not be valid during the exit handler.
//
// C_RegisterFunction() -- dynamically register a CCMD.
//
int C_RegisterFunction(const char* pszName, const char* pszDesc, int (*func)(CCmdFuncPtr))
{
FString nname = pszName;
auto callback = [nname, pszDesc, func](FCommandLine& args, int key)
{
if (args.argc() > 0) args.operator[](0);
CCmdFuncParm param = { args.argc() - 1, nname.GetChars(), (const char**)args._argv + 1, args.cmd };
if (func(&param) != CCMD_OK)
{
Printf("%s\n", pszDesc);
}
};
auto ccmd = new FConsoleCommand(pszName, callback);
dynccmds.Push(ccmd);
return 0;
}
void C_ClearDynCCmds()
{
for (auto ccmd : dynccmds)
{
delete ccmd;
}
dynccmds.Clear();
}
CCMD (pullin)
{
// Actual handling for pullin is now completely special-cased above

View file

@ -35,6 +35,8 @@
#define __C_DISPATCH_H__
#include <stdint.h>
#include <functional>
#include "c_console.h"
#include "tarray.h"
#include "c_commandline.h"
#include "zstring.h"
@ -75,6 +77,7 @@ 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);
void C_ClearDynCCmds();
// Write out alias commands to a file for all current aliases.
void C_ArchiveAliases (FConfigFile *f);
@ -85,8 +88,7 @@ void C_ClearAliases ();
// build a single string out of multiple strings
FString BuildString (int argc, FString *argv);
class AActor;
typedef void (*CCmdRun) (FCommandLine &argv, int key);
typedef std::function<void(FCommandLine & argv, int key)> CCmdRun;;
class FConsoleCommand
{
@ -100,7 +102,7 @@ public:
static FConsoleCommand* FindByName (const char* name);
FConsoleCommand *m_Next, **m_Prev;
char *m_Name;
FString m_Name;
enum { HASH_SIZE = 251 }; // Is this prime?
@ -164,9 +166,48 @@ public:
virtual void Run (FCommandLine &args, int key) override;
};
class UnsafeExecutionScope
{
const bool wasEnabled;
public:
explicit UnsafeExecutionScope(const bool enable = true)
: wasEnabled(UnsafeExecutionContext)
{
UnsafeExecutionContext = enable;
}
~UnsafeExecutionScope()
{
UnsafeExecutionContext = wasEnabled;
}
};
#include "superfasthash.h"
void execLogfile(const char *fn, bool append = false);
enum
{
CCMD_OK = 0,
CCMD_SHOWHELP = 1
};
struct CCmdFuncParm
{
int32_t numparms;
const char* name;
const char** parms;
const char* raw;
};
using CCmdFuncPtr = CCmdFuncParm const* const;
// registers a function
// name = name of the function
// help = a short help string
// func = the entry point to the function
int C_RegisterFunction(const char* name, const char* help, int (*func)(CCmdFuncPtr));
#endif //__C_DISPATCH_H__

View file

@ -55,6 +55,7 @@
#include "menu/menu.h"
#include "c_cvars.h"
#include "c_bind.h"
#include "c_dispatch.h"
DVector2 AM_GetPosition();
int Net_GetLatency(int *ld, int *ad);
@ -3393,6 +3394,18 @@ DEFINE_ACTION_FUNCTION(FKeyBindings, UnbindACommand)
return 0;
}
// This is only accessible to the special menu item to run CCMDs.
DEFINE_ACTION_FUNCTION(DOptionMenuItemCommand, DoCommand)
{
if (CurrentMenu == nullptr) return 0;
PARAM_PROLOGUE;
PARAM_STRING(cmd);
PARAM_BOOL(unsafe);
UnsafeExecutionScope scope(unsafe);
C_DoCommand(cmd);
return 0;
}