aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/con_.c6
-rw-r--r--src/con_.h51
-rw-r--r--src/sst.c8
3 files changed, 39 insertions, 26 deletions
diff --git a/src/con_.c b/src/con_.c
index 90cc0fd..23291d7 100644
--- a/src/con_.c
+++ b/src/con_.c
@@ -186,7 +186,7 @@ static bool VCALLCONV ClampValue_OE(struct con_var *this, float *f) {
// global argc/argv. also OE only. extern for use in sst.c plugin_unload hook
// as well as in DEF_CCMD_COMPAT_HOOK
int *_con_argc;
-const char *(*_con_argv)[80];
+const char **_con_argv; // note: points to array of 80
static bool find_argcargv() {
const uchar *insns = (const uchar *)VFUNC(engclient, Cmd_Argv);
@@ -217,12 +217,12 @@ int VCALLCONV AutoCompleteSuggest(struct con_cmd *this, const char *partial,
bool VCALLCONV CanAutoComplete(struct con_cmd *this) {
return false;
}
-void VCALLCONV Dispatch(struct con_cmd *this, const struct con_cmdargs *args) {
+void VCALLCONV Dispatch(struct con_cmd *this, struct con_cmdargs *args) {
this->cb(args->argc, args->argv);
}
#ifdef _WIN32
void VCALLCONV Dispatch_OE(struct con_cmd *this) {
- this->cb(*_con_argc, *_con_argv);
+ this->cb(*_con_argc, _con_argv);
}
#endif
diff --git a/src/con_.h b/src/con_.h
index 8bef5d0..eb03642 100644
--- a/src/con_.h
+++ b/src/con_.h
@@ -73,10 +73,10 @@ enum {
};
/* A callback function invoked by SST to execute its own commands. */
-typedef void (*con_cmdcb)(int argc, const char *const *argv);
+typedef void (*con_cmdcb)(int argc, const char **argv);
/* A callback function used by most commands in most versions of the engine. */
-typedef void (*con_cmdcbv2)(const struct con_cmdargs *cmd);
+typedef void (*con_cmdcbv2)(struct con_cmdargs *cmd);
/* An older style of callback function used by some old commands, and in OE. */
typedef void (*con_cmdcbv1)();
@@ -339,12 +339,12 @@ extern struct _con_vtab_iconvar_wrap {
/*
* Defines a console command with the handler function body immediately
* following the macro (like in Source itself). The function takes the implicit
- * arguments `int argc` and `const char *const *argv` for command arguments.
+ * arguments `int argc` and `const char **argv` for command arguments.
*/
#define DEF_CCMD_HERE(name, desc, flags) \
- static void _cmdf_##name(int argc, const char *const *argv); \
+ static void _cmdf_##name(int argc, const char **argv); \
_DEF_CCMD(name, name, desc, _cmdf_##name, flags) \
- static void _cmdf_##name(int argc, const char *const *argv) \
+ static void _cmdf_##name(int argc, const char **argv) \
/* { body here } */
/*
@@ -396,11 +396,6 @@ extern struct _con_vtab_iconvar_wrap {
* command handler defined with DEF_CCMD_HERE. Calling the original command
* handler can be done using orig_##name##_cb, passing through argc and argv.
*
- * Note that argc and argv MUST remain unmodified, as not all callback
- * interfaces pass arguments through the callback and so attempting to change
- * these parameters could cause unexpected or inconsistent behaviour across
- * engine versions.
- *
* In some cases, a command will be defined to take no arguments, in which case
* argc will be zero and argv will be null. In these cases, the parameters
* should still be passed through to the orig_ function, as this ensures
@@ -411,10 +406,28 @@ extern struct _con_vtab_iconvar_wrap {
con_cmdcbv1 v1; \
con_cmdcbv2 v2; \
} _orig_##name##_cb; \
- static void _orig_##name##_cbv1(int argc, const char *const *argv) { \
- _orig_##name##_cb.v1(); \
+ static void _orig_##name##_cbv1(int argc, const char **argv) { \
+ extern int *_con_argc; \
+ extern const char **_con_argv; \
+ int _orig_argc = *_con_argc; \
+ *_con_argc = argc; \
+ if (argv != _con_argv) { \
+ /* args can be passed through as-is, or modified in place, however
+ here we have a whole different array, so we have to copy it out
+ and back to avoid confusing side effects for the caller. */ \
+ /* XXX: not bothering with the null term here; should we be? */ \
+ const char *_orig_argv[80]; \
+ memcpy(_orig_argv, _con_argv, _orig_argc * sizeof(*argv)); \
+ memcpy(_con_argv, argv, argc * sizeof(*argv)); \
+ _orig_##name##_cb.v1(); \
+ memcpy(_con_argv, _orig_argv, _orig_argc * sizeof(*argv)); \
+ } \
+ else { \
+ _orig_##name##_cb.v1(); \
+ } \
+ *_con_argc = _orig_argc; \
} \
- static void _orig_##name##_cbv2(int argc, const char *const *argv) { \
+ static void _orig_##name##_cbv2(int argc, const char **argv) { \
struct con_cmdargs args; \
args.argc = argc; \
/* XXX: having to copy argv sucks, but can't see how to avoid without
@@ -422,14 +435,14 @@ extern struct _con_vtab_iconvar_wrap {
for (int i = 0; i < argc; ++i) args.argv[i] = argv[i]; \
_orig_##name##_cb.v2(&args); \
} \
- static void (*orig_##name##_cb)(int argc, const char *const *argv); \
- static void _hook_##name##_cb(int argc, const char *const *argv); \
+ static void (*orig_##name##_cb)(int argc, const char **argv); \
+ static void _hook_##name##_cb(int argc, const char **argv); \
static void _hook_##name##_cbv1() { \
extern int *_con_argc; \
- extern const char *(*_con_argv)[80]; \
- _hook_##name##_cb(*_con_argc, *_con_argv); \
+ extern const char **_con_argv; \
+ _hook_##name##_cb(*_con_argc, _con_argv); \
} \
- static void _hook_##name##_cbv2(const struct con_cmdargs *args) { \
+ static void _hook_##name##_cbv2(struct con_cmdargs *args) { \
_hook_##name##_cb(args->argc, args->argv); \
} \
static void hook_##name##_cb(struct con_cmd *cmd) { \
@@ -446,7 +459,7 @@ extern struct _con_vtab_iconvar_wrap {
static void unhook_##name##_cb(struct con_cmd *cmd) { \
cmd->cb_v1 = _orig_##name##_cb.v1; \
} \
- static void _hook_##name##_cb(int argc, const char *const *argv) /* ... */
+ static void _hook_##name##_cb(int argc, const char **argv) /* ... */
/*
* These functions register a command or variable, respectively, defined with
diff --git a/src/sst.c b/src/sst.c
index 8bdb56c..3ed92ee 100644
--- a/src/sst.c
+++ b/src/sst.c
@@ -466,7 +466,7 @@ enum unload_action {
UNLOAD_SELF,
UNLOAD_OTHER
};
-static int hook_plugin_unload_common(int argc, const char *const *argv) {
+static int hook_plugin_unload_common(int argc, const char **argv) {
if (argc > 1) {
if (!CHECK_AllowPluginLoading(false)) return UNLOAD_SKIP;
if (!*argv[1]) {
@@ -515,8 +515,8 @@ static int hook_plugin_unload_common(int argc, const char *const *argv) {
static void hook_plugin_unload_cbv1() {
extern int *_con_argc;
- extern const char *(*_con_argv)[80];
- int action = hook_plugin_unload_common(*_con_argc, *_con_argv);
+ extern const char **_con_argv;
+ int action = hook_plugin_unload_common(*_con_argc, _con_argv);
switch_exhaust_enum(unload_action, action) {
case UNLOAD_SKIP:
return;
@@ -527,7 +527,7 @@ static void hook_plugin_unload_cbv1() {
EMIT_PluginUnloaded();
}
}
-static void hook_plugin_unload_cbv2(const struct con_cmdargs *args) {
+static void hook_plugin_unload_cbv2(struct con_cmdargs *args) {
int action = hook_plugin_unload_common(args->argc, args->argv);
switch_exhaust_enum(unload_action, action) {
case UNLOAD_SKIP: