Don't misinterpret blank configuration entries as sentinels
Configuration table entries not defined by builtin and custom configuration files remain blank. They get misinterpreted as sentinel in tables that use one. Affected are tables product, ship-chr, plane-chr, land-chr and nuke-chr. Tables item, sect-chr and infrastructure are immune despite using a sentinel, because omitting entries is not permitted there. Code relying on the sentinel fails to pick up entries after the first blank one. They don't get set up correctly, they're invisible to build and show, and not recognized as symbolic selector values (the frg in ship ?type=frg). xdump is fine, because it doesn't rely on sentinels. It dumps blank entries normally. The bugs don't bite in the stock game, because the builtin configuration files are all dense. The sentinels are all null strings. Set them to "" in the affected tables' oninit callback. Fix up code iterating over the tables to ignore such entries. This is precisely the code relying on sentinels, plus xdump's xdvisible().
This commit is contained in:
parent
1e9c9c8273
commit
84d88442b3
7 changed files with 72 additions and 7 deletions
|
@ -37,6 +37,7 @@
|
||||||
#include "empobj.h"
|
#include "empobj.h"
|
||||||
#include "news.h"
|
#include "news.h"
|
||||||
#include "optlist.h"
|
#include "optlist.h"
|
||||||
|
#include "product.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "xdump.h"
|
#include "xdump.h"
|
||||||
|
|
||||||
|
@ -52,6 +53,7 @@ xdvisible(int type, void *p)
|
||||||
struct lonstr *lp = p;
|
struct lonstr *lp = p;
|
||||||
struct natstr *natp;
|
struct natstr *natp;
|
||||||
int tlev;
|
int tlev;
|
||||||
|
char *name;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case EF_SECTOR:
|
case EF_SECTOR:
|
||||||
|
@ -84,19 +86,27 @@ xdvisible(int type, void *p)
|
||||||
case EF_TRADE:
|
case EF_TRADE:
|
||||||
case EF_COMM:
|
case EF_COMM:
|
||||||
return gp->own != 0;
|
return gp->own != 0;
|
||||||
|
case EF_PRODUCT:
|
||||||
|
return ((struct pchrstr *)p)->p_sname[0] != 0;
|
||||||
case EF_SHIP_CHR:
|
case EF_SHIP_CHR:
|
||||||
tlev = ((struct mchrstr *)p)->m_tech;
|
tlev = ((struct mchrstr *)p)->m_tech;
|
||||||
|
name = ((struct mchrstr *)p)->m_name;
|
||||||
goto tech;
|
goto tech;
|
||||||
case EF_PLANE_CHR:
|
case EF_PLANE_CHR:
|
||||||
tlev = ((struct plchrstr *)p)->pl_tech;
|
tlev = ((struct plchrstr *)p)->pl_tech;
|
||||||
|
name = ((struct plchrstr *)p)->pl_name;
|
||||||
goto tech;
|
goto tech;
|
||||||
case EF_LAND_CHR:
|
case EF_LAND_CHR:
|
||||||
tlev = ((struct lchrstr *)p)->l_tech;
|
tlev = ((struct lchrstr *)p)->l_tech;
|
||||||
|
name = ((struct lchrstr *)p)->l_name;
|
||||||
tech:
|
tech:
|
||||||
natp = getnatp(player->cnum);
|
natp = getnatp(player->cnum);
|
||||||
|
if (!name[0])
|
||||||
|
return 0;
|
||||||
return player->god || tlev <= (int)(1.25 * natp->nat_level[NAT_TLEV]);
|
return player->god || tlev <= (int)(1.25 * natp->nat_level[NAT_TLEV]);
|
||||||
case EF_NUKE_CHR:
|
case EF_NUKE_CHR:
|
||||||
tlev = ((struct nchrstr *)p)->n_tech;
|
tlev = ((struct nchrstr *)p)->n_tech;
|
||||||
|
name = ((struct nchrstr *)p)->n_name;
|
||||||
if (drnuke_const > MIN_DRNUKE_CONST) {
|
if (drnuke_const > MIN_DRNUKE_CONST) {
|
||||||
natp = getnatp(player->cnum);
|
natp = getnatp(player->cnum);
|
||||||
if (tlev > (int)((int)(1.25 * natp->nat_level[NAT_RLEV])
|
if (tlev > (int)((int)(1.25 * natp->nat_level[NAT_RLEV])
|
||||||
|
|
|
@ -226,6 +226,8 @@ ef_verify(void)
|
||||||
|
|
||||||
/* Special checks */
|
/* Special checks */
|
||||||
for (i = 0; pchr[i].p_sname; i++) {
|
for (i = 0; pchr[i].p_sname; i++) {
|
||||||
|
if (!pchr[i].p_sname[0])
|
||||||
|
continue;
|
||||||
if ((pchr[i].p_type >= 0) == (pchr[i].p_level >= 0)) {
|
if ((pchr[i].p_type >= 0) == (pchr[i].p_level >= 0)) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"Config %s uid %d field level doesn't match field type\n",
|
"Config %s uid %d field level doesn't match field type\n",
|
||||||
|
|
|
@ -62,6 +62,11 @@ static void nuk_oninit(void *);
|
||||||
static void nat_oninit(void *);
|
static void nat_oninit(void *);
|
||||||
static void realm_oninit(void *);
|
static void realm_oninit(void *);
|
||||||
static void game_oninit(void *);
|
static void game_oninit(void *);
|
||||||
|
static void pchr_oninit(void *);
|
||||||
|
static void mchr_oninit(void *);
|
||||||
|
static void plchr_oninit(void *);
|
||||||
|
static void lchr_oninit(void *);
|
||||||
|
static void nchr_oninit(void *);
|
||||||
|
|
||||||
/* Number of elements in ARRAY. */
|
/* Number of elements in ARRAY. */
|
||||||
#define SZ(array) (sizeof(array) / sizeof((array)[0]))
|
#define SZ(array) (sizeof(array) / sizeof((array)[0]))
|
||||||
|
@ -192,17 +197,17 @@ struct empfile empfile[] = {
|
||||||
{EF_ITEM, "item", "item.config", ichr_ca, EF_BAD,
|
{EF_ITEM, "item", "item.config", ichr_ca, EF_BAD,
|
||||||
ARRAY_CACHE(ichr, EFF_CFG), NULL, NULL, NULL, NULL},
|
ARRAY_CACHE(ichr, EFF_CFG), NULL, NULL, NULL, NULL},
|
||||||
{EF_PRODUCT, "product", "product.config", pchr_ca, EF_BAD,
|
{EF_PRODUCT, "product", "product.config", pchr_ca, EF_BAD,
|
||||||
ARRAY_CACHE(pchr, EFF_CFG), NULL, NULL, NULL, NULL},
|
ARRAY_CACHE(pchr, EFF_CFG), pchr_oninit, NULL, NULL, NULL},
|
||||||
{EF_SECTOR_CHR, "sect-chr", "sect.config", dchr_ca, EF_BAD,
|
{EF_SECTOR_CHR, "sect-chr", "sect.config", dchr_ca, EF_BAD,
|
||||||
ARRAY_CACHE(dchr, EFF_CFG), NULL, NULL, NULL, NULL},
|
ARRAY_CACHE(dchr, EFF_CFG), NULL, NULL, NULL, NULL},
|
||||||
{EF_SHIP_CHR, "ship-chr", "ship.config", mchr_ca, EF_BAD,
|
{EF_SHIP_CHR, "ship-chr", "ship.config", mchr_ca, EF_BAD,
|
||||||
ARRAY_CACHE(mchr, EFF_CFG), NULL, NULL, NULL, NULL},
|
ARRAY_CACHE(mchr, EFF_CFG), mchr_oninit, NULL, NULL, NULL},
|
||||||
{EF_PLANE_CHR, "plane-chr", "plane.config", plchr_ca, EF_BAD,
|
{EF_PLANE_CHR, "plane-chr", "plane.config", plchr_ca, EF_BAD,
|
||||||
ARRAY_CACHE(plchr, EFF_CFG), NULL, NULL, NULL, NULL},
|
ARRAY_CACHE(plchr, EFF_CFG), plchr_oninit, NULL, NULL, NULL},
|
||||||
{EF_LAND_CHR, "land-chr", "land.config", lchr_ca, EF_BAD,
|
{EF_LAND_CHR, "land-chr", "land.config", lchr_ca, EF_BAD,
|
||||||
ARRAY_CACHE(lchr, EFF_CFG), NULL, NULL, NULL, NULL},
|
ARRAY_CACHE(lchr, EFF_CFG), lchr_oninit, NULL, NULL, NULL},
|
||||||
{EF_NUKE_CHR, "nuke-chr", "nuke.config", nchr_ca, EF_BAD,
|
{EF_NUKE_CHR, "nuke-chr", "nuke.config", nchr_ca, EF_BAD,
|
||||||
ARRAY_CACHE(nchr, EFF_CFG), NULL, NULL, NULL, NULL},
|
ARRAY_CACHE(nchr, EFF_CFG), nchr_oninit, NULL, NULL, NULL},
|
||||||
{EF_NEWS_CHR, "news-chr", NULL, rpt_ca, EF_BAD,
|
{EF_NEWS_CHR, "news-chr", NULL, rpt_ca, EF_BAD,
|
||||||
ARRAY_TABLE(rpt, N_MAX_VERB + 1, EFF_CFG), NULL, NULL, NULL, NULL},
|
ARRAY_TABLE(rpt, N_MAX_VERB + 1, EFF_CFG), NULL, NULL, NULL, NULL},
|
||||||
{EF_INFRASTRUCTURE, "infrastructure", "infra.config", intrchr_ca, EF_BAD,
|
{EF_INFRASTRUCTURE, "infrastructure", "infra.config", intrchr_ca, EF_BAD,
|
||||||
|
@ -329,6 +334,36 @@ game_oninit(void *ptr)
|
||||||
((struct gamestr *)ptr)->game_turn = 1;
|
((struct gamestr *)ptr)->game_turn = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pchr_oninit(void *ptr)
|
||||||
|
{
|
||||||
|
((struct pchrstr *)ptr)->p_sname = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mchr_oninit(void *ptr)
|
||||||
|
{
|
||||||
|
((struct mchrstr *)ptr)->m_name = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
plchr_oninit(void *ptr)
|
||||||
|
{
|
||||||
|
((struct plchrstr *)ptr)->pl_name = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lchr_oninit(void *ptr)
|
||||||
|
{
|
||||||
|
((struct lchrstr *)ptr)->l_name = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
nchr_oninit(void *ptr)
|
||||||
|
{
|
||||||
|
((struct nchrstr *)ptr)->n_name = "";
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ef_fix_size(struct empfile *ep, int n)
|
ef_fix_size(struct empfile *ep, int n)
|
||||||
{
|
{
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
* several.
|
* several.
|
||||||
* Each array element has a pointer to its name stored at offset OFFS.
|
* Each array element has a pointer to its name stored at offset OFFS.
|
||||||
* Search stops when this name is a null pointer.
|
* Search stops when this name is a null pointer.
|
||||||
|
* It ignores elements with an empty name.
|
||||||
* NEEDLE is compared to element names with mineq(NEEDLE, NAME).
|
* NEEDLE is compared to element names with mineq(NEEDLE, NAME).
|
||||||
* SIZE gives the size of an array element.
|
* SIZE gives the size of an array element.
|
||||||
*/
|
*/
|
||||||
|
@ -54,6 +55,8 @@ stmtch(char *needle, void *haystack, ptrdiff_t offs, size_t size)
|
||||||
name = *(char **)((char *)haystack + i * size + offs);
|
name = *(char **)((char *)haystack + i * size + offs);
|
||||||
if (!name)
|
if (!name)
|
||||||
break;
|
break;
|
||||||
|
if (!*name)
|
||||||
|
continue;
|
||||||
switch (mineq(needle, name)) {
|
switch (mineq(needle, name)) {
|
||||||
case ME_MISMATCH:
|
case ME_MISMATCH:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -43,7 +43,6 @@
|
||||||
* - Normalize terminology: table/rows/columns or file/records/fields
|
* - Normalize terminology: table/rows/columns or file/records/fields
|
||||||
* - Loading tables with NSC_STRING elements more than once leaks memory
|
* - Loading tables with NSC_STRING elements more than once leaks memory
|
||||||
* TODO:
|
* TODO:
|
||||||
* - Check EFF_CFG tables are dense
|
|
||||||
* - Symbolic array indexes
|
* - Symbolic array indexes
|
||||||
* - Option to treat missing and unknown fields as warning, not error
|
* - Option to treat missing and unknown fields as warning, not error
|
||||||
* TODO, but hardly worth the effort:
|
* TODO, but hardly worth the effort:
|
||||||
|
|
|
@ -60,6 +60,8 @@ init_mchr(void)
|
||||||
struct mchrstr *mp;
|
struct mchrstr *mp;
|
||||||
|
|
||||||
for (mp = mchr; mp->m_name; mp++) {
|
for (mp = mchr; mp->m_name; mp++) {
|
||||||
|
if (!mp->m_name[0])
|
||||||
|
continue;
|
||||||
if (mp->m_nplanes && !(mp->m_flags & M_MSL || mp->m_flags & M_FLY))
|
if (mp->m_nplanes && !(mp->m_flags & M_MSL || mp->m_flags & M_FLY))
|
||||||
mp->m_flags |= M_MSL;
|
mp->m_flags |= M_MSL;
|
||||||
}
|
}
|
||||||
|
@ -71,6 +73,8 @@ init_plchr(void)
|
||||||
struct plchrstr *pp;
|
struct plchrstr *pp;
|
||||||
|
|
||||||
for (pp = plchr; pp->pl_name; pp++) {
|
for (pp = plchr; pp->pl_name; pp++) {
|
||||||
|
if (!pp->pl_name[0])
|
||||||
|
continue;
|
||||||
if (pp->pl_flags & P_M)
|
if (pp->pl_flags & P_M)
|
||||||
pp->pl_flags |= P_V;
|
pp->pl_flags |= P_V;
|
||||||
}
|
}
|
||||||
|
@ -81,7 +85,9 @@ init_pchr(void)
|
||||||
{
|
{
|
||||||
struct pchrstr *p;
|
struct pchrstr *p;
|
||||||
|
|
||||||
for (p = pchr; p->p_name; p++) {
|
for (p = pchr; p->p_sname; p++) {
|
||||||
|
if (!p->p_sname[0])
|
||||||
|
continue;
|
||||||
if (opt_GO_RENEW) {
|
if (opt_GO_RENEW) {
|
||||||
if (p->p_type == I_DUST || p->p_type == I_OIL)
|
if (p->p_type == I_DUST || p->p_type == I_OIL)
|
||||||
p->p_nrdep = 0;
|
p->p_nrdep = 0;
|
||||||
|
|
|
@ -79,6 +79,8 @@ make_mchr_index(struct chr_index chridx[], int tlev)
|
||||||
|
|
||||||
n = 0;
|
n = 0;
|
||||||
for (i = 0; mchr[i].m_name; i++) {
|
for (i = 0; mchr[i].m_name; i++) {
|
||||||
|
if (!mchr[i].m_name[0])
|
||||||
|
continue;
|
||||||
if (mchr[i].m_tech > tlev)
|
if (mchr[i].m_tech > tlev)
|
||||||
continue;
|
continue;
|
||||||
if ((mchr[i].m_flags & M_TRADE) && !opt_TRADESHIPS)
|
if ((mchr[i].m_flags & M_TRADE) && !opt_TRADESHIPS)
|
||||||
|
@ -100,6 +102,8 @@ make_plchr_index(struct chr_index chridx[], int tlev)
|
||||||
|
|
||||||
n = 0;
|
n = 0;
|
||||||
for (i = 0; plchr[i].pl_name; i++) {
|
for (i = 0; plchr[i].pl_name; i++) {
|
||||||
|
if (!plchr[i].pl_name[0])
|
||||||
|
continue;
|
||||||
if (plchr[i].pl_tech > tlev)
|
if (plchr[i].pl_tech > tlev)
|
||||||
continue;
|
continue;
|
||||||
chridx[n].type = i;
|
chridx[n].type = i;
|
||||||
|
@ -119,6 +123,8 @@ make_lchr_index(struct chr_index chridx[], int tlev)
|
||||||
|
|
||||||
n = 0;
|
n = 0;
|
||||||
for (i = 0; lchr[i].l_name; i++) {
|
for (i = 0; lchr[i].l_name; i++) {
|
||||||
|
if (!lchr[i].l_name[0])
|
||||||
|
continue;
|
||||||
if (lchr[i].l_tech > tlev)
|
if (lchr[i].l_tech > tlev)
|
||||||
continue;
|
continue;
|
||||||
if ((lchr[i].l_flags & L_SPY) && !opt_LANDSPIES)
|
if ((lchr[i].l_flags & L_SPY) && !opt_LANDSPIES)
|
||||||
|
@ -140,6 +146,8 @@ make_nchr_index(struct chr_index chridx[], int tlev)
|
||||||
|
|
||||||
n = 0;
|
n = 0;
|
||||||
for (i = 0; nchr[i].n_name; i++) {
|
for (i = 0; nchr[i].n_name; i++) {
|
||||||
|
if (!nchr[i].n_name[0])
|
||||||
|
continue;
|
||||||
if (nchr[i].n_tech > tlev)
|
if (nchr[i].n_tech > tlev)
|
||||||
continue;
|
continue;
|
||||||
chridx[n].type = i;
|
chridx[n].type = i;
|
||||||
|
@ -506,6 +514,8 @@ show_product(int tlev)
|
||||||
pr("product cost raw materials reso dep level p.e.\n");
|
pr("product cost raw materials reso dep level p.e.\n");
|
||||||
|
|
||||||
for (pp = pchr; pp->p_sname; pp++) {
|
for (pp = pchr; pp->p_sname; pp++) {
|
||||||
|
if (!pp->p_sname[0])
|
||||||
|
continue;
|
||||||
pr("%7.7s %c $%-3d ",
|
pr("%7.7s %c $%-3d ",
|
||||||
pp->p_sname,
|
pp->p_sname,
|
||||||
pp->p_type < 0 ? ' ' : ichr[pp->p_type].i_mnem,
|
pp->p_type < 0 ? ' ' : ichr[pp->p_type].i_mnem,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue