aboutsummaryrefslogtreecommitdiff
path: root/src/build
diff options
context:
space:
mode:
Diffstat (limited to 'src/build')
-rw-r--r--src/build/gluegen.c121
-rw-r--r--src/build/mkentprops.c23
-rw-r--r--src/build/mkgamedata.c73
3 files changed, 163 insertions, 54 deletions
diff --git a/src/build/gluegen.c b/src/build/gluegen.c
index 4abfd2b..574aa92 100644
--- a/src/build/gluegen.c
+++ b/src/build/gluegen.c
@@ -602,18 +602,44 @@ static cold noreturn diewrite() { die(100, "couldn't write to file"); }
_("/* This file is autogenerated by src/build/gluegen.c. DO NOT EDIT! */")
#define H() H_() _("")
-static void recursefeatdescs(FILE *out, s16 node) {
+static void recursedbgmodnames(FILE *out, s16 node) {
if (node < 0) {
+ if (!(mod_flags[-node] & HAS_INIT)) return;
+F( " switch (status_%.*s) {",
+ mod_names[-node].len, mod_names[-node].s)
+_( " case FEAT_SKIP: colour = &grey; break;")
+_( " case FEAT_OK: colour = &green; break;")
+_( " default: colour = &red; break;")
+_( " }")
if (mod_featdescs[-node].s) {
+F( " con_colourmsg(colour, featmsgs[status_%.*s], \"%.*s (\" %.*s \")\");",
+ mod_names[-node].len, mod_names[-node].s,
+ mod_names[-node].len, mod_names[-node].s,
+ mod_featdescs[-node].len, mod_featdescs[-node].s)
+ }
+ else {
+F( " con_colourmsg(colour, featmsgs[status_%.*s], \"%.*s\");",
+ mod_names[-node].len, mod_names[-node].s,
+ mod_names[-node].len, mod_names[-node].s)
+ }
+ }
+ else if (node > 0) {
+ for (int i = 0; i < 16; ++i) {
+ recursedbgmodnames(out, radices[node].children[i]);
+ }
+ }
+}
+
+static void recursefeatdescs(FILE *out, s16 node) {
+ if (node < 0) {
F( " if (status_%.*s != FEAT_SKIP) {",
- mod_names[-node].len, mod_names[-node].s)
+ mod_names[-node].len, mod_names[-node].s)
F( " con_colourmsg(status_%.*s == FEAT_OK ? &green : &red,",
- mod_names[-node].len, mod_names[-node].s)
+ mod_names[-node].len, mod_names[-node].s)
F( " featmsgs[status_%.*s], %.*s);",
- mod_names[-node].len, mod_names[-node].s,
- mod_featdescs[-node].len, mod_featdescs[-node].s)
+ mod_names[-node].len, mod_names[-node].s,
+ mod_featdescs[-node].len, mod_featdescs[-node].s)
_( " }")
- }
}
else if (node > 0) {
for (int i = 0; i < 16; ++i) {
@@ -660,7 +686,7 @@ static int evargs_notype(FILE *out, s16 i, const char *suffix) {
return j;
}
-static inline void gencode(FILE *out, s16 featdescs) {
+static inline void gencode(FILE *out, s16 modnames, s16 featdescs) {
for (int i = 1; i < nmods; ++i) {
if (mod_flags[i] & HAS_INIT) {
F( "extern int _feat_init_%.*s();", mod_names[i].len, mod_names[i].s)
@@ -723,16 +749,23 @@ F( " feats.preinit_%.*s = _feat_preinit_%.*s();",
_( "}")
_( "")
_( "static inline void initfeatures() {")
+ // note: hidden flag could be 0 on OE but it's useful to know which things
+ // *would* be hidden. in particular, GetHelpText currently checks for both
+ // CON_INIT_HIDDEN and _CON_NE_HIDDEN when deciding whether to prepend
+ // the unsupported marker to the help text. the value of CON_INIT_HIDDEN
+ // is otherwise unused in OE so won't do any harm being set all the time.
+_( " int _hiddenflag = GAMETYPE_MATCHES(OE) ?")
+_( " CON_INIT_HIDDEN : _CON_NE_HIDDEN;")
for (int i = 0; i < nfeatures; ++i) { // N.B.: this *should* be 0-indexed!
const char *else_ = "";
s16 mod = feat_initorder[i];
+F( " s8 status_%.*s;", mod_names[mod].len, mod_names[mod].s)
if (mod_flags[mod] & HAS_PREINIT) {
-F( " s8 status_%.*s = feats.preinit_%.*s;",
+F( " if (feats.preinit_%.*s != FEAT_OK) status_%.*s = feats.preinit_%.*s;",
+ mod_names[mod].len, mod_names[mod].s,
mod_names[mod].len, mod_names[mod].s,
mod_names[mod].len, mod_names[mod].s)
- }
- else {
-F( " s8 status_%.*s;", mod_names[mod].len, mod_names[mod].s)
+ else_ = "else ";
}
if (mod_gamespecific[mod].s) {
F( " %sif (!GAMETYPE_MATCHES(%.*s)) status_%.*s = FEAT_SKIP;", else_,
@@ -741,48 +774,41 @@ F( " %sif (!GAMETYPE_MATCHES(%.*s)) status_%.*s = FEAT_SKIP;", else_,
else_ = "else ";
}
list_foreach (struct cmeta_slice, gamedata, mod_gamedata + mod) {
- // this is not a *totally* ideal way of doing this, but it's easy.
- // if we had some info about what gamedata was doing, we could avoid
- // having to ifdef these cases and could just directly generate the
- // right thing. but that'd be quite a bit of work, so... we don't!
if (mod_gamespecific[mod].s) {
-F( "#ifdef _GAMES_WITH_%.*s", gamedata.len, gamedata.s)
-F( " %sif (!(_gametype_tag_%.*s & _GAMES_WITH_%.*s) && !has_%.*s) {", else_,
- mod_gamespecific[mod].len, mod_gamespecific[mod].s,
- gamedata.len, gamedata.s, gamedata.len, gamedata.s)
+F( " %sif (!_HAS_%.*s(_gametype_tag_%.*s)) {", else_,
+ gamedata.len, gamedata.s,
+ mod_gamespecific[mod].len, mod_gamespecific[mod].s)
F( " status_%.*s = NOGD;", mod_names[mod].len, mod_names[mod].s)
_( " }")
-_( "#else")
}
-F( " %sif (!has_%.*s) status_%.*s = NOGD;", else_,
- gamedata.len, gamedata.s, mod_names[mod].len, mod_names[mod].s)
- if (mod_gamespecific[mod].s) {
-_( "#endif")
+ else {
+F( " %sif (!_HAS_%.*s(0)) status_%.*s = NOGD;", else_,
+ gamedata.len, gamedata.s, mod_names[mod].len, mod_names[mod].s)
}
else_ = "else ";
}
list_foreach (struct cmeta_slice, global, mod_globals + mod) {
F( " %sif (!(%.*s)) status_%.*s = NOGLOBAL;", else_,
- global.len, global.s, mod_names[mod].len, mod_names[mod].s)
+ global.len, global.s, mod_names[mod].len, mod_names[mod].s)
else_ = "else ";
}
list_foreach (s16, dep, mod_needs + mod) {
F( " %sif (status_%.*s != FEAT_OK) status_%.*s = REQFAIL;", else_,
- mod_names[dep].len, mod_names[dep].s,
- mod_names[mod].len, mod_names[mod].s)
+ mod_names[dep].len, mod_names[dep].s,
+ mod_names[mod].len, mod_names[mod].s)
else_ = "else ";
}
if (mod_flags[mod] & (HAS_END | HAS_EVENTS | HAS_OPTDEPS)) {
F( " %sif ((status_%.*s = _feat_init_%.*s()) == FEAT_OK) has_%.*s = true;",
- else_,
- mod_names[mod].len, mod_names[mod].s,
- mod_names[mod].len, mod_names[mod].s,
- mod_names[mod].len, mod_names[mod].s)
+ else_,
+ mod_names[mod].len, mod_names[mod].s,
+ mod_names[mod].len, mod_names[mod].s,
+ mod_names[mod].len, mod_names[mod].s)
}
else {
F( " %sstatus_%.*s = _feat_init_%.*s();", else_,
- mod_names[mod].len, mod_names[mod].s,
- mod_names[mod].len, mod_names[mod].s)
+ mod_names[mod].len, mod_names[mod].s,
+ mod_names[mod].len, mod_names[mod].s)
}
}
_( "")
@@ -790,10 +816,13 @@ _( "")
if (!(cvar_flags[i] & CMETA_CVAR_UNREG)) {
if (cvar_flags[i] & CMETA_CVAR_FEAT) {
struct cmeta_slice modname = mod_names[cvar_feats[i]];
-F( " if (status_%.*s != FEAT_SKIP) con_regvar(%.*s);",
- modname.len, modname.s, cvar_names[i].len, cvar_names[i].s)
-F( " else if (status_%.*s != FEAT_OK) %.*s->base.flags |= CON_HIDDEN;",
+F( " if (status_%.*s != FEAT_SKIP) {",
+ modname.len, modname.s)
+F( " con_regvar(%.*s);",
+ cvar_names[i].len, cvar_names[i].s)
+F( " if (status_%.*s != FEAT_OK) %.*s->base.flags |= _hiddenflag;",
modname.len, modname.s, cvar_names[i].len, cvar_names[i].s)
+_( " }")
}
else {
F( " con_regvar(%.*s);", cvar_names[i].len, cvar_names[i].s)
@@ -818,7 +847,13 @@ _( " struct rgba white = {255, 255, 255, 255};")
_( " struct rgba green = {128, 255, 128, 255};")
_( " struct rgba red = {255, 128, 128, 255};")
_( " con_colourmsg(&white, \"---- List of plugin features ---\\n\");");
+_( "#ifdef SST_DBG")
+_( " struct rgba grey = {192, 192, 192, 255};")
+_( " struct rgba *colour;")
+ recursedbgmodnames(out, modnames);
+_( "#else")
recursefeatdescs(out, featdescs);
+_( "#endif")
_( "}")
_( "")
_( "static inline void endfeatures() {")
@@ -834,9 +869,19 @@ _( "}")
_( "")
_( "static inline void freevars() {")
for (int i = 1; i < ncvars; ++i) {
-F( " extfree(%.*s->strval);", cvar_names[i].len, cvar_names[i].s)
+F( " extfree(con_getvarcommon(%.*s)->strval);",
+ cvar_names[i].len, cvar_names[i].s)
}
_( "}")
+_( "")
+_( "static inline void shuntvars() {")
+_( "#ifdef _WIN32")
+ for (int i = 1; i < ncvars; ++i) {
+F( " memmove(&%.*s->v1, &%.*s->v2, sizeof(struct con_var_common));",
+ cvar_names[i].len, cvar_names[i].s, cvar_names[i].len, cvar_names[i].s)
+ }
+_( "#endif")
+_( "}")
for (int i = 1; i < nevents; ++i) {
const char *prefix = event_predicateflags[i] ?
"bool CHECK_" : "void EMIT_";
@@ -953,7 +998,7 @@ int OS_MAIN(int argc, os_char *argv[]) {
FILE *out = fopen(".build/include/glue.gen.h", "wb");
if_cold (!out) die(100, "couldn't open .build/include/glue.gen.h");
H()
- gencode(out, featdesclookup);
+ gencode(out, modlookup, featdesclookup);
if_cold (fflush(out)) die(100, "couldn't finish writing output");
return 0;
}
diff --git a/src/build/mkentprops.c b/src/build/mkentprops.c
index bd4b082..7c195d0 100644
--- a/src/build/mkentprops.c
+++ b/src/build/mkentprops.c
@@ -350,6 +350,7 @@ static inline void dodecls(FILE *out) {
const char *s = sbase + decls[i];
F( "extern int %s;", s);
F( "#define has_%s (!!%s)", s, s); // offsets will NEVER be 0, due to vtable!
+F( "#define _HAS_%s(x) has_%s", s, s); // HACK: stupid dupe for gluegen
}
}
@@ -368,6 +369,21 @@ _( " }")
_( "}")
}
+static inline void dodbgdump(FILE *out) {
+_( "static inline void dumpentprops() {")
+_( " con_msg(\"-- entprops.txt --\\n\");")
+ for (int i = 0; i < ndecls; ++i) {
+ const char *s = sbase + decls[i];
+F( " if (has_%s) {", s);
+F( " con_msg(\" [x] %s = %%d\\n\", %s);", s, s)
+_( " }")
+_( " else {")
+F( " con_msg(\" [ ] %s\\n\");", s)
+_( " }")
+ }
+_( "}")
+}
+
int OS_MAIN(int argc, os_char *argv[]) {
if_cold (argc != 2) die(1, "wrong number of arguments");
int f = os_open_read(argv[1]);
@@ -389,6 +405,13 @@ int OS_MAIN(int argc, os_char *argv[]) {
if_cold (!out) die(100, "couldn't open entpropsinit.gen.h");
H();
doinit(out);
+
+ // technically we don't need this header in release builds, but whatever.
+ out = fopen(".build/include/entpropsdbg.gen.h", "wb");
+ if_cold (!out) die(100, "couldn't open entpropsdbg.gen.h");
+ H();
+ dodbgdump(out);
+
return 0;
}
diff --git a/src/build/mkgamedata.c b/src/build/mkgamedata.c
index 325cda2..e0d08f3 100644
--- a/src/build/mkgamedata.c
+++ b/src/build/mkgamedata.c
@@ -163,28 +163,29 @@ _( "")
static inline void knowngames(FILE *out) {
// kind of tricky optimisation: if a gamedata entry has no default but
// does have game-specific values which match a feature's GAMESPECIFIC()
- // macro, load-time conditional checks resulting from REQUIRE_GAMEDATA() can
- // be elided at compile-time.
+ // macro, we can elide has_* and REQUIRE_GAMEDATA() checks at compile time.
for (int i = 0, j; i < nents - 1; i = j) {
while (exprs[i]) { // if there's a default value, we don't need this
// skip to next unindented thing, return if there isn't one with at
// least one indented thing under it.
- for (++i; indents[i] != 0; ++i) if (i == nents - 1) return;
+ do {
+ if (++i == nents - 1) return;
+ } while (indents[i] != 0);
}
F( "#line %d \"%" fS "\"", srclines[i], srcnames[srcfiles[i]])
- if_cold (fprintf(out, "#define _GAMES_WITH_%s (", sbase + tags[i]) < 0) {
+ if_cold (fprintf(out, "#define _GAMES_WITH_%s (0", sbase + tags[i]) < 0) {
diewrite();
}
- const char *pipe = "";
for (j = i + 1; j < nents && indents[j] != 0; ++j) {
// don't attempt to optimise for nested conditionals because that's
// way more complicated and also basically defeats the purpose.
- if (indents[j] != 1) continue;
- if_cold (fprintf(out, "%s \\\n\t _gametype_tag_%s", pipe,
- sbase + tags[j]) < 0) {
+ if (indents[j] != 1 || !exprs[j]) continue;
+ bool neg = sbase[tags[j]] == '!';
+ const char *tilde = (const char *)"~" + !neg; // cast away warning
+ if_cold (fprintf(out, " | \\\n\t%s_gametype_tag_%s", tilde,
+ sbase + tags[j] + neg) < 0) {
diewrite();
}
- pipe = " |";
}
fputs(" \\\n)\n", out);
}
@@ -195,17 +196,22 @@ static inline void decls(FILE *out) {
if (indents[i] != 0) continue;
F( "#line %d \"%" fS "\"", srclines[i], srcnames[srcfiles[i]])
if (exprs[i]) { // default value is specified - entry always exists
- // *technically* this case is redundant - the other has_ macro would
- // still work. however, having a distinct case makes the generated
- // header a little easier to read at a glance.
-F( "#define has_%s 1", sbase + tags[i])
+F( "#define _HAS_%s(feattags) 1", sbase + tags[i])
}
else { // entry is missing unless a tag is matched
// implementation detail: INT_MIN is reserved for missing gamedata!
// XXX: for max robustness, should probably check for this in input?
-F( "#define has_%s (%s != -2147483648)", sbase + tags[i], sbase + tags[i])
+F( "#define _HAS_%s(feattags) ( \\", sbase + tags[i])
+_( " !!feattags && \\")
+F( " (feattags & _GAMES_WITH_%s) == feattags || \\",
+ sbase + tags[i])
+F( " %s != -2147483648 \\", sbase + tags[i])
+_(")")
}
F( "#line %d \"%" fS "\"", srclines[i], srcnames[srcfiles[i]])
+F( "#define has_%s _HAS_%s(_gamedata_feattags)",
+ sbase + tags[i], sbase + tags[i])
+F( "#line %d \"%" fS "\"", srclines[i], srcnames[srcfiles[i]])
if_cold (i == nents - 1 || !indents[i + 1]) { // no tags - it's constant
F( "enum { %s = (%s) };", sbase + tags[i], sbase + exprs[i])
}
@@ -245,14 +251,16 @@ _i("}")
continue;
}
F( "#line %d \"%" fS "\"", srclines[i], srcnames[srcfiles[i]])
+ bool neg = sbase[tags[i]] == '!';
+ const char *excl = (const char *)"!" + !neg; // cast away warning
if (indents[i] > indents[i - 1]) {
-Fi(" if (GAMETYPE_MATCHES(%s)) {", sbase + tags[i])
+Fi(" if (%sGAMETYPE_MATCHES(%s)) {", excl, sbase + tags[i] + neg);
++indent;
}
else {
_i("}")
F( "#line %d \"%" fS "\"", srclines[i], srcnames[srcfiles[i]])
-Fi("else if (GAMETYPE_MATCHES(%s)) {", sbase + tags[i])
+Fi("if (%sGAMETYPE_MATCHES(%s)) {", excl, sbase + tags[i] + neg);
}
if (exprs[i]) {
F( "#line %d \"%" fS "\"", srclines[i], srcnames[srcfiles[i]])
@@ -265,6 +273,32 @@ _i("}")
_( "}")
}
+static inline void dbgdump(FILE *out) {
+_( "static void dumpgamedata() {")
+ int cursrc = -1;
+ for (int i = 0; i < nents; ++i) {
+ if (indents[i] != 0) continue;
+ if_cold (srcfiles[i] != cursrc) {
+ cursrc = srcfiles[i];
+F( " con_msg(\"-- %" fS " --\\n\");", srcnames[cursrc])
+ }
+ const char *s = sbase + tags[i];
+ int line = srclines[i];
+ if (exprs[i]) {
+F( " con_msg(\" [x] %s = %%d (line %d)\\n\", %s);", s, line, s)
+ }
+ else {
+F( " if (has_%s) {", sbase + tags[i])
+F( " con_msg(\" [x] %s = %%d (line %d)\\n\", %s);", s, line, s)
+_( " }")
+_( " else {")
+F( " con_msg(\" [ ] %s (line %d)\\n\");", s, line);
+_( " }")
+ }
+ }
+_( "}")
+}
+
int OS_MAIN(int argc, os_char *argv[]) {
srcnames = (const os_char *const *)argv;
int sbase_len = 0, sbase_max = 65536;
@@ -304,6 +338,13 @@ int OS_MAIN(int argc, os_char *argv[]) {
defs(out);
_("")
init(out);
+
+ // technically we don't need this header in release builds, but whatever.
+ out = fopen(".build/include/gamedatadbg.gen.h", "wb");
+ if_cold (!out) die(100, "couldn't open gamedatadbg.gen.h");
+ H();
+ dbgdump(out);
+
return 0;
}