more cmdhelp revamp

The if/elif/else/endif interpretor for '&' command data was too
simplistic.  It would allow multiple else clauses, elif clauses
after an else clause, and worst of all, accept a should-be-rejected
conditional block if an else or elif which evaluated true followed
an elif which evaluated false which in turn followed an earlier
true clause.  (dat/cmdhelp trigger any of those bugs.)
This commit is contained in:
PatR
2016-06-08 16:54:01 -07:00
parent ca22b3fe46
commit 60b7e9bc17
+29 -13
View File
@@ -18,7 +18,6 @@ STATIC_DCL void FDECL(checkfile, (char *, struct permonst *,
BOOLEAN_P, BOOLEAN_P)); BOOLEAN_P, BOOLEAN_P));
STATIC_DCL void FDECL(look_all, (BOOLEAN_P,BOOLEAN_P)); STATIC_DCL void FDECL(look_all, (BOOLEAN_P,BOOLEAN_P));
STATIC_DCL void NDECL(whatdoes_help); STATIC_DCL void NDECL(whatdoes_help);
STATIC_DCL boolean FDECL(whatdoes_cond, (char *, boolean *, int *, int));
STATIC_DCL boolean FDECL(help_menu, (int *)); STATIC_DCL boolean FDECL(help_menu, (int *));
STATIC_DCL void NDECL(docontact); STATIC_DCL void NDECL(docontact);
#ifdef PORT_HELP #ifdef PORT_HELP
@@ -1335,25 +1334,36 @@ whatdoes_help()
} }
#define WD_STACKLIMIT 5 #define WD_STACKLIMIT 5
struct wd_stack_frame {
Bitfield(active, 1);
Bitfield(been_true, 1);
Bitfield(else_seen, 1);
};
STATIC_DCL boolean FDECL(whatdoes_cond, (char *, struct wd_stack_frame *,
int *, int));
STATIC_OVL boolean STATIC_OVL boolean
whatdoes_cond(buf, stack, depth, lnum) whatdoes_cond(buf, stack, depth, lnum)
char *buf; char *buf;
boolean *stack; struct wd_stack_frame *stack;
int *depth, lnum; int *depth, lnum;
{ {
const char badstackfmt[] = "cmdhlp: too many &%c directives at line %d."; const char badstackfmt[] = "cmdhlp: too many &%c directives at line %d.";
boolean newcond, neg; boolean newcond, neg, gotopt;
char *p, *q, act = buf[1]; char *p, *q, act = buf[1];
int np = 0; int np = 0;
newcond = (act == '?' || !stack[*depth].been_true);
buf += 2; buf += 2;
mungspaces(buf); mungspaces(buf);
if (act == '#' || *buf == '#') { if (act == '#' || *buf == '#' || !*buf || !newcond) {
gotopt = (*buf && *buf != '#');
*buf = '\0'; *buf = '\0';
neg = FALSE; /* lint suppression */ neg = FALSE; /* lint suppression */
p = q = (char *) 0; p = q = (char *) 0;
} else { } else {
gotopt = TRUE;
if ((neg = (*buf == '!')) != 0) if ((neg = (*buf == '!')) != 0)
if (*++buf == ' ') if (*++buf == ' ')
++buf; ++buf;
@@ -1369,7 +1379,6 @@ int *depth, lnum;
p++; p++;
} }
} }
newcond = TRUE;
if (*buf && (act == '?' || act == ':')) { if (*buf && (act == '?' || act == ':')) {
if (!strcmpi(buf, "number_pad")) { if (!strcmpi(buf, "number_pad")) {
if (!p) { if (!p) {
@@ -1430,24 +1439,29 @@ int *depth, lnum;
} }
break; break;
case ':': /* else or elif */ case ':': /* else or elif */
if (*depth == 0) { if (*depth == 0 || stack[*depth].else_seen) {
impossible(badstackfmt, ':', lnum); impossible(badstackfmt, ':', lnum);
*depth = 1; /* so that stack[*depth - 1] is a valid access */ *depth = 1; /* so that stack[*depth - 1] is a valid access */
} }
if (stack[*depth] || !stack[*depth - 1]) if (stack[*depth].active || stack[*depth].been_true
stack[*depth] = FALSE; || !stack[*depth - 1].active)
stack[*depth].active = 0;
else if (newcond) else if (newcond)
stack[*depth] = TRUE; stack[*depth].active = stack[*depth].been_true = 1;
if (!gotopt)
stack[*depth].else_seen = 1;
break; break;
case '?': /* if */ case '?': /* if */
if (++*depth >= WD_STACKLIMIT) { if (++*depth >= WD_STACKLIMIT) {
impossible(badstackfmt, '?', lnum); impossible(badstackfmt, '?', lnum);
*depth = WD_STACKLIMIT - 1; *depth = WD_STACKLIMIT - 1;
} }
stack[*depth] = newcond && stack[*depth - 1]; stack[*depth].active = (newcond && stack[*depth - 1].active) ? 1 : 0;
stack[*depth].been_true = stack[*depth].active;
stack[*depth].else_seen = 0;
break; break;
} }
return stack[*depth]; return stack[*depth].active ? TRUE : FALSE;
} }
char * char *
@@ -1457,7 +1471,8 @@ char *cbuf;
{ {
dlb *fp; dlb *fp;
char buf[BUFSZ]; char buf[BUFSZ];
boolean cond, stack[WD_STACKLIMIT]; struct wd_stack_frame stack[WD_STACKLIMIT];
boolean cond;
int ctrl, meta, depth = 0, lnum = 0; int ctrl, meta, depth = 0, lnum = 0;
fp = dlb_fopen(CMDHELPFILE, "r"); fp = dlb_fopen(CMDHELPFILE, "r");
@@ -1475,7 +1490,8 @@ char *cbuf;
else if (q == 0x7f) else if (q == 0x7f)
ctrl = 1, q = '?'; ctrl = 1, q = '?';
cond = stack[0] = TRUE, stack[1] = FALSE; (void) memset((genericptr_t) stack, 0, sizeof stack);
cond = stack[0].active = 1;
while (dlb_fgets(buf, sizeof buf, fp)) { while (dlb_fgets(buf, sizeof buf, fp)) {
++lnum; ++lnum;
if (buf[0] == '&' && buf[1] && index("?:.#", buf[1])) { if (buf[0] == '&' && buf[1] && index("?:.#", buf[1])) {