summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/3p/chibicc/chibicc.h4
-rw-r--r--src/3p/chibicc/tokenize.c2
-rw-r--r--src/ac.c5
-rw-r--r--src/alias.c1
-rw-r--r--src/autojump.c2
-rw-r--r--src/bind.c2
-rw-r--r--src/bitbuf.h2
-rw-r--r--src/build/cmeta.c87
-rw-r--r--src/build/cmeta.h6
-rw-r--r--src/build/codegen.c84
-rw-r--r--src/build/mkentprops.c1
-rw-r--r--src/build/mkgamedata.c1
-rw-r--r--src/build/vec.h1
-rw-r--r--src/con_.c53
-rw-r--r--src/con_.h2
-rw-r--r--src/democustom.c4
-rw-r--r--src/demorec.c1
-rw-r--r--src/engineapi.c8
-rw-r--r--src/ent.c4
-rw-r--r--src/event.h56
-rw-r--r--src/extmalloc.c26
-rw-r--r--src/feature.h2
-rw-r--r--src/fov.c9
-rw-r--r--src/fov.h2
-rw-r--r--src/gamedata.c2
-rw-r--r--src/gamedata.h2
-rw-r--r--src/gameinfo.c3
-rw-r--r--src/hook.h2
-rw-r--r--src/kv.c2
-rw-r--r--src/kv.h2
-rw-r--r--src/l4dwarp.c8
-rw-r--r--src/os.h2
-rw-r--r--src/portalcolours.c1
-rw-r--r--src/sst.c14
-rw-r--r--src/sst.h4
-rw-r--r--src/vcall.h98
-rw-r--r--src/x86util.h4
37 files changed, 337 insertions, 172 deletions
diff --git a/src/3p/chibicc/chibicc.h b/src/3p/chibicc/chibicc.h
index dd810ec..2a80ecf 100644
--- a/src/3p/chibicc/chibicc.h
+++ b/src/3p/chibicc/chibicc.h
@@ -7,7 +7,7 @@
#include <ctype.h>
#include <errno.h>
#include <stdarg.h>
-#include <stdbool.h>
+//#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -93,7 +93,7 @@ _Noreturn void error(char *fmt, ...) __attribute__((format(printf, 1, 2)));
_Noreturn void error_at(char *loc, char *fmt, ...) __attribute__((format(printf, 2, 3)));
_Noreturn void error_tok(Token *tok, char *fmt, ...) __attribute__((format(printf, 2, 3)));
void warn_tok(Token *tok, char *fmt, ...) __attribute__((format(printf, 2, 3)));
-bool equal(Token *tok, char *op);
+bool equal(const Token *tok, const char *op);
Token *skip(Token *tok, char *op);
bool consume(Token **rest, Token *tok, char *str);
void convert_pp_tokens(Token *tok);
diff --git a/src/3p/chibicc/tokenize.c b/src/3p/chibicc/tokenize.c
index 8ed414e..3b15df9 100644
--- a/src/3p/chibicc/tokenize.c
+++ b/src/3p/chibicc/tokenize.c
@@ -77,7 +77,7 @@ void warn_tok(Token *tok, char *fmt, ...) {
}
// Consumes the current token if it matches `op`.
-bool equal(Token *tok, char *op) {
+bool equal(const Token *tok, const char *op) {
return memcmp(tok->loc, op, tok->len) == 0 && op[tok->len] == '\0';
}
diff --git a/src/ac.c b/src/ac.c
index 4d21a48..326894a 100644
--- a/src/ac.c
+++ b/src/ac.c
@@ -15,7 +15,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdbool.h>
#include <stdlib.h>
#include "bind.h"
@@ -144,7 +143,7 @@ static void startlockdown(void) {
HANDLE_EVENT(Tick) {
#ifdef _WIN32
- static int fewticks = 0;
+ static uint fewticks = 0;
// just check this every so often (roughly 0.1-0.3s depending on game)
if (lockdown && !(++fewticks & 7)) inhook_check();
#endif
@@ -198,7 +197,7 @@ static void VCALLCONV hook_DispatchInputEvent(void *this,
static bool find_DispatchInputEvent(void) {
#ifdef _WIN32
- // Crazy pointer-chasing path to get to DispachInputEvent (to log keypresses
+ // Crazy pointer-chasing path to get to DispatchInputEvent (to log keypresses
// and their associated binds):
// IGameUIFuncs interface
// -> CGameUIFuncs::GetDesktopResolution vfunc
diff --git a/src/alias.c b/src/alias.c
index b94a6d5..765f735 100644
--- a/src/alias.c
+++ b/src/alias.c
@@ -14,7 +14,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdbool.h>
#include <string.h>
#include "alias.h"
diff --git a/src/autojump.c b/src/autojump.c
index c4f54f4..d26ab9e 100644
--- a/src/autojump.c
+++ b/src/autojump.c
@@ -14,8 +14,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdbool.h>
-
#include "con_.h"
#include "engineapi.h"
#include "errmsg.h"
diff --git a/src/bind.c b/src/bind.c
index 762259d..41fd437 100644
--- a/src/bind.c
+++ b/src/bind.c
@@ -14,8 +14,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdbool.h>
-
#include "con_.h"
#include "dbg.h"
#include "errmsg.h"
diff --git a/src/bitbuf.h b/src/bitbuf.h
index 104c9a1..8700af3 100644
--- a/src/bitbuf.h
+++ b/src/bitbuf.h
@@ -17,8 +17,6 @@
#ifndef INC_BITBUF_H
#define INC_BITBUF_H
-#include <stdbool.h>
-
#include "intdefs.h"
// NOTE: This code assumes it's running on a little endian machine, because,
diff --git a/src/build/cmeta.c b/src/build/cmeta.c
index 260d33f..7f314c7 100644
--- a/src/build/cmeta.c
+++ b/src/build/cmeta.c
@@ -14,13 +14,13 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "../intdefs.h"
#include "../os.h"
#include "cmeta.h"
+#include "vec.h"
/*
* This file does C metadata parsing/scraping for the build system. This
@@ -73,16 +73,16 @@ Type *array_of(Type *base, int len) {
#include "../3p/chibicc/tokenize.c"
// one more copypaste from preprocess.c for #include <filename> and then I'm
// done I promise
-static char *join_tokens(Token *tok, Token *end) {
+static char *join_tokens(const Token *tok, const Token *end) {
int len = 1;
- for (Token *t = tok; t != end && t->kind != TK_EOF; t = t->next) {
+ for (const Token *t = tok; t != end && t->kind != TK_EOF; t = t->next) {
if (t != tok && t->has_space)
len++;
len += t->len;
}
char *buf = calloc(1, len);
int pos = 0;
- for (Token *t = tok; t != end && t->kind != TK_EOF; t = t->next) {
+ for (const Token *t = tok; t != end && t->kind != TK_EOF; t = t->next) {
if (t != tok && t->has_space)
buf[pos++] = ' ';
strncpy(buf + pos, t->loc, t->len);
@@ -166,7 +166,7 @@ const struct cmeta *cmeta_loadfile(const os_char *f) {
// picks it anyway, and gives far better diagnostics.
void cmeta_includes(const struct cmeta *cm,
void (*cb)(const char *f, bool issys, void *ctxt), void *ctxt) {
- Token *tp = (Token *)cm;
+ const Token *tp = (const Token *)cm;
if (!tp || !tp->next || !tp->next->next) return; // #, include, "string"
while (tp) {
if (!tp->at_bol || !equal(tp, "#")) { tp = tp->next; continue; }
@@ -187,7 +187,7 @@ void cmeta_includes(const struct cmeta *cm,
else if (equal(tp, "<")) {
tp = tp->next;
if (!tp) break;
- Token *end = tp;
+ const Token *end = tp;
while (!equal(end, ">")) {
end = end->next;
if (!end) return; // shouldn't happen in valid source obviously
@@ -210,7 +210,7 @@ void cmeta_includes(const struct cmeta *cm,
// we're not writing something weird. Don't write something weird!
void cmeta_conmacros(const struct cmeta *cm,
void (*cb)(const char *, bool, bool)) {
- Token *tp = (Token *)cm;
+ const Token *tp = (const Token *)cm;
if (!tp || !tp->next || !tp->next->next) return; // DEF_xyz, (, name
while (tp) {
bool isplusminus = false, isvar = false;
@@ -271,7 +271,7 @@ void cmeta_conmacros(const struct cmeta *cm,
}
const char *cmeta_findfeatmacro(const struct cmeta *cm) {
- Token *tp = (Token *)cm;
+ const Token *tp = (const Token *)cm;
if (!tp || !tp->next) return 0; // FEATURE, (
while (tp) {
if (equal(tp, "FEATURE") && equal(tp->next, "(")) {
@@ -288,7 +288,7 @@ const char *cmeta_findfeatmacro(const struct cmeta *cm) {
void cmeta_featinfomacros(const struct cmeta *cm, void (*cb)(
enum cmeta_featmacro type, const char *param, void *ctxt), void *ctxt) {
- Token *tp = (Token *)cm;
+ const Token *tp = (const Token *)cm;
if (!tp || !tp->next) return;
while (tp) {
int type = -1;
@@ -336,26 +336,73 @@ void cmeta_featinfomacros(const struct cmeta *cm, void (*cb)(
}
}
-void cmeta_evdefmacros(const struct cmeta *cm,
- void (*cb_def)(const char *name)) {
- Token *tp = (Token *)cm;
+struct vec_str VEC(const char *);
+
+static void pushmacroarg(const Token *last, const char *start,
+ struct vec_str *list) {
+ int len = last->loc - start + last->len;
+ char *dup = malloc(len + 1);
+ if (!dup) die1("couldn't allocate memory");
+ memcpy(dup, start, len);
+ dup[len] = '\0';
+ if (!vec_push(list, dup)) die1("couldn't append to array");
+}
+
+// XXX: maybe this should be used for the other functions too. it'd be less ugly
+// and handle closing parentheses better, but alloc for tokens we don't care
+// about. probably a worthy tradeoff?
+static const Token *macroargs(const Token *t, struct vec_str *list) {
+ int paren = 1;
+ const Token *last; // avoids copying extra ws/comments in
+ for (const char *start = t->loc; t; last = t, t = t->next) {
+ if (equal(t, "(")) {
+ ++paren;
+ }
+ else if (equal(t, ")")) {
+ if (!--paren) {
+ pushmacroarg(last, start, list);
+ return t->next;
+ }
+ }
+ else if (paren == 1 && equal(t, ",")) {
+ pushmacroarg(last, start, list);
+ t = t->next;
+ if (t) start = t->loc; // slightly annoying...
+ }
+ }
+ // I guess we handle this here.
+ fprintf(stderr, "cmeta: fatal: unexpected EOF in %s\n", t->filename);
+ exit(2);
+}
+
+void cmeta_evdefmacros(const struct cmeta *cm, void (*cb)(const char *name,
+ const char *const *params, int nparams, bool predicate)) {
+ const Token *tp = (const Token *)cm;
if (!tp || !tp->next || !tp->next->next) return; // DEF_EVENT, (, name
while (tp) {
+ bool predicate = true;
if (equal(tp, "DEF_EVENT") && equal(tp->next, "(")) {
- tp = tp->next->next;
- char *name = malloc(tp->len + 1);
- if (!name) die1("couldn't allocate memory");
- memcpy(name, tp->loc, tp->len);
- name[tp->len] = '\0';
- cb_def(name);
+ predicate = false;
}
- tp = tp->next;
+ else if (!equal(tp, "DEF_PREDICATE") || !equal(tp->next, "(")) {
+ tp = tp->next;
+ continue;
+ }
+ tp = tp->next->next;
+ struct vec_str args = {0};
+ tp = macroargs(tp, &args);
+ if (args.sz == 0) {
+ fprintf(stderr, "cmeta: fatal: missing event parameters in %s\n",
+ tp->filename);
+ exit(2);
+ }
+ cb(args.data[0], args.data + 1, args.sz - 1, predicate);
}
}
void cmeta_evhandlermacros(const struct cmeta *cm, const char *modname,
void (*cb_handler)(const char *evname, const char *modname)) {
- Token *tp = (Token *)cm;
+ const Token *tp = (const Token *)cm;
while (tp) {
if (equal(tp, "HANDLE_EVENT") && equal(tp->next, "(")) {
tp = tp->next->next;
diff --git a/src/build/cmeta.h b/src/build/cmeta.h
index 40c4ac5..48a2d6d 100644
--- a/src/build/cmeta.h
+++ b/src/build/cmeta.h
@@ -17,8 +17,6 @@
#ifndef INC_CMETA_H
#define INC_CMETA_H
-#include <stdbool.h>
-
#include "../os.h"
struct cmeta;
@@ -76,8 +74,8 @@ void cmeta_featinfomacros(const struct cmeta *cm, void (*cb)(
* Iterates through all event-related macros and takes note of which events are
* defined, giving a callback for each.
*/
-void cmeta_evdefmacros(const struct cmeta *cm, void (*cb)(const char *name));
-
+void cmeta_evdefmacros(const struct cmeta *cm, void (*cb)(const char *name,
+ const char *const *params, int nparams, bool predicate));
/*
* Iterates through all event-related macros and gives a callback for each event
* that is handled by the given module.
diff --git a/src/build/codegen.c b/src/build/codegen.c
index 04a9058..f5231c0 100644
--- a/src/build/codegen.c
+++ b/src/build/codegen.c
@@ -14,7 +14,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -139,12 +138,15 @@ push: if (!vec_push(vecp, param)) die("couldn't allocate memory");
DECL_SKIPLIST(static, event, struct event, const char *, 4)
struct event {
- const char *name;
+ usize name; // string, but tagged pointer - see below
+ const char *const *params;
+ int nparams;
+ //char pad[4];
struct vec_usize handlers; // strings, but with tagged pointers - see below
struct skiplist_hdr_event hdr;
};
static inline int cmp_event(struct event *e, const char *s) {
- return strcmp(e->name, s);
+ return strcmp((const char *)(e->name & ~1ull), s);
}
static inline struct skiplist_hdr_event *hdr_event(struct event *e) {
return &e->hdr;
@@ -152,12 +154,15 @@ static inline struct skiplist_hdr_event *hdr_event(struct event *e) {
DEF_SKIPLIST(static, event, cmp_event, hdr_event)
static struct skiplist_hdr_event events = {0};
-static void onevdef(const char *name) {
+static void onevdef(const char *name, const char *const *params, int nparams,
+ bool predicate) {
struct event *e = skiplist_get_event(&events, name);
if (!e) {
struct event *e = malloc(sizeof(*e));
if (!e) die("couldn't allocate memory");
- e->name = name;
+ // hack: using unused pointer bit to distinguish the two types of event
+ e->name = (usize)name | predicate;
+ e->params = params; e->nparams = nparams;
e->handlers = (struct vec_usize){0};
e->hdr = (struct skiplist_hdr_event){0};
skiplist_insert_event(&events, name, e);
@@ -445,19 +450,70 @@ _( "")
H_()
for (const struct event *e = events.x[0]; e; e = e->hdr.x[0]) {
_( "")
-F( "void _evemit_%s(void) {", e->name)
- for (usize *pp = e->handlers.data;
- pp - e->handlers.data < e->handlers.sz; ++pp) {
- const char *modname = (const char *)(*pp & ~1ull);
-F( " void _evhandler_%s_%s(void);", modname, e->name) // blegh.
- if (*pp & 1ull) {
- // note: has_* variables are already included by this point (above)
-F( " if (has_%s) _evhandler_%s_%s();", modname, modname, e->name)
+ // gotta break from the string emit macros for a sec in order to do the
+ // somewhat more complicated task sometimes referred to as a "for loop"
+ fprintf(out, "%s_%s(", e->name & 1 ? "bool CHECK" : "void EMIT",
+ (const char *)(e->name & ~1ull));
+ for (int n = 0; n < (int)e->nparams - 1; ++n) {
+ fprintf(out, "typeof(%s) a%d, ", e->params[n], n + 1);
+ }
+ if (e->nparams && strcmp(e->params[0], "void")) {
+ fprintf(out, "typeof(%s) a%d", e->params[e->nparams - 1],
+ e->nparams);
}
else {
-F( " _evhandler_%s_%s();", modname, e->name)
+ // just unilaterally doing void for now. when we're fully on C23
+ // eventually we can unilaterally do nothing instead
+ fputs("void", out);
}
+_( ") {")
+ for (usize *pp = e->handlers.data;
+ pp - e->handlers.data < e->handlers.sz; ++pp) {
+ const char *modname = (const char *)(*pp & ~1ull);
+ fprintf(out, "\t%s _evhandler_%s_%s(", e->name & 1 ? "bool" : "void",
+ modname, (const char *)(e->name & ~1ull));
+ for (int n = 0; n < (int)e->nparams - 1; ++n) {
+ fprintf(out, "typeof(%s) a%d, ", e->params[n], n + 1);
+ }
+ if (e->nparams && strcmp(e->params[0], "void")) {
+ fprintf(out, "typeof(%s) a%d", e->params[e->nparams - 1],
+ e->nparams);
+ }
+ else {
+ fputs("void", out);
+ }
+ fputs(");\n\t", out);
+ // conditional and non-conditional cases - in theory could be
+ // unified a bit but this is easier to make output relatively pretty
+ // note: has_* variables are already included by this point (above)
+ if (e->name & 1) {
+ if (*pp & 1) fprintf(out, "if (has_%s && !", modname);
+ else fprintf(out, "if (!");
+ fprintf(out, "_evhandler_%s_%s(", modname,
+ (const char *)(e->name & ~1ull));
+ // XXX: much repetitive drivel here
+ for (int n = 0; n < (int)e->nparams - 1; ++n) {
+ fprintf(out, "a%d,", n + 1);
+ }
+ if (e->nparams && strcmp(e->params[0], "void")) {
+ fprintf(out, "a%d", e->nparams);
+ }
+ fputs(")) return false;\n", out);
+ }
+ else {
+ if (*pp & 1) fprintf(out, "if (has_%s) ", modname);
+ fprintf(out, "_evhandler_%s_%s(", modname,
+ (const char *)(e->name & ~1ull));
+ for (int n = 0; n < (int)e->nparams - 1; ++n) {
+ fprintf(out, "a%d,", n + 1);
+ }
+ if (e->nparams && strcmp(e->params[0], "void")) {
+ fprintf(out, "a%d", e->nparams);
+ }
+ fputs(");\n", out);
+ }
}
+ if (e->name & 1) fputs("\treturn true;\n", out);
_( "}")
}
if (fclose(out) == EOF) die("couldn't fully write evglue.gen.h");
diff --git a/src/build/mkentprops.c b/src/build/mkentprops.c
index 300dafa..fdb6982 100644
--- a/src/build/mkentprops.c
+++ b/src/build/mkentprops.c
@@ -14,7 +14,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/src/build/mkgamedata.c b/src/build/mkgamedata.c
index 7d7a425..fdb2aef 100644
--- a/src/build/mkgamedata.c
+++ b/src/build/mkgamedata.c
@@ -14,7 +14,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/src/build/vec.h b/src/build/vec.h
index 50b0a3b..6b4dffb 100644
--- a/src/build/vec.h
+++ b/src/build/vec.h
@@ -4,7 +4,6 @@
#define INC_VEC_H
#include <errno.h>
-#include <stdbool.h>
#include <stdlib.h>
#include "../intdefs.h"
diff --git a/src/con_.c b/src/con_.c
index cb3db5b..f8b24f6 100644
--- a/src/con_.c
+++ b/src/con_.c
@@ -15,7 +15,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdbool.h>
#include <stddef.h> // should be implied by stdlib but glibc is dumb (offsetof)
#include <stdlib.h>
#include <stdio.h>
@@ -64,8 +63,12 @@ DECL_VFUNC_DYN(struct con_var *, FindVar, const char *)
DECL_VFUNC_DYN(struct con_cmd *, FindCommand, const char *)
DECL_VFUNC_DYN(void, CallGlobalChangeCallbacks, struct con_var *, const char *,
float)
-DECL_VFUNC_CDECLDYN(void, ConsoleColorPrintf, const struct con_colour *,
- const char *, ...)
+// sad: since adding the cool abstraction, we can't do varargs (because you
+// can't pass varargs to other varargs of course). we only get a pointer to it
+// via VFUNC so just declare the typedef here - I don't wanna write any more
+// macros today.
+typedef void (*ConsoleColorPrintf_func)(void *, const struct con_colour *,
+ const char *, ...);
static inline void initval(struct con_var *v) {
// v->strlen is set to defaultval len in _DEF_CVAR so we don't need to call
@@ -81,7 +84,7 @@ static inline void initval(struct con_var *v) {
// required, we call the Internal* virtual functions by actual virtual lookup.
// since the vtables are filled dynamically (below), we store this index; other
// indices are just offset from this one since the 3-or-4 functions are all
-// right next to each other. the #defines allow us to still use the nice VCALL
+// right next to each other. the #defines allow us to still use the nice vcall
// stuff.
static int vtidx_InternalSetValue;
#define vtidx_InternalSetFloatValue (vtidx_InternalSetValue + 1)
@@ -180,10 +183,10 @@ static void VCALLCONV ChangeStringValue(struct con_var *this, const char *s,
// do need callbacks for at least one feature, so do our own minimal thing
if (this->cb) this->cb(this);
// also call global callbacks, as is polite.
- VCALL(_con_iface, CallGlobalChangeCallbacks, this, old, oldf);
+ CallGlobalChangeCallbacks(_con_iface, this, old, oldf);
}
-static void VCALLCONV InternalSetValue(struct con_var *this, const char *v) {
+static void VCALLCONV InternalSetValue_impl(struct con_var *this, const char *v) {
float oldf = this->fval;
float newf = atof(v);
char tmp[32];
@@ -198,7 +201,7 @@ static void VCALLCONV InternalSetValue(struct con_var *this, const char *v) {
if (!(this->base.flags & CON_NOPRINT)) ChangeStringValue(this, v, oldf);
}
-static void VCALLCONV InternalSetFloatValue(struct con_var *this, float v) {
+static void VCALLCONV InternalSetFloatValue_impl(struct con_var *this, float v) {
if (v == this->fval) return;
ClampValue(this, &v);
float old = this->fval;
@@ -210,7 +213,7 @@ static void VCALLCONV InternalSetFloatValue(struct con_var *this, float v) {
}
}
-static void VCALLCONV InternalSetIntValue(struct con_var *this, int v) {
+static void VCALLCONV InternalSetIntValue_impl(struct con_var *this, int v) {
if (v == this->ival) return;
float f = (float)v;
if (ClampValue(this, &f)) v = (int)f;
@@ -233,22 +236,22 @@ DECL_VFUNC_DYN(void, InternalSetColorValue, struct con_colour)
static void VCALLCONV SetValue_str_thunk(void *thisoff, const char *v) {
struct con_var *this = mem_offset(thisoff,
-offsetof(struct con_var, vtable_iconvar));
- VCALL(&this->parent->base, InternalSetValue, v);
+ InternalSetValue(&this->parent->base, v);
}
static void VCALLCONV SetValue_f_thunk(void *thisoff, float v) {
struct con_var *this = mem_offset(thisoff,
-offsetof(struct con_var, vtable_iconvar));
- VCALL(&this->parent->base, InternalSetFloatValue, v);
+ InternalSetFloatValue(&this->parent->base, v);
}
static void VCALLCONV SetValue_i_thunk(void *thisoff, int v) {
struct con_var *this = mem_offset(thisoff,
-offsetof(struct con_var, vtable_iconvar));
- VCALL(&this->parent->base, InternalSetIntValue, v);
+ InternalSetIntValue(&this->parent->base, v);
}
static void VCALLCONV SetValue_colour_thunk(void *thisoff, struct con_colour v) {
struct con_var *this = mem_offset(thisoff,
-offsetof(struct con_var, vtable_iconvar));
- VCALL(&this->parent->base, InternalSetColorValue, v);
+ InternalSetColorValue(&this->parent->base, v);
}
// more misc thunks, hopefully these just compile to a sub and a jmp
@@ -322,13 +325,13 @@ void *_con_vtab_iconvar[7] = {
};
void con_reg(void *cmd_or_var) {
- VCALL(_con_iface, RegisterConCommand, cmd_or_var);
+ RegisterConCommand(_con_iface, cmd_or_var);
}
void con_init(void) {
// FIXME: ConsoleColorPrintf isn't working in Portal 2, possible regression?
_con_colourmsgf = VFUNC(_con_iface, ConsoleColorPrintf);
- dllid = VCALL(_con_iface, AllocateDLLIdentifier);
+ dllid = AllocateDLLIdentifier(_con_iface);
void **pc = _con_vtab_cmd + 3 + NVDTOR, **pv = _con_vtab_var + 3 + NVDTOR,
**pi = _con_vtab_iconvar
@@ -362,13 +365,13 @@ void con_init(void) {
*pv++ = (void *)&Init;
// var-specific
vtidx_InternalSetValue = pv - _con_vtab_var;
- *pv++ = (void *)&InternalSetValue;
- *pv++ = (void *)&InternalSetFloatValue;
- *pv++ = (void *)&InternalSetIntValue;
+ *pv++ = (void *)&InternalSetValue_impl;
+ *pv++ = (void *)&InternalSetFloatValue_impl;
+ *pv++ = (void *)&InternalSetIntValue_impl;
if (GAMETYPE_MATCHES(L4D2x) || GAMETYPE_MATCHES(Portal2)) { // ugh, annoying
// This is InternalSetColorValue, but that's basically the same thing,
// when you think about it.
- *pv++ = (void *)&InternalSetIntValue;
+ *pv++ = (void *)&InternalSetIntValue_impl;
}
*pv++ = (void *)&ClampValue;;
*pv++ = (void *)&ChangeStringValue;
@@ -415,15 +418,15 @@ bool con_detect(int pluginver) {
// *actually* calls the const-overloaded FindVar on other branches,
// which just happens to still work fine. From there, we can figure out
// the actual ABI to use to avoid spectacular crashes.
- if (VCALL(_con_iface, FindCommandBase_p2, "portal2_square_portals")) {
+ if (FindCommandBase_p2(_con_iface, "portal2_square_portals")) {
_gametype_tag |= _gametype_tag_Portal2;
return true;
}
- if (VCALL(_con_iface, FindCommand_nonp2, "l4d2_snd_adrenaline")) {
+ if (FindCommand_nonp2(_con_iface, "l4d2_snd_adrenaline")) {
// while we're here, also distinguish Survivors, the stupid Japanese
// arcade game a few people seem to care about for some reason
// (which for some other reason also has some vtable changes)
- if (VCALL(_con_iface, FindVar_nonp2, "avatarbasemodel")) {
+ if (FindVar_nonp2(_con_iface, "avatarbasemodel")) {
_gametype_tag |= _gametype_tag_L4DS;
}
else {
@@ -431,7 +434,7 @@ bool con_detect(int pluginver) {
}
return true;
}
- if (VCALL(_con_iface, FindVar_nonp2, "z_difficulty")) {
+ if (FindVar_nonp2(_con_iface, "z_difficulty")) {
_gametype_tag |= _gametype_tag_L4D1;
return true;
}
@@ -463,16 +466,16 @@ bool con_detect(int pluginver) {
}
void con_disconnect(void) {
- VCALL(_con_iface, UnregisterConCommands, dllid);
+ UnregisterConCommands(_con_iface, dllid);
freevars();
}
struct con_var *con_findvar(const char *name) {
- return VCALL(_con_iface, FindVar, name);
+ return FindVar(_con_iface, name);
}
struct con_cmd *con_findcmd(const char *name) {
- return VCALL(_con_iface, FindCommand, name);
+ return FindCommand(_con_iface, name);
}
#define GETTER(T, N, M) T N(const struct con_var *v) { return v->parent->M; }
diff --git a/src/con_.h b/src/con_.h
index 1de9bc5..a43294c 100644
--- a/src/con_.h
+++ b/src/con_.h
@@ -18,8 +18,6 @@
#ifndef INC_CON_H
#define INC_CON_H
-#include <stdbool.h>
-
#include "intdefs.h"
#if defined(__GNUC__) || defined(__clang__)
diff --git a/src/democustom.c b/src/democustom.c
index c7de77b..f8c7c9d 100644
--- a/src/democustom.c
+++ b/src/democustom.c
@@ -14,8 +14,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdbool.h>
-
#include "bitbuf.h"
#include "con_.h"
#include "democustom.h"
@@ -121,7 +119,7 @@ INIT {
// > there might be some other l4d2 versions where it's 11 but idk
// So here we have to figure out the network protocol version!
// NOTE: assuming engclient != null as GEBN index relies on client version
- int buildnum = VCALL(engclient, GetEngineBuildNumber);
+ int buildnum = GetEngineBuildNumber(engclient);
// condition is redundant until other GetEngineBuildNumber offsets are added
// if (GAMETYPE_MATCHES(L4D2)) {
nbits_msgtype = 6;
diff --git a/src/demorec.c b/src/demorec.c
index 50128f0..4434534 100644
--- a/src/demorec.c
+++ b/src/demorec.c
@@ -15,7 +15,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdbool.h>
#include <string.h>
#include "con_.h"
diff --git a/src/engineapi.c b/src/engineapi.c
index cef085b..8cc3dd6 100644
--- a/src/engineapi.c
+++ b/src/engineapi.c
@@ -14,7 +14,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdbool.h>
#include <stdlib.h> // used in generated code
#include <string.h> // "
@@ -42,7 +41,6 @@ DECL_VFUNC(void *, GetGlobalVars, 1)
void *globalvars;
DECL_VFUNC_DYN(void *, GetAllServerClasses)
-DECL_VFUNC_DYN(int, GetEngineBuildNumber)
DECL_VFUNC(int, GetEngineBuildNumber_newl4d2, 99) // duping gamedata entry, yuck
@@ -71,7 +69,7 @@ bool engineapi_init(int pluginver) {
// }
void *pim = factory_server("PlayerInfoManager002", 0);
- if (pim) globalvars = VCALL(pim, GetGlobalVars);
+ if (pim) globalvars = GetGlobalVars(pim);
void *srvdll;
// TODO(compat): add this back when there's gamedata for 009 (no point atm)
@@ -93,7 +91,7 @@ bool engineapi_init(int pluginver) {
// till gamedata is set up, so we have to have a bit of redundant logic here
// to bootstrap things.
if (GAMETYPE_MATCHES(L4D2) && GAMETYPE_MATCHES(Client013) &&
- VCALL(engclient, GetEngineBuildNumber_newl4d2) >= 2200) {
+ GetEngineBuildNumber_newl4d2(engclient) >= 2200) {
_gametype_tag |= _gametype_tag_TheLastStand;
}
@@ -104,7 +102,7 @@ bool engineapi_init(int pluginver) {
if (!gameinfo_init()) { con_disconnect(); return false; }
if (has_vtidx_GetAllServerClasses && has_sz_SendProp &&
has_off_SP_varname && has_off_SP_offset) {
- initentprops(VCALL(srvdll, GetAllServerClasses));
+ initentprops(GetAllServerClasses(srvdll));
}
return true;
}
diff --git a/src/ent.c b/src/ent.c
index 9d69bf0..4a457af 100644
--- a/src/ent.c
+++ b/src/ent.c
@@ -14,8 +14,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdbool.h>
-
#include "engineapi.h"
#include "errmsg.h"
#include "feature.h"
@@ -37,7 +35,7 @@ void *ent_getedict(int idx) {
return mem_offset(*edicts, sz_edict * idx);
}
else {
- return VCALL(engserver, PEntityOfEntIndex, idx);
+ return PEntityOfEntIndex(engserver, idx);
}
}
diff --git a/src/event.h b/src/event.h
index e439201..86a443e 100644
--- a/src/event.h
+++ b/src/event.h
@@ -20,15 +20,53 @@
#define _EVENT_CAT4_(a, b, c, d) a##b##c##d
#define _EVENT_CAT4(a, b, c, d) _EVENT_CAT4_(a, b, c, d)
-#define DECL_EVENT(evname) void _evemit_##evname(void);
-#define DEF_EVENT(evname) \
- DECL_EVENT(evname) \
- static inline void _evown_##evname(void) { _evemit_##evname(); }
-#define EMIT_EVENT(evname) _evown_##evname()
-
-#define HANDLE_EVENT(evname) \
- void _EVENT_CAT4(_evhandler_, MODULE_NAME, _, evname)(void) \
- /* function body here */
+/*
+ * Declares an event defined somewhere in the codebase, allowing a handler to be
+ * defined with HANDLE_EVENT() below. Takes an optional list of types for
+ * parameters. The handler will be called every time the event is emitted by the
+ * declaring module.
+ */
+#define DECL_EVENT(evname, ...) typedef void _must_declare_event_##evname;
+
+/*
+ * Declares a predicate - a special type of even returning bool. Predicates are
+ * used to determine whether some other action should be performed, and
+ * generally should not have side effects, since they get short-circuited and
+ * thus won't always fire when a check is being performed.
+ */
+#define DECL_PREDICATE(evname, ...) typedef bool _must_declare_event_##evname;
+
+/*
+ * Defines an event belonging to this module. Doing so allows EMIT_<event>() to
+ * be called to fire handlers in all modules. Two modules (i.e. source files)
+ * cannot define an event (or predicate) with the same name.
+ */
+#define DEF_EVENT(event, ...) void EMIT_##event(__VA_ARGS__);
+
+/*
+ * Defines a predicate belonging to this module. Doing so allows CHECK_<pred>()
+ * to be called to determine whether to perform some action. Predicates share a
+ * namespace with events and two modules cannot define two things with the same
+ * name.
+ */
+#define DEF_PREDICATE(pred, ...) bool CHECK_##pred(__VA_ARGS__);
+
+/*
+ * Begins an event handler function that gets hooked up to an event by the code
+ * generation system. This is type-generic: if the event is a regular event,
+ * the function will return void; if it is a predicate it will return bool.
+ * Takes a function argument list which must match the type lists given to the
+ * above DEF/DECL macros.
+ *
+ * Note again that predicates are not guaranteed to fire at all due to
+ * short-circuiting and thus generally should not have side effects.
+ *
+ * In the current event implementation, each source file may handle only one of
+ * each event type, as any more wouldn't be too useful anyway.
+ */
+#define HANDLE_EVENT(evname, ...) \
+ _must_declare_event_##evname _EVENT_CAT4(_evhandler_, MODULE_NAME, _, \
+ evname)(__VA_ARGS__) /* function body here */
#endif
diff --git a/src/extmalloc.c b/src/extmalloc.c
index 9117db0..edd1d54 100644
--- a/src/extmalloc.c
+++ b/src/extmalloc.c
@@ -36,25 +36,17 @@ IMPORT void *g_pMemAlloc;
// affected by naming (overloads are grouped, and *reversed* inside of a
// group!?), we get this amusing ABI difference between platforms:
#ifdef _WIN32
-DECL_VFUNC(void *, Alloc, 1, usize sz)
-DECL_VFUNC(void *, Realloc, 3, void *mem, usize sz)
-DECL_VFUNC(void, Free, 5, void *mem)
+DECL_VFUNC(void *, Alloc, 1, usize)
+DECL_VFUNC(void *, Realloc, 3, void *, usize)
+DECL_VFUNC(void, Free, 5, void *)
#else
-DECL_VFUNC(void *, Alloc, 0, usize sz)
-DECL_VFUNC(void *, Realloc, 1, void *mem, usize sz)
-DECL_VFUNC(void, Free, 2, void *mem)
+DECL_VFUNC(void *, Alloc, 0, usize)
+DECL_VFUNC(void *, Realloc, 1, void *, usize)
+DECL_VFUNC(void, Free, 2, void *)
#endif
-void *extmalloc(usize sz) {
- return VCALL(g_pMemAlloc, Alloc, sz);
-}
-
-void *extrealloc(void *mem, usize sz) {
- return VCALL(g_pMemAlloc, Realloc, mem, sz);
-}
-
-void extfree(void *mem) {
- VCALL(g_pMemAlloc, Free, mem);
-}
+void *extmalloc(usize sz) { return Alloc(g_pMemAlloc, sz); }
+void *extrealloc(void *mem, usize sz) { return Realloc(g_pMemAlloc, mem, sz); }
+void extfree(void *mem) { Free(g_pMemAlloc, mem); }
// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/feature.h b/src/feature.h
index 5277bca..e1e4688 100644
--- a/src/feature.h
+++ b/src/feature.h
@@ -17,8 +17,6 @@
#ifndef INC_FEATURE_H
#define INC_FEATURE_H
-#include <stdbool.h>
-
#define _FEATURE_CAT1(a, b) a##b
#define _FEATURE_CAT(a, b) _FEATURE_CAT1(a, b)
diff --git a/src/fov.c b/src/fov.c
index c7c72ed..9ab1137 100644
--- a/src/fov.c
+++ b/src/fov.c
@@ -17,8 +17,6 @@
// TODO(linux): theoretically, probably ifdef out the cvar-replacement stuff; we
// expect any game that's been ported to linux to already have fov_desired
-#include <stdbool.h>
-
#include "con_.h"
#include "engineapi.h"
#include "errmsg.h"
@@ -74,10 +72,9 @@ static void fovcb(struct con_var *v) {
}
// ensure FOV is applied on load, if the engine wouldn't do that itself
-HANDLE_EVENT(ClientActive) {
- if (real_fov_desired == fov_desired) {
- void *player = ent_get(1); // "
- if (player) orig_SetDefaultFOV(player, con_getvari(fov_desired));
+HANDLE_EVENT(ClientActive, struct edict *player) {
+ if (player && real_fov_desired == fov_desired) {
+ orig_SetDefaultFOV(player, con_getvari(fov_desired));
}
}
diff --git a/src/fov.h b/src/fov.h
index a057fb7..63cd170 100644
--- a/src/fov.h
+++ b/src/fov.h
@@ -17,8 +17,6 @@
#ifndef INC_FOV_H
#define INC_FOV_H
-#include <stdbool.h>
-
bool fov_init(bool has_ent);
void fov_end(void);
diff --git a/src/gamedata.c b/src/gamedata.c
index 7b89257..639b2f8 100644
--- a/src/gamedata.c
+++ b/src/gamedata.c
@@ -14,8 +14,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdbool.h>
-
#include "gametype.h"
// same as gamedata.h, not worth putting in its own thing
diff --git a/src/gamedata.h b/src/gamedata.h
index 678d572..471e5bb 100644
--- a/src/gamedata.h
+++ b/src/gamedata.h
@@ -17,8 +17,6 @@
#ifndef INC_GAMEDATA_H
#define INC_GAMEDATA_H
-#include <stdbool.h>
-
#ifdef _WIN32
#define NVDTOR 1
#else
diff --git a/src/gameinfo.c b/src/gameinfo.c
index b371e76..f8b5311 100644
--- a/src/gameinfo.c
+++ b/src/gameinfo.c
@@ -14,7 +14,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdbool.h>
#ifdef _WIN32
#include <shlwapi.h>
#endif
@@ -260,7 +259,7 @@ bool gameinfo_init(void) {
// to respect the system code page setting, otherwise some users using e.g.
// Cyrillic folder names and successfully loading their speedgames won't be
// able to load SST. Thanks Windows!
- const char *lcpgamedir = VCALL(engclient, GetGameDirectory);
+ const char *lcpgamedir = GetGameDirectory(engclient);
int gamedirlen = MultiByteToWideChar(CP_ACP, 0, lcpgamedir,
strlen(lcpgamedir), gamedir, sizeof(gamedir) / sizeof(*gamedir));
if (!gamedirlen) {
diff --git a/src/hook.h b/src/hook.h
index ff1acff..8d91508 100644
--- a/src/hook.h
+++ b/src/hook.h
@@ -17,8 +17,6 @@
#ifndef INC_HOOK_H
#define INC_HOOK_H
-#include <stdbool.h>
-
#include "intdefs.h"
bool hook_init(void);
diff --git a/src/kv.c b/src/kv.c
index 7720d46..019d017 100644
--- a/src/kv.c
+++ b/src/kv.c
@@ -14,8 +14,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdbool.h>
-
#include "intdefs.h"
#include "kv.h"
#include "unreachable.h"
diff --git a/src/kv.h b/src/kv.h
index 689f5bd..63a9146 100644
--- a/src/kv.h
+++ b/src/kv.h
@@ -17,8 +17,6 @@
#ifndef INC_KV_H
#define INC_KV_H
-#include <stdbool.h>
-
#include "intdefs.h"
/*
diff --git a/src/l4dwarp.c b/src/l4dwarp.c
index 5412b64..5540763 100644
--- a/src/l4dwarp.c
+++ b/src/l4dwarp.c
@@ -34,14 +34,14 @@ REQUIRE_GAMEDATA(off_eyeang)
REQUIRE_GAMEDATA(vtidx_Teleport)
DECL_VFUNC_DYN(void *, GetBaseEntity)
-DECL_VFUNC_DYN(void, Teleport, const struct vec3f *pos, const struct vec3f *ang,
- const struct vec3f *vel)
+DECL_VFUNC_DYN(void, Teleport, const struct vec3f */*pos*/,
+ const struct vec3f */*pos*/, const struct vec3f */*vel*/)
DEF_CCMD_HERE_UNREG(sst_l4d_testwarp, "Simulate a bot warping to you",
CON_SERVERSIDE | CON_CHEAT) {
struct edict *ed = ent_getedict(con_cmdclient + 1);
if (!ed) { errmsg_errorx("couldn't access player entity"); return; }
- void *e = VCALL(ed->ent_unknown, GetBaseEntity); // is this call required?
+ void *e = GetBaseEntity(ed->ent_unknown); // is this call required?
struct vec3f *org = mem_offset(e, off_entpos);
struct vec3f *ang = mem_offset(e, off_eyeang);
// L4D idle warps go up to 10 units behind relative to whatever angle the
@@ -49,7 +49,7 @@ DEF_CCMD_HERE_UNREG(sst_l4d_testwarp, "Simulate a bot warping to you",
// displacing vertically
float pitch = ang->x * M_PI / 180, yaw = ang->y * M_PI / 180;
float shift = -10 * cos(pitch);
- VCALL(e, Teleport, &(struct vec3f){org->x + shift * cos(yaw),
+ Teleport(e, &(struct vec3f){org->x + shift * cos(yaw),
org->y + shift * sin(yaw), org->z}, 0, &(struct vec3f){0, 0, 0});
}
diff --git a/src/os.h b/src/os.h
index 3d3ab00..c954d1a 100644
--- a/src/os.h
+++ b/src/os.h
@@ -17,8 +17,6 @@
#ifndef INC_OS_H
#define INC_OS_H
-#include <stdbool.h>
-
/*
* Here we declare an absolute ton of wrappers, macros, compatibility shims,
* reimplementations and so on to try in vain to sweep the inconsistencies
diff --git a/src/portalcolours.c b/src/portalcolours.c
index 231aa01..2231da4 100644
--- a/src/portalcolours.c
+++ b/src/portalcolours.c
@@ -14,7 +14,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdbool.h>
#include <string.h>
#include "con_.h"
diff --git a/src/sst.c b/src/sst.c
index c959d65..af15c66 100644
--- a/src/sst.c
+++ b/src/sst.c
@@ -14,7 +14,6 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-#include <stdbool.h>
#include <string.h>
#ifdef _WIN32
@@ -429,20 +428,17 @@ DECL_VFUNC_DYN(void, ServerCommand, const char *)
DEF_CVAR(_sst_onload_echo, "EXPERIMENTAL! Don't rely on this existing!", "",
CON_HIDDEN)
-DEF_EVENT(ClientActive)
-DEF_EVENT(Tick)
+DEF_EVENT(ClientActive, struct edict */*player*/)
+DEF_EVENT(Tick, bool /*simulating*/)
// Quick and easy server tick event. Eventually, we might want a deeper hook
// for anything timing-sensitive, but this will do for our current needs.
static void VCALLCONV GameFrame(void *this, bool simulating) {
- EMIT_EVENT(Tick);
+ EMIT_Tick(simulating);
}
static void VCALLCONV ClientActive(void *this, struct edict *player) {
- // XXX: it's kind of dumb that we get handed the edict here then go look it
- // up again in fov.c but I can't be bothered refactoring any further now
- // that this finally works, do something later lol
- EMIT_EVENT(ClientActive);
+ EMIT_ClientActive(player);
// continuing dumb portal hack. didn't even seem worth adding a feature for
if (has_vtidx_ServerCommand && con_getvarstr(_sst_onload_echo)[0]) {
@@ -454,7 +450,7 @@ static void VCALLCONV ClientActive(void *this, struct edict *player) {
memcpy(s + 6, con_getvarstr(_sst_onload_echo),
_sst_onload_echo->strlen);
memcpy(s + 6 + _sst_onload_echo->strlen - 1, "\"\n", 3);
- VCALL(engserver, ServerCommand, s);
+ ServerCommand(engserver, s);
free(s);
}
}
diff --git a/src/sst.h b/src/sst.h
index d432480..a959e00 100644
--- a/src/sst.h
+++ b/src/sst.h
@@ -21,8 +21,8 @@
/* misc stuff that doesn't belong anywhere else */
-DECL_EVENT(ClientActive)
-DECL_EVENT(Tick)
+DECL_EVENT(ClientActive, struct edict */*player*/)
+DECL_EVENT(Tick, bool /*simulating*/)
extern void *clientlib;
diff --git a/src/vcall.h b/src/vcall.h
index caee70a..778ba09 100644
--- a/src/vcall.h
+++ b/src/vcall.h
@@ -35,32 +35,108 @@
#define VCALLCONV
#endif
+// black magic argument list maker thingmy, similar to the PPMAGIC_MAP thing,
+// but slightly different, so we get to have all this nonsense twice. not sorry
+
+// note: arg numbering is counting down instead of up because it's easier to
+// treat the vararg macros like a stack, and doesn't actually matter otherwise
+// also note: I just did 16. that should be enough
+#define _VCALL_ARG00()
+#define _VCALL_ARG01(t) typeof(t) a1
+#define _VCALL_ARG02(t1, t2) typeof(t1) a2, typeof(t2) a1
+#define _VCALL_ARG03(t1, t2, t3) typeof(t1) a3, typeof(t2) a2, typeof(t3) a1
+#define _VCALL_ARG04(t1, t2, t3, t4) \
+ typeof(t1) a4, typeof(t2) a3, typeof(t3) a2, typeof(t4) a1
+#define _VCALL_ARG05(t, ...) typeof(t) a5, _VCALL_ARG04(__VA_ARGS__)
+#define _VCALL_ARG06(t, ...) typeof(t) a6, _VCALL_ARG05(__VA_ARGS__)
+#define _VCALL_ARG07(t, ...) typeof(t) a7, _VCALL_ARG06(__VA_ARGS__)
+#define _VCALL_ARG08(t, ...) typeof(t) a8, _VCALL_ARG07(__VA_ARGS__)
+#define _VCALL_ARG09(t, ...) typeof(t) a9, _VCALL_ARG08(__VA_ARGS__)
+#define _VCALL_ARG10(t, ...) typeof(t) a10, _VCALL_ARG09(__VA_ARGS__)
+#define _VCALL_ARG11(t, ...) typeof(t) a11, _VCALL_ARG10(__VA_ARGS__)
+#define _VCALL_ARG12(t, ...) typeof(t) a12, _VCALL_ARG11(__VA_ARGS__)
+#define _VCALL_ARG13(t, ...) typeof(t) a13, _VCALL_ARG12(__VA_ARGS__)
+#define _VCALL_ARG14(t, ...) typeof(t) a14, _VCALL_ARG14(__VA_ARGS__)
+#define _VCALL_ARG15(t, ...) typeof(t) a15, _VCALL_ARG15(__VA_ARGS__)
+#define _VCALL_ARG16(t, ...) typeof(t) a16, _VCALL_ARG16(__VA_ARGS__)
+
+#define _VCALL_ARG_N(x01, x02, x03, x04, x05, x06, x07, x08, x09, x10, \
+ x11, x12, x13, x14, x15, x16, N, ...) \
+ _VCALL_ARG##N
+
+#define _VCALL_ARGLIST(...) \
+ _VCALL_ARG_N(__VA_ARGS__ __VA_OPT__(,) \
+ 16, 15, 14, 13, 12, 11, 10, 09, 08, 07, 06, 05, 04, 03, 02, 01, 00) \
+ (__VA_ARGS__)
+
+// aannd we need these as well...
+#define _VCALL_PASS00()
+#define _VCALL_PASS01() a1
+#define _VCALL_PASS02() a2, a1
+#define _VCALL_PASS03() a3, a2, a1
+#define _VCALL_PASS04() a4, a3, a2, a1
+#define _VCALL_PASS05() a5, _VCALL_PASS04()
+#define _VCALL_PASS06() a6, _VCALL_PASS05()
+#define _VCALL_PASS07() a7, _VCALL_PASS06()
+#define _VCALL_PASS08() a8, _VCALL_PASS07()
+#define _VCALL_PASS09() a9, _VCALL_PASS08()
+#define _VCALL_PASS10() a10, _VCALL_PASS09()
+#define _VCALL_PASS11() a11, _VCALL_PASS10()
+#define _VCALL_PASS12() a12, _VCALL_PASS11()
+#define _VCALL_PASS13() a13, _VCALL_PASS12()
+#define _VCALL_PASS14() a14, _VCALL_PASS13()
+#define _VCALL_PASS15() a15, _VCALL_PASS14()
+#define _VCALL_PASS16() a16, _VCALL_PASS15()
+#define _VCALL_PASS_N(x01, x02, x03, x04, x05, x06, x07, x08, x09, x10, x11, \
+ x12, x13, x14, x15, x16, N, ...) \
+ _VCALL_PASS##N
+
+#define _VCALL_PASSARGS(...) \
+ _VCALL_PASS_N(__VA_ARGS__ __VA_OPT__(,) 16, 15, 14, 13, 12, 11, 10, 09, \
+ 08, 07, 06, 05, 04, 03, 02, 01, 00)()
+
+#define VFUNC(x, name) ((*(name##_func **)(x))[vtidx_##name])
+#define VCALL(x, name, ...) VFUNC(x, name)(x, ##__VA_ARGS__)
+
+// even more magic: return keyword only if not void
+#define _VCALL_RETKW_(x, n, ...) n
+#define _VCALL_RETKW(...) _VCALL_RETKW_(__VA_ARGS__, return,)
+#define _VCALL_RET_void() x, ,
+#define _VCALL_RET(t) _VCALL_RETKW(_VCALL_RET_##t())
+
+// I thought static inline was supposed to prevent unused warnings???
+#if defined(__GNUC__) || defined(__clang__)
+#define _VCALL_UNUSED __attribute__((unused))
+#else
+#define _VCALL_UNUSED
+#endif
+
#define _DECL_VFUNC_DYN(ret, conv, name, ...) \
- /* XXX: GCC extension, seems worthwhile vs having two macros for one thing.
- Replace with __VA_OPT__(,) whenever that gets fully standardised. */ \
- typedef ret (*conv name##_func)(void *this, ##__VA_ARGS__);
+ typedef typeof(ret) (*conv name##_func)(void * __VA_OPT__(,) __VA_ARGS__); \
+ static inline _VCALL_UNUSED typeof(ret) name(void *this __VA_OPT__(,) \
+ _VCALL_ARGLIST(__VA_ARGS__)) { \
+ _VCALL_RET(ret) VCALL(this, name __VA_OPT__(,) \
+ _VCALL_PASSARGS(__VA_ARGS__)); \
+ }
#define _DECL_VFUNC(ret, conv, name, idx, ...) \
enum { vtidx_##name = (idx) }; \
- _DECL_VFUNC_DYN(ret, conv, name, ##__VA_ARGS__)
+ _DECL_VFUNC_DYN(ret, conv, name __VA_OPT__(,) __VA_ARGS__)
/* Define a virtual function with a known index */
#define DECL_VFUNC(ret, name, idx, ...) \
- _DECL_VFUNC(ret, VCALLCONV, name, idx, ##__VA_ARGS__)
+ _DECL_VFUNC(ret, VCALLCONV, name, idx __VA_OPT__(,) __VA_ARGS__)
/* Define a virtual function with a known index, without thiscall convention */
#define DECL_VFUNC_CDECL(ret, name, idx, ...) \
- _DECL_VFUNC(ret, , name, idx, ##__VA_ARGS__)
+ _DECL_VFUNC(ret, , name, idx __VA_OPT__(,) __VA_ARGS__)
/* Define a virtual function with an index defined elsewhere */
#define DECL_VFUNC_DYN(ret, name, ...) \
- _DECL_VFUNC_DYN(ret, VCALLCONV, name, ##__VA_ARGS__)
+ _DECL_VFUNC_DYN(ret, VCALLCONV, name __VA_OPT__(,) __VA_ARGS__)
/* Define a virtual function with an index defined elsewhere, without thiscall */
#define DECL_VFUNC_CDECLDYN(ret, name, ...) \
- _DECL_VFUNC_DYN(ret, , name, ##__VA_ARGS__)
-
-#define VFUNC(x, name) ((*(name##_func **)(x))[vtidx_##name])
-#define VCALL(x, name, ...) VFUNC(x, name)(x, ##__VA_ARGS__)
+ _DECL_VFUNC_DYN(ret, , name __VA_OPT__(,) __VA_ARGS__)
#endif
diff --git a/src/x86util.h b/src/x86util.h
index 0ae89ae..85a824e 100644
--- a/src/x86util.h
+++ b/src/x86util.h
@@ -17,8 +17,6 @@
#ifndef INC_X86UTIL_H
#define INC_X86UTIL_H
-#include <stdbool.h>
-
#include "errmsg.h"
#include "x86.h"
@@ -35,3 +33,5 @@
} while (0)
#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80