summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMichael Smith <mikesmiffy128@gmail.com>2022-03-20 20:05:42 +0000
committerMichael Smith <mikesmiffy128@gmail.com>2022-03-20 20:09:53 +0000
commitc0d4714cb304394f19cac5b71d704aa6b2c27dd5 (patch)
tree252a0880c6e2fbff9a506ad049b03691eaf1094e
parent254c7be6edd17a3c33e9152097264f5b159b1b45 (diff)
Support deferring cvar registration
This allows stuff to be registered conditionally. Unfortunately cmeta is now truly the worst thing of all time, but cleaning it up isn't a huge priority. On the plus side, codegen actually got simpler.
-rw-r--r--src/build/cmeta.c31
-rw-r--r--src/build/cmeta.h2
-rw-r--r--src/build/codegen.c57
-rw-r--r--src/con_.c37
-rw-r--r--src/con_.h18
5 files changed, 94 insertions, 51 deletions
diff --git a/src/build/cmeta.c b/src/build/cmeta.c
index 7b7a767..4e1eb4a 100644
--- a/src/build/cmeta.c
+++ b/src/build/cmeta.c
@@ -204,16 +204,37 @@ void cmeta_includes(const struct cmeta *cm,
// AGAIN, NOTE: this doesn't *perfectly* match top level decls only in the event
// that someone writes something weird, but we just don't really care because
// we're not writing something weird. Don't write something weird!
-void cmeta_conmacros(const struct cmeta *cm, void (*cb)(const char *, bool)) {
+void cmeta_conmacros(const struct cmeta *cm,
+ void (*cb)(const char *, bool, bool)) {
Token *tp = (Token *)cm;
if (!tp || !tp->next || !tp->next->next) return; // DEF_xyz, (, name
while (tp) {
bool isplusminus = false, isvar = false;
- if (equal(tp, "DEF_CCMD_PLUSMINUS")) isplusminus = true;
+ bool unreg = false;
+ // this is like the worst thing ever, but oh well it's just build time
+ // XXX: tidy this up some day, though, probably
+ if (equal(tp, "DEF_CCMD_PLUSMINUS")) {
+ isplusminus = true;
+ }
+ else if (equal(tp, "DEF_CCMD_PLUSMINUS_UNREG")) {
+ isplusminus = true;
+ unreg = true;
+ }
else if (equal(tp, "DEF_CVAR") || equal(tp, "DEF_CVAR_MIN") ||
equal(tp, "DEF_CVAR_MAX") || equal(tp, "DEF_CVAR_MINMAX")) {
isvar = true;
}
+ else if (equal(tp, "DEF_CVAR_UNREG") ||
+ equal(tp, "DEF_CVAR_MIN_UNREG") ||
+ equal(tp, "DEF_CVAR_MAX_UNREG") ||
+ equal(tp, "DEF_CVAR_MINMAX_UNREG")) {
+ isvar = true;
+ unreg = true;
+ }
+ else if (equal(tp, "DEF_CCMD_UNREG") ||
+ equal(tp, "DEF_CCMD_HERE_UNREG")) {
+ unreg = true;
+ }
else if (!equal(tp, "DEF_CCMD") && !equal(tp, "DEF_CCMD_HERE")) {
tp = tp->next; continue;
}
@@ -226,20 +247,20 @@ void cmeta_conmacros(const struct cmeta *cm, void (*cb)(const char *, bool)) {
memcpy(plusname, "PLUS_", 5);
memcpy(plusname + sizeof("PLUS_") - 1, tp->loc, tp->len);
plusname[sizeof("PLUS_") - 1 + tp->len] = '\0';
- cb(plusname, false);
+ cb(plusname, false, unreg);
char *minusname = malloc(sizeof("MINUS_") + tp->len);
if (!minusname) die1("couldn't allocate memory");
memcpy(minusname, "MINUS_", 5);
memcpy(minusname + sizeof("MINUS_") - 1, tp->loc, tp->len);
minusname[sizeof("MINUS_") - 1 + tp->len] = '\0';
- cb(minusname, false);
+ cb(minusname, false, unreg);
}
else {
char *name = malloc(tp->len + 1);
if (!name) die1("couldn't allocate memory");
memcpy(name, tp->loc, tp->len);
name[tp->len] = '\0';
- cb(name, isvar);
+ cb(name, isvar, unreg);
}
tp = tp->next;
}
diff --git a/src/build/cmeta.h b/src/build/cmeta.h
index 3319e3a..18ff62c 100644
--- a/src/build/cmeta.h
+++ b/src/build/cmeta.h
@@ -37,7 +37,7 @@ void cmeta_includes(const struct cmeta *cm,
* con_.h, passing each one in turn to the callback cb.
*/
void cmeta_conmacros(const struct cmeta *cm,
- void (*cb)(const char *name, bool isvar));
+ void (*cb)(const char *name, bool isvar, bool unreg));
#endif
diff --git a/src/build/codegen.c b/src/build/codegen.c
index c9be0ef..38645e5 100644
--- a/src/build/codegen.c
+++ b/src/build/codegen.c
@@ -21,26 +21,30 @@
#include "../os.h"
#include "cmeta.h"
-static const char *cmdnames[4096]; // arbitrary limit!
-static int ncmdnames = 0;
-static const char *varnames[4096]; // arbitrary limit!
-static int nvarnames = 0;
+#define MAXENT 65536 // arbitrary limit!
+static struct ent {
+ const char *name;
+ bool unreg;
+ bool isvar; // false for cmd
+} ents[MAXENT];
+static int nents;
static void die(const char *s) {
fprintf(stderr, "codegen: %s\n", s);
exit(100);
}
-#define PUT(array, ent) do { \
- if (n##array == sizeof(array) / sizeof(*array)) { \
- fprintf(stderr, "codegen: out of space; make " #array " bigger!\n"); \
+#define PUT(name_, isvar_, unreg_) do { \
+ if (nents == sizeof(ents) / sizeof(*ents)) { \
+ fprintf(stderr, "codegen: out of space; make ents bigger!\n"); \
exit(1); \
} \
- array[n##array++] = ent; \
+ ents[nents].name = name_; \
+ ents[nents].isvar = isvar_; ents[nents++].unreg = unreg_; \
} while (0)
-static void oncondef(const char *name, bool isvar) {
- if (isvar) PUT(varnames, name); else PUT(cmdnames, name);
+static void oncondef(const char *name, bool isvar, bool unreg) {
+ PUT(name, isvar, unreg);
}
#define _(x) \
@@ -60,31 +64,26 @@ int OS_MAIN(int argc, os_char *argv[]) {
FILE *out = fopen(".build/include/cmdinit.gen.h", "wb");
if (!out) die("couldn't open cmdinit.gen.h");
H();
- for (const char *const *pp = cmdnames;
- pp - cmdnames < ncmdnames; ++pp) {
-F( "extern struct con_cmd *%s;", *pp)
- }
- for (const char *const *pp = varnames;
- pp - varnames < nvarnames; ++pp) {
-F( "extern struct con_var *%s;", *pp)
+ for (const struct ent *p = ents; p - ents < nents; ++p) {
+F( "extern struct con_%s *%s;", p->isvar ? "var" : "cmd", p->name)
}
_( "")
-_( "static void regcmds(void (*VCALLCONV f)(void *, void *)) {")
- for (const char *const *pp = cmdnames;
- pp - cmdnames < ncmdnames; ++pp) {
-F( " f(_con_iface, %s);", *pp)
- }
- for (const char *const *pp = varnames;
- pp - varnames < nvarnames; ++pp) {
-F( " initval(%s);", *pp)
-F( " f(_con_iface, %s);", *pp)
+_( "static void regcmds(void) {")
+ for (const struct ent *p = ents; p - ents < nents; ++p) {
+ if (p->isvar) {
+F( " initval(%s);", p->name)
+ }
+ if (!p->unreg) {
+F( " con_reg(%s);", p->name)
+ }
}
_( "}")
_( "")
_( "static void freevars(void) {")
- for (const char *const *pp = varnames;
- pp - varnames < nvarnames; ++pp) {
-F( " extfree(%s->strval);", *pp)
+ for (const struct ent *p = ents; p - ents < nents; ++p) {
+ if (p->isvar) {
+F( " extfree(%s->strval);", p->name);
+ }
}
_( "}")
if (fflush(out) == EOF) die("couldn't fully write cmdinit.gen.h");
diff --git a/src/con_.c b/src/con_.c
index e58c040..ab1cd1e 100644
--- a/src/con_.c
+++ b/src/con_.c
@@ -396,6 +396,15 @@ static void fillvts(void) {
*pi++ = (void *)&GetSplitScreenPlayerSlot;
}
+void con_reg(void *cmd_or_var) {
+ if (GAMETYPE_MATCHES(Portal2)) {
+ VCALL(_con_iface, RegisterConCommand_p2, cmd_or_var);
+ }
+ else {
+ VCALL(_con_iface, RegisterConCommand, cmd_or_var);
+ }
+}
+
bool con_init(void *(*f)(const char *, int *), int plugin_ver) {
int ifacever; // for error messages
if (_con_iface = f("VEngineCvar007", 0)) {
@@ -409,11 +418,8 @@ bool con_init(void *(*f)(const char *, int *), int plugin_ver) {
_con_colourmsgf = VFUNC(_con_iface, ConsoleColorPrintf_p2);
dllid = VCALL0(_con_iface, AllocateDLLIdentifier_p2);
_gametype_tag |= _gametype_tag_Portal2;
- fillvts();
- regcmds(VFUNC(_con_iface, RegisterConCommand_p2));
- return true;
}
- if (VCALL(_con_iface, FindCommand, "l4d2_snd_adrenaline")) {
+ else if (VCALL(_con_iface, FindCommand, "l4d2_snd_adrenaline")) {
_con_colourmsgf = VFUNC(_con_iface, ConsoleColorPrintf_l4d);
dllid = VCALL0(_con_iface, AllocateDLLIdentifier);
// while we're here, also distinguish Survivors, the stupid Japanese
@@ -428,22 +434,21 @@ bool con_init(void *(*f)(const char *, int *), int plugin_ver) {
else {
_gametype_tag |= _gametype_tag_L4D2;
}
- fillvts();
- regcmds(VFUNC(_con_iface, RegisterConCommand));
- return true;
}
- if (VCALL(_con_iface, FindVar, "z_difficulty")) {
+ else if (VCALL(_con_iface, FindVar, "z_difficulty")) {
_con_colourmsgf = VFUNC(_con_iface, ConsoleColorPrintf_l4d);
dllid = VCALL0(_con_iface, AllocateDLLIdentifier);
_gametype_tag |= _gametype_tag_L4D1;
- fillvts(); // XXX: is this all kinda dupey? maybe rearrange one day.
- regcmds(VFUNC(_con_iface, RegisterConCommand));
- return true;
}
- con_warn("sst: error: game \"%s\" is unsupported (using "
- "VEngineCvar007)\n", gameinfo_title);
- ifacever = 7;
- goto e;
+ else {
+ con_warn("sst: error: game \"%s\" is unsupported (using "
+ "VEngineCvar007)\n", gameinfo_title);
+ ifacever = 7;
+ goto e;
+ }
+ fillvts();
+ regcmds();
+ return true;
}
if (_con_iface = f("VEngineCvar004", 0)) {
// TODO(compat): are there any cases where 004 is incompatible? could
@@ -455,7 +460,7 @@ bool con_init(void *(*f)(const char *, int *), int plugin_ver) {
if (plugin_ver == 3) _gametype_tag |= _gametype_tag_2013;
else _gametype_tag |= _gametype_tag_OrangeBox;
fillvts();
- regcmds(VFUNC(_con_iface, RegisterConCommand));
+ regcmds();
return true;
}
if (f("VEngineCvar003", 0)) {
diff --git a/src/con_.h b/src/con_.h
index ff4241f..c0c37f1 100644
--- a/src/con_.h
+++ b/src/con_.h
@@ -293,6 +293,24 @@ extern void *_con_vtab_iconvar[];
static void _cmdf_##name(const struct con_cmdargs *cmd) \
/* { body here } */
+/*
+ * These are exactly the same as the above macros, but they don't cause the
+ * commands or variables to be registered on plugin load.
+ */
+#define DEF_CVAR_UNREG DEF_CVAR
+#define DEF_CVAR_MIN_UNREG DEF_CVAR_MIN
+#define DEF_CVAR_MAX_UNREG DEF_CVAR_MAX
+#define DEF_CVAR_MINMAX_UNREG DEF_CVAR_MINMAX
+#define DEF_CCMD_UNREG DEF_CCMD
+#define DEF_CCMD_HERE_UNREG DEF_CCMD_HERE
+#define DEF_CCMD_PLUSMINUS_UNREG DEF_CCMD_PLUSMINUS
+
+/*
+ * Registers a command or variable defined with the _UNREG variants of the above
+ * macros. Can be used to conditionally register things.
+ */
+void con_reg(void *cmd_or_var);
+
#endif
// vi: sw=4 ts=4 noet tw=80 cc=80