cmdhelp revamp
Implement a rudimentary if/elif/else/endif interpretor and use
conditionals in dat/cmdhelp to describe what command each keystroke
currently invokes, so that there isn't a lot of "(debug mode only)"
and "(if number_pad is off)" cluttering the feedback that the user
sees. (The conditionals add quite a bit of clutter to the raw data
but users don't see that. number_pad produces a lot of conditional
commands: basic letters vs digits, 'g' vs 'G' for '5', phone
keypad vs normal layout of digits, and QWERTZ keyboard swap between
y/Y/^Y/M-y/M-Y/M-^Y and z/Z/^Z/M-z/M-Z/M-^Z.)
The interpretor understands
'&#' for comment,
'&? option' for 'if' (also '&? !option'
or '&? option=value[,value2,...]'
or '&? !option=value[,value2,...]'),
'&: option' for 'elif' (with argument variations same as 'if';
any number of instances for each 'if'),
'&:' for 'else' (also '&: #comment';
0 or 1 instance for a given 'if'), and
'&.' for 'endif' (also '&. #comment'; required for each 'if').
The option handling is a bit of a mess, with no generality for
which options to deal with and only a comma separated list of
integer values for the '=value' part. number_pad is the only
supported option that has a value; the few others (wizard/debug,
rest_on_space, #if SHELL, #if SUSPEND) are booleans.
This commit is contained in:
186
src/pager.c
186
src/pager.c
@@ -17,6 +17,8 @@ STATIC_DCL struct permonst *FDECL(lookat, (int, int, char *, char *));
|
||||
STATIC_DCL void FDECL(checkfile, (char *, struct permonst *,
|
||||
BOOLEAN_P, BOOLEAN_P));
|
||||
STATIC_DCL void FDECL(look_all, (BOOLEAN_P,BOOLEAN_P));
|
||||
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 void NDECL(docontact);
|
||||
#ifdef PORT_HELP
|
||||
@@ -1307,7 +1309,7 @@ doidtrap()
|
||||
}
|
||||
|
||||
STATIC_DCL void
|
||||
dowhatdoes_help()
|
||||
whatdoes_help()
|
||||
{
|
||||
dlb *fp;
|
||||
char *p, buf[BUFSZ];
|
||||
@@ -1332,14 +1334,131 @@ dowhatdoes_help()
|
||||
destroy_nhwindow(tmpwin);
|
||||
}
|
||||
|
||||
#define WD_STACKLIMIT 5
|
||||
|
||||
STATIC_OVL boolean
|
||||
whatdoes_cond(buf, stack, depth, lnum)
|
||||
char *buf;
|
||||
boolean *stack;
|
||||
int *depth, lnum;
|
||||
{
|
||||
const char badstackfmt[] = "cmdhlp: too many &%c directives at line %d.";
|
||||
boolean newcond, neg;
|
||||
char *p, *q, act = buf[1];
|
||||
int np = 0;
|
||||
|
||||
buf += 2;
|
||||
mungspaces(buf);
|
||||
if (act == '#' || *buf == '#') {
|
||||
*buf = '\0';
|
||||
neg = FALSE; /* lint suppression */
|
||||
p = q = (char *) 0;
|
||||
} else {
|
||||
if ((neg = (*buf == '!')) != 0)
|
||||
if (*++buf == ' ')
|
||||
++buf;
|
||||
p = index(buf, '='), q = index(buf, ':');
|
||||
if (!p || (q && q < p))
|
||||
p = q;
|
||||
if (p) { /* we have a value specified */
|
||||
/* handle a space before or after (or both) '=' (or ':') */
|
||||
if (p > buf && p[-1] == ' ')
|
||||
p[-1] = '\0'; /* end of keyword in buf[] */
|
||||
*p++ = '\0'; /* terminate keyword, advance to start of value */
|
||||
if (*p == ' ')
|
||||
p++;
|
||||
}
|
||||
}
|
||||
newcond = TRUE;
|
||||
if (*buf && (act == '?' || act == ':')) {
|
||||
if (!strcmpi(buf, "number_pad")) {
|
||||
if (!p) {
|
||||
newcond = iflags.num_pad;
|
||||
} else {
|
||||
/* convert internal encoding (separate yes/no and 0..3)
|
||||
back to user-visible one (-1..4) */
|
||||
np = iflags.num_pad ? (1 + iflags.num_pad_mode) /* 1..4 */
|
||||
: (-1 * iflags.num_pad_mode); /* -1..0 */
|
||||
newcond = FALSE;
|
||||
for (; p; p = q) {
|
||||
q = index(p, ',');
|
||||
if (q)
|
||||
*q++ = '\0';
|
||||
if (atoi(p) == np) {
|
||||
newcond = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (!strcmpi(buf, "rest_on_space")) {
|
||||
newcond = flags.rest_on_space;
|
||||
} else if (!strcmpi(buf, "debug") || !strcmpi(buf, "wizard")) {
|
||||
newcond = flags.debug; /* == wizard */
|
||||
} else if (!strcmpi(buf, "shell")) {
|
||||
#ifdef SHELL
|
||||
/* should we also check sysopt.shellers? */
|
||||
newcond = TRUE;
|
||||
#else
|
||||
newcond = FALSE;
|
||||
#endif
|
||||
} else if (!strcmpi(buf, "suspend")) {
|
||||
#ifdef SUSPEND
|
||||
/* sysopt.shellers is also used for dosuspend()... */
|
||||
newcond = TRUE;
|
||||
#else
|
||||
newcond = FALSE;
|
||||
#endif
|
||||
} else {
|
||||
impossible(
|
||||
"cmdhelp: unrecognized &%c conditional at line %d: \"%.20s\"",
|
||||
act, lnum, buf);
|
||||
neg = FALSE;
|
||||
}
|
||||
/* this works for number_pad too: &? !number_pad:-1,0
|
||||
would be true for 1..4 after negation */
|
||||
if (neg)
|
||||
newcond = !newcond;
|
||||
}
|
||||
switch (act) {
|
||||
default:
|
||||
case '#': /* comment */
|
||||
break;
|
||||
case '.': /* endif */
|
||||
if (--*depth < 0) {
|
||||
impossible(badstackfmt, '.', lnum);
|
||||
*depth = 0;
|
||||
}
|
||||
break;
|
||||
case ':': /* else or elif */
|
||||
if (*depth == 0) {
|
||||
impossible(badstackfmt, ':', lnum);
|
||||
*depth = 1; /* so that stack[*depth - 1] is a valid access */
|
||||
}
|
||||
if (stack[*depth] || !stack[*depth - 1])
|
||||
stack[*depth] = FALSE;
|
||||
else if (newcond)
|
||||
stack[*depth] = TRUE;
|
||||
break;
|
||||
case '?': /* if */
|
||||
if (++*depth >= WD_STACKLIMIT) {
|
||||
impossible(badstackfmt, '?', lnum);
|
||||
*depth = WD_STACKLIMIT - 1;
|
||||
}
|
||||
stack[*depth] = newcond && stack[*depth - 1];
|
||||
break;
|
||||
}
|
||||
return stack[*depth];
|
||||
}
|
||||
|
||||
char *
|
||||
dowhatdoes_core(q, cbuf)
|
||||
char q;
|
||||
char *cbuf;
|
||||
{
|
||||
dlb *fp;
|
||||
char bufr[BUFSZ];
|
||||
register char *buf = &bufr[6], ctrl, meta;
|
||||
char buf[BUFSZ];
|
||||
boolean cond, stack[WD_STACKLIMIT];
|
||||
int ctrl, meta, depth = 0, lnum = 0;
|
||||
|
||||
fp = dlb_fopen(CMDHELPFILE, "r");
|
||||
if (!fp) {
|
||||
@@ -1347,25 +1466,44 @@ char *cbuf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctrl = ((q <= '\033') ? (q - 1 + 'A') : 0);
|
||||
meta = ((0x80 & q) ? (0x7f & q) : 0);
|
||||
while (dlb_fgets(buf, BUFSZ - 6, fp)) {
|
||||
if ((ctrl && *buf == '^' && *(buf + 1) == ctrl)
|
||||
|| (meta && *buf == 'M' && *(buf + 1) == '-'
|
||||
&& *(buf + 2) == meta) || *buf == q) {
|
||||
meta = (0x80 & (uchar) q) != 0;
|
||||
if (meta)
|
||||
q &= 0x7f;
|
||||
ctrl = (0x1f & (uchar) q) == (uchar) q;
|
||||
if (ctrl)
|
||||
q |= 0x40; /* NUL -> '@', ^A -> 'A', ... ^Z -> 'Z', ^[ -> '[', ... */
|
||||
else if (q == 0x7f)
|
||||
ctrl = 1, q = '?';
|
||||
|
||||
cond = stack[0] = TRUE, stack[1] = FALSE;
|
||||
while (dlb_fgets(buf, sizeof buf, fp)) {
|
||||
++lnum;
|
||||
if (buf[0] == '&' && buf[1] && index("?:.#", buf[1])) {
|
||||
cond = whatdoes_cond(buf, stack, &depth, lnum);
|
||||
continue;
|
||||
}
|
||||
if (!cond)
|
||||
continue;
|
||||
if (meta ? (buf[0] == 'M' && buf[1] == '-'
|
||||
&& (ctrl ? buf[2] == '^' && highc(buf[3]) == q
|
||||
: buf[2] == q))
|
||||
: (ctrl ? buf[0] == '^' && highc(buf[1]) == q
|
||||
: buf[0] == q)) {
|
||||
(void) strip_newline(buf);
|
||||
if (ctrl && buf[2] == '\t') {
|
||||
buf = bufr + 1;
|
||||
(void) strncpy(buf, "^? ", 8);
|
||||
buf[1] = ctrl;
|
||||
} else if (meta && buf[3] == '\t') {
|
||||
buf = bufr + 2;
|
||||
if (index(buf, '\t'))
|
||||
(void) tabexpand(buf);
|
||||
if (meta && ctrl && buf[4] == ' ') {
|
||||
(void) strncpy(buf, "M-^? ", 8);
|
||||
buf[3] = q;
|
||||
} else if (meta && buf[3] == ' ') {
|
||||
(void) strncpy(buf, "M-? ", 8);
|
||||
buf[2] = meta;
|
||||
} else if (buf[1] == '\t') {
|
||||
buf = bufr;
|
||||
buf[2] = q;
|
||||
} else if (ctrl && buf[2] == ' ') {
|
||||
(void) strncpy(buf, "^? ", 8);
|
||||
buf[1] = q;
|
||||
} else if (buf[1] == ' ') {
|
||||
(void) strncpy(buf, "? ", 8);
|
||||
buf[0] = q;
|
||||
(void) strncpy(buf + 1, " ", 7);
|
||||
}
|
||||
(void) dlb_fclose(fp);
|
||||
Strcpy(cbuf, buf);
|
||||
@@ -1373,6 +1511,8 @@ char *cbuf;
|
||||
}
|
||||
}
|
||||
(void) dlb_fclose(fp);
|
||||
if (depth != 0)
|
||||
impossible("cmdhelp: mismatched &? &: &. conditionals.");
|
||||
return (char *) 0;
|
||||
}
|
||||
|
||||
@@ -1395,9 +1535,9 @@ dowhatdoes()
|
||||
if (q == '\033' && iflags.altmeta) {
|
||||
/* in an ideal world, we would know whether another keystroke
|
||||
was already pending, but this is not an ideal world...
|
||||
if user types ESC, we'll essentially hang until another
|
||||
if user typed ESC, we'll essentially hang until another
|
||||
character is typed */
|
||||
q = yn_function("", (char *) 0, '\0');
|
||||
q = yn_function("]", (char *) 0, '\0');
|
||||
if (q != '\033')
|
||||
q = (char) ((uchar) q | 0200);
|
||||
}
|
||||
@@ -1407,7 +1547,7 @@ dowhatdoes()
|
||||
reslt = dowhatdoes_core(q, bufr);
|
||||
if (reslt) {
|
||||
if (q == '&' || q == '?')
|
||||
dowhatdoes_help();
|
||||
whatdoes_help();
|
||||
pline("%s", reslt);
|
||||
} else {
|
||||
pline("No such command '%s', char code %d (0%03o or 0x%02x).",
|
||||
@@ -1416,7 +1556,7 @@ dowhatdoes()
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
STATIC_OVL void
|
||||
docontact()
|
||||
{
|
||||
winid cwin = create_nhwindow(NHW_TEXT);
|
||||
|
||||
Reference in New Issue
Block a user