diff options
Diffstat (limited to 'src/build')
| -rw-r--r-- | src/build/gluegen.c | 121 | ||||
| -rw-r--r-- | src/build/mkentprops.c | 23 | ||||
| -rw-r--r-- | src/build/mkgamedata.c | 73 |
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; } |
