fix default engraving/epitaph/bogusmon corruption

Fixes #369.
Fixes #370.

The default entries inserted by makedefs -s (starting in 3.6.6,
to guard against having an empty data file which led to divide by
zero crash when nethack picked a random entry) lacked a terminating
newline so the first entry from the file (for the usual case when
that data file wasn't empty) got implicitly concatenated to it.
If the first entry got chosen during play, the initial portion
corresponding to the default entry was decrypted properly but the
concatenated portion corresponding to file's first line didn't.
So gibberish was appended to default engraving or epitaph or bogus
monster; also, the input file's first line would never appear.

The newline fix in makedefs is different from pull request #370
but accomplishes the same thing.

The bulk of the patch is an enhancement to #wizrumorcheck to show
first (default inserted by makedefs), second (first in input file)
and last engravings, epitaphs, and bogusmons in addition to rumors.
The command name has become a little misleading but the limited
functionality doesn't call for separate commands.
This commit is contained in:
PatR
2020-07-09 19:23:19 -07:00
parent 63842b64ef
commit 0bd2c3154d
5 changed files with 144 additions and 16 deletions

View File

@@ -1,4 +1,4 @@
/* NetHack 3.7 rumors.c $NHDT-Date: 1583445339 2020/03/05 21:55:39 $ $NHDT-Branch: NetHack-3.6-Mar2020 $:$NHDT-Revision: 1.38 $ */
/* NetHack 3.7 rumors.c $NHDT-Date: 1594347790 2020/07/10 02:23:10 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.55 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2012. */
/* NetHack may be freely redistributed. See license for details. */
@@ -42,6 +42,7 @@
static void FDECL(init_rumors, (dlb *));
static void FDECL(init_oracles, (dlb *));
static void FDECL(others_check, (const char *ftype, const char *, winid *));
static void FDECL(couldnt_open_file, (const char *));
static void
@@ -166,14 +167,13 @@ boolean exclude_cookie;
return rumor_buf;
}
/*
* test that the true/false rumor boundaries are valid.
*/
/* test that the true/false rumor boundaries are valid and show the first
two and very last epitaphs, engravings, and bogus monsters */
void
rumor_check()
{
dlb *rumors = 0;
winid tmpwin;
winid tmpwin = WIN_ERR;
char *endp, line[BUFSZ], xbuf[BUFSZ], rumor_buf[BUFSZ];
if (g.true_rumor_size < 0L) { /* we couldn't open RUMORFILE */
@@ -183,7 +183,6 @@ rumor_check()
}
rumors = dlb_fopen(RUMORFILE, "r");
if (rumors) {
long ftell_rumor_start = 0L;
@@ -257,12 +256,122 @@ rumor_check()
putstr(tmpwin, 0, rumor_buf);
(void) dlb_fclose(rumors);
display_nhwindow(tmpwin, TRUE);
destroy_nhwindow(tmpwin);
} else {
couldnt_open_file(RUMORFILE);
g.true_rumor_size = -1; /* don't try to open it again */
}
/* initial implementation of default epitaph/engraving/bogusmon
contained an error; check those along with rumors */
others_check("Engravings:", ENGRAVEFILE, &tmpwin);
others_check("Epitaphs:", EPITAPHFILE, &tmpwin);
others_check("Bogus monsters:", BOGUSMONFILE, &tmpwin);
if (tmpwin != WIN_ERR) {
display_nhwindow(tmpwin, TRUE);
destroy_nhwindow(tmpwin);
}
}
/* 3.7: augments rumors_check(); test 'engrave' or 'epitaph' or 'bogusmon' */
static void
others_check(ftype, fname, winptr)
const char *ftype, *fname;
winid *winptr;
{
static const char errfmt[] = "others_check(\"%s\"): %s";
dlb *fh;
char line[BUFSZ], xbuf[BUFSZ], *endp;
winid tmpwin = *winptr;
int entrycount = 0;
fh = dlb_fopen(fname, "r");
if (fh) {
if (tmpwin == WIN_ERR) {
*winptr = tmpwin = create_nhwindow(NHW_TEXT);
if (tmpwin == WIN_ERR) {
/* should panic, but won't for wizard mode check operation */
impossible(errfmt, fname, "can't create temporary window");
goto closeit;
}
}
putstr(tmpwin, 0, "");
putstr(tmpwin, 0, ftype);
/* "don't edit" comment */
*line = '\0';
if (!dlb_fgets(line, sizeof line, fh)) {
Sprintf(xbuf, errfmt, fname, "error; can't read comment line");
putstr(tmpwin, 0, xbuf);
goto closeit;
}
if (*line != '#') {
Sprintf(xbuf, errfmt, fname,
"malformed; first line is not a comment line:");
putstr(tmpwin, 0, xbuf);
/* show the bad line; we don't know whether it has been
encrypted via xcrypt() so show it both ways */
if ((endp = index(line, '\n')) != 0)
*endp = 0;
putstr(tmpwin, 0, "- first line, as is");
putstr(tmpwin, 0, line);
putstr(tmpwin, 0, "- xcrypt of first line");
putstr(tmpwin, 0, xcrypt(line, xbuf));
goto closeit;
}
/* first line; should be default one inserted by makedefs when
building the file but we don't have the expected value so
can only require a line to exist */
*line = '\0';
if (!dlb_fgets(line, sizeof line, fh) || *line == '\n') {
Sprintf(xbuf, errfmt, fname,
!*line ? "can't read first non-comment line"
: "first non-comment line is empty");
putstr(tmpwin, 0, xbuf);
goto closeit;
}
++entrycount;
if ((endp = index(line, '\n')) != 0)
*endp = 0;
putstr(tmpwin, 0, xcrypt(line, xbuf));
if (!dlb_fgets(line, sizeof line, fh)) {
putstr(tmpwin, 0, "(no second entry)");
} else {
++entrycount;
if ((endp = index(line, '\n')) != 0)
*endp = 0;
putstr(tmpwin, 0, xcrypt(line, xbuf));
while (dlb_fgets(line, sizeof line, fh)) {
++entrycount;
if ((endp = index(line, '\n')) != 0)
*endp = 0;
(void) xcrypt(line, xbuf);
}
/* count will be 2 if the default entry and the first ordinary
entry are the only ones present (if either of those were
missing, we wouldn't have gotten here...) */
if (entrycount == 2) {
putstr(tmpwin, 0, "(only two entries)");
} else {
/* showing an elipsis three times (once for each file)
results in total size being 24 lines, forcing a
--More-- prompt if user only has a 24 line screen;
that doesn't look very good but isn't incorrect;
including it avoids ambiguity about whether there
are other lines */
if (entrycount > 3)
putstr(tmpwin, 0, " ...");
putstr(tmpwin, 0, xbuf); /* already decrypted */
}
}
closeit:
(void) dlb_fclose(fh);
} else {
/* since this comes out via impossible(), it won't be integrated
with the text window of values, but it shouldn't ever happen
so we won't waste effort integrating it */
couldnt_open_file(fname);
}
}
/* Gets a random line of text from file 'fname', and returns it.