Merge branch 'master' into NetHack-3.7
This commit is contained in:
@@ -470,6 +470,17 @@ struct early_opt {
|
|||||||
boolean valallowed;
|
boolean valallowed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ptr_array {
|
||||||
|
size_t length;
|
||||||
|
size_t max_length;
|
||||||
|
void ** elements;
|
||||||
|
};
|
||||||
|
typedef struct ptr_array ptr_array_t;
|
||||||
|
|
||||||
|
/* logging verbosity levels */
|
||||||
|
#define LOG_MINIMAL 0
|
||||||
|
#define LOG_VERBOSE 1
|
||||||
|
|
||||||
/* special key functions */
|
/* special key functions */
|
||||||
enum nh_keyfunc {
|
enum nh_keyfunc {
|
||||||
NHKF_ESC = 0,
|
NHKF_ESC = 0,
|
||||||
|
|||||||
@@ -28,6 +28,13 @@ E void FDECL(welcome, (BOOLEAN_P));
|
|||||||
E time_t NDECL(get_realtime);
|
E time_t NDECL(get_realtime);
|
||||||
E int FDECL(argcheck, (int, char **, enum earlyarg));
|
E int FDECL(argcheck, (int, char **, enum earlyarg));
|
||||||
E void NDECL(early_init);
|
E void NDECL(early_init);
|
||||||
|
E void NDECL(fuzzer_start);
|
||||||
|
E void NDECL(fuzzer_stop);
|
||||||
|
E void NDECL(fuzzer_toggle);
|
||||||
|
E void VDECL(fuzzer_log, (int, const char *, ...)) PRINTF_F(2, 3);
|
||||||
|
E void NDECL(fuzzer_check);
|
||||||
|
E void NDECL(fuzzer_auto_start);
|
||||||
|
E boolean FDECL(fuzzer_msg_history, (const char *));
|
||||||
|
|
||||||
/* ### apply.c ### */
|
/* ### apply.c ### */
|
||||||
|
|
||||||
@@ -951,6 +958,7 @@ E boolean
|
|||||||
FDECL(fuzzymatch, (const char *, const char *, const char *, BOOLEAN_P));
|
FDECL(fuzzymatch, (const char *, const char *, const char *, BOOLEAN_P));
|
||||||
E void FDECL(init_random, (int FDECL((*fn), (int))));
|
E void FDECL(init_random, (int FDECL((*fn), (int))));
|
||||||
E void FDECL(reseed_random, (int FDECL((*fn), (int))));
|
E void FDECL(reseed_random, (int FDECL((*fn), (int))));
|
||||||
|
E void FDECL(set_random, (unsigned long, int FDECL((*fn), (int))));
|
||||||
E time_t NDECL(getnow);
|
E time_t NDECL(getnow);
|
||||||
E int NDECL(getyear);
|
E int NDECL(getyear);
|
||||||
#if 0
|
#if 0
|
||||||
@@ -969,6 +977,8 @@ E void FDECL(strbuf_append, (strbuf_t *, const char *));
|
|||||||
E void FDECL(strbuf_reserve, (strbuf_t *, int));
|
E void FDECL(strbuf_reserve, (strbuf_t *, int));
|
||||||
E void FDECL(strbuf_empty, (strbuf_t *));
|
E void FDECL(strbuf_empty, (strbuf_t *));
|
||||||
E void FDECL(strbuf_nl_to_crlf, (strbuf_t *));
|
E void FDECL(strbuf_nl_to_crlf, (strbuf_t *));
|
||||||
|
E struct ptr_array * FDECL(ptr_array_new, (size_t length));
|
||||||
|
E void FDECL(ptr_array_free, (struct ptr_array *));
|
||||||
|
|
||||||
/* ### invent.c ### */
|
/* ### invent.c ### */
|
||||||
|
|
||||||
@@ -2157,6 +2167,7 @@ E int FDECL(rnd, (int));
|
|||||||
E int FDECL(d, (int, int));
|
E int FDECL(d, (int, int));
|
||||||
E int FDECL(rne, (int));
|
E int FDECL(rne, (int));
|
||||||
E int FDECL(rnz, (int));
|
E int FDECL(rnz, (int));
|
||||||
|
E unsigned long NDECL(rul);
|
||||||
|
|
||||||
/* ### role.c ### */
|
/* ### role.c ### */
|
||||||
|
|
||||||
|
|||||||
@@ -433,6 +433,10 @@ struct instance_flags {
|
|||||||
chosen_windowport[], but do not switch to
|
chosen_windowport[], but do not switch to
|
||||||
it in the midst of options processing */
|
it in the midst of options processing */
|
||||||
boolean obsolete; /* obsolete options can point at this, it isn't used */
|
boolean obsolete; /* obsolete options can point at this, it isn't used */
|
||||||
|
boolean fuzzer_auto_start; /* start fuzzer automatically */
|
||||||
|
int fuzzer_stop_and_save; /* move when fuzzer stops and saves game */
|
||||||
|
boolean fuzzer_saving; /* fuzzer is saving game */
|
||||||
|
int verbose_logging_start; /* move when verbose fuzzer logging starts */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
133
src/allmain.c
133
src/allmain.c
@@ -4,7 +4,7 @@
|
|||||||
/* NetHack may be freely redistributed. See license for details. */
|
/* NetHack may be freely redistributed. See license for details. */
|
||||||
|
|
||||||
/* various code that was replicated in *main.c */
|
/* various code that was replicated in *main.c */
|
||||||
|
#define NEED_VARARGS
|
||||||
#include "hack.h"
|
#include "hack.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
@@ -441,6 +441,8 @@ boolean resuming;
|
|||||||
#ifdef MAIL
|
#ifdef MAIL
|
||||||
ckmailstatus();
|
ckmailstatus();
|
||||||
#endif
|
#endif
|
||||||
|
fuzzer_check();
|
||||||
|
|
||||||
rhack((char *) 0);
|
rhack((char *) 0);
|
||||||
}
|
}
|
||||||
if (u.utotype) /* change dungeon level */
|
if (u.utotype) /* change dungeon level */
|
||||||
@@ -588,6 +590,8 @@ newgame()
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
fuzzer_auto_start();
|
||||||
|
|
||||||
#ifdef MFLOPPY
|
#ifdef MFLOPPY
|
||||||
gameDiskPrompt();
|
gameDiskPrompt();
|
||||||
#endif
|
#endif
|
||||||
@@ -927,4 +931,131 @@ const char *opts;
|
|||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static FILE * g_fuzzer_log_file = NULL;
|
||||||
|
static int g_fuzzer_log_level = LOG_MINIMAL;
|
||||||
|
|
||||||
|
/* fuzzer_start() starts the fuzzer opening the fuzzer log file */
|
||||||
|
void
|
||||||
|
fuzzer_start()
|
||||||
|
{
|
||||||
|
if (!iflags.debug_fuzzer) {
|
||||||
|
const char * fq_replay;
|
||||||
|
|
||||||
|
iflags.debug_fuzzer = TRUE;
|
||||||
|
iflags.fuzzer_auto_start = FALSE;
|
||||||
|
|
||||||
|
nhassert(g_fuzzer_log_file == NULL);
|
||||||
|
fq_replay = fqname("fuzzer.log", SAVEPREFIX, 0);
|
||||||
|
|
||||||
|
g_fuzzer_log_file = fopen(fq_replay, "w");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fuzzer_stop() stops the fuzzer and close the fuzzer log file */
|
||||||
|
void
|
||||||
|
fuzzer_stop()
|
||||||
|
{
|
||||||
|
if (iflags.debug_fuzzer) {
|
||||||
|
if(g_fuzzer_log_file != NULL) {
|
||||||
|
fclose(g_fuzzer_log_file);
|
||||||
|
g_fuzzer_log_file = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fuzzer_toggle() toggles fuzzer state */
|
||||||
|
void
|
||||||
|
fuzzer_toggle()
|
||||||
|
{
|
||||||
|
if (iflags.debug_fuzzer)
|
||||||
|
fuzzer_stop();
|
||||||
|
else
|
||||||
|
fuzzer_start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fuzzer_log() is used to place messages in the file 'fuzzer.log'. This
|
||||||
|
* log is the primary tool for monitoring fuzzer activity and tracking down
|
||||||
|
* issues that the fuzzer is able to reproduce.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fuzzer_log
|
||||||
|
VA_DECL2(int, level, const char *, str)
|
||||||
|
{
|
||||||
|
VA_START(str);
|
||||||
|
VA_INIT(str, char *);
|
||||||
|
|
||||||
|
if (!g_fuzzer_log_file)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (iflags.verbose_logging_start != 0 && g.moves >= iflags.verbose_logging_start)
|
||||||
|
g_fuzzer_log_level = LOG_VERBOSE;
|
||||||
|
|
||||||
|
if (level <= g_fuzzer_log_level)
|
||||||
|
Vfprintf(g_fuzzer_log_file, str, VA_ARGS);
|
||||||
|
|
||||||
|
VA_END();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fuzzer_check() is called prior to rhack(0) to allow the fuzzer to
|
||||||
|
* check if it should stop and to allow it to reseed the game.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fuzzer_check()
|
||||||
|
{
|
||||||
|
if (iflags.debug_fuzzer)
|
||||||
|
{
|
||||||
|
if (g.moves >= iflags.fuzzer_stop_and_save) {
|
||||||
|
iflags.fuzzer_saving = TRUE;
|
||||||
|
dosave0();
|
||||||
|
exit_nhwindows("Goodbye from the fuzzer...");
|
||||||
|
fuzzer_stop();
|
||||||
|
nh_terminate(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long seed = rul();
|
||||||
|
set_random(seed, rn2);
|
||||||
|
fuzzer_log(LOG_MINIMAL, "SEED:%ld:%lu\n", g.moves, seed);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fuzzer_auto_start is called when creating a new game to allow
|
||||||
|
* the fuzzer to start itself.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fuzzer_auto_start()
|
||||||
|
{
|
||||||
|
if (iflags.fuzzer_auto_start) {
|
||||||
|
nhassert(!iflags.debug_fuzzer);
|
||||||
|
fuzzer_start();
|
||||||
|
unsigned long seed = rul();
|
||||||
|
set_random(seed, rn2);
|
||||||
|
fuzzer_log(LOG_MINIMAL, "START:%ld:%lu\n", g.moves, seed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fuzzer_msg_history is called during save file recovery to allow
|
||||||
|
* the fuzzer to snoop the messages being recovered. The fuzzer
|
||||||
|
* saves a seed as a message in save files and this is the mechanism
|
||||||
|
* used to recover that seed if the fuzzer is being auto started.
|
||||||
|
*/
|
||||||
|
boolean
|
||||||
|
fuzzer_msg_history(msg)
|
||||||
|
const char * msg;
|
||||||
|
{
|
||||||
|
long saved_moves;
|
||||||
|
unsigned long saved_seed;
|
||||||
|
if (sscanf(msg, "SEED:%ld:%lu", &saved_moves, &saved_seed) == 2) {
|
||||||
|
nhassert(saved_moves == g.moves);
|
||||||
|
if (iflags.fuzzer_auto_start) {
|
||||||
|
fuzzer_start();
|
||||||
|
set_random(saved_seed, rn2);
|
||||||
|
fuzzer_log(LOG_MINIMAL, "START:%ld:%lu\n", g.moves, saved_seed);
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
/*allmain.c*/
|
/*allmain.c*/
|
||||||
|
|||||||
@@ -2516,7 +2516,8 @@ recalc_mapseen()
|
|||||||
struct cemetery *bp, **bonesaddr;
|
struct cemetery *bp, **bonesaddr;
|
||||||
struct trap *t;
|
struct trap *t;
|
||||||
unsigned i, ridx;
|
unsigned i, ridx;
|
||||||
int x, y, ltyp, count, atmp;
|
int x, y, ltyp, count;
|
||||||
|
unsigned int atmp;
|
||||||
|
|
||||||
/* Should not happen in general, but possible if in the process
|
/* Should not happen in general, but possible if in the process
|
||||||
* of being booted from the quest. The mapseen object gets
|
* of being booted from the quest. The mapseen object gets
|
||||||
|
|||||||
@@ -854,7 +854,7 @@ STATIC_DCL struct tm *NDECL(getlt);
|
|||||||
/* Sets the seed for the random number generator */
|
/* Sets the seed for the random number generator */
|
||||||
#ifdef USE_ISAAC64
|
#ifdef USE_ISAAC64
|
||||||
|
|
||||||
static void
|
void
|
||||||
set_random(seed, fn)
|
set_random(seed, fn)
|
||||||
unsigned long seed;
|
unsigned long seed;
|
||||||
int FDECL((*fn), (int));
|
int FDECL((*fn), (int));
|
||||||
@@ -865,7 +865,7 @@ int FDECL((*fn), (int));
|
|||||||
#else /* USE_ISAAC64 */
|
#else /* USE_ISAAC64 */
|
||||||
|
|
||||||
/*ARGSUSED*/
|
/*ARGSUSED*/
|
||||||
static void
|
void
|
||||||
set_random(seed, fn)
|
set_random(seed, fn)
|
||||||
unsigned long seed;
|
unsigned long seed;
|
||||||
int FDECL((*fn), (int)) UNUSED;
|
int FDECL((*fn), (int)) UNUSED;
|
||||||
@@ -917,7 +917,7 @@ int FDECL((*fn), (int));
|
|||||||
{
|
{
|
||||||
/* only reseed if we are certain that the seed generation is unguessable
|
/* only reseed if we are certain that the seed generation is unguessable
|
||||||
* by the players. */
|
* by the players. */
|
||||||
if (has_strong_rngseed)
|
if (has_strong_rngseed && !iflags.debug_fuzzer)
|
||||||
init_random(fn);
|
init_random(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1108,6 +1108,9 @@ phase_of_the_moon() /* 0-7, with 0: new, 4: full */
|
|||||||
register struct tm *lt = getlt();
|
register struct tm *lt = getlt();
|
||||||
register int epact, diy, goldn;
|
register int epact, diy, goldn;
|
||||||
|
|
||||||
|
if(iflags.debug_fuzzer)
|
||||||
|
return rn2(8);
|
||||||
|
|
||||||
diy = lt->tm_yday;
|
diy = lt->tm_yday;
|
||||||
goldn = (lt->tm_year % 19) + 1;
|
goldn = (lt->tm_year % 19) + 1;
|
||||||
epact = (11 * goldn + 18) % 30;
|
epact = (11 * goldn + 18) % 30;
|
||||||
@@ -1122,6 +1125,9 @@ friday_13th()
|
|||||||
{
|
{
|
||||||
register struct tm *lt = getlt();
|
register struct tm *lt = getlt();
|
||||||
|
|
||||||
|
if(iflags.debug_fuzzer)
|
||||||
|
return rn2(30);
|
||||||
|
|
||||||
/* tm_wday (day of week; 0==Sunday) == 5 => Friday */
|
/* tm_wday (day of week; 0==Sunday) == 5 => Friday */
|
||||||
return (boolean) (lt->tm_wday == 5 && lt->tm_mday == 13);
|
return (boolean) (lt->tm_wday == 5 && lt->tm_mday == 13);
|
||||||
}
|
}
|
||||||
@@ -1223,4 +1229,38 @@ strbuf_t *strbuf;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ptr_array_t *
|
||||||
|
ptr_array_new(max_length)
|
||||||
|
size_t max_length;
|
||||||
|
{
|
||||||
|
size_t esize = max_length * sizeof(void *);
|
||||||
|
ptr_array_t * a = (ptr_array_t *) malloc(sizeof(ptr_array_t) + esize);
|
||||||
|
a->elements = (void **)(a + 1);
|
||||||
|
a->length = 0;
|
||||||
|
a->max_length = max_length;
|
||||||
|
memset(a->elements, 0, esize);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ptr_array_free(a)
|
||||||
|
ptr_array_t * a;
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
nhassert(a->length <= a->max_length);
|
||||||
|
|
||||||
|
for(i = 0; i < a->length; i++)
|
||||||
|
if(a->elements[i])
|
||||||
|
free(a->elements[i]);
|
||||||
|
|
||||||
|
for (i = a->length; i < a->max_length; i++) {
|
||||||
|
nhassert(a->elements[i] == NULL);
|
||||||
|
if(a->elements[i])
|
||||||
|
free(a->elements[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(a);
|
||||||
|
}
|
||||||
|
|
||||||
/*hacklib.c*/
|
/*hacklib.c*/
|
||||||
|
|||||||
@@ -1509,6 +1509,8 @@ NHFILE *nhfp;
|
|||||||
if (nhfp->fieldlevel)
|
if (nhfp->fieldlevel)
|
||||||
sfi_str(nhfp, msg, "msghistory", "msg", msgsize);
|
sfi_str(nhfp, msg, "msghistory", "msg", msgsize);
|
||||||
msg[msgsize] = '\0';
|
msg[msgsize] = '\0';
|
||||||
|
if(fuzzer_msg_history(msg))
|
||||||
|
continue;
|
||||||
putmsghistory(msg, TRUE);
|
putmsghistory(msg, TRUE);
|
||||||
++msgcount;
|
++msgcount;
|
||||||
}
|
}
|
||||||
|
|||||||
29
src/rnd.c
29
src/rnd.c
@@ -56,10 +56,21 @@ int FDECL((*fn), (int));
|
|||||||
(int) sizeof seed);
|
(int) sizeof seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned long
|
||||||
|
rul()
|
||||||
|
{
|
||||||
|
unsigned long value;
|
||||||
|
|
||||||
|
value = (unsigned long) isaac64_next_uint64(&rnglist[CORE].rng_state);
|
||||||
|
fuzzer_log(LOG_VERBOSE, "RANDOM:%llu\n", value);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
RND(int x)
|
RND(int x)
|
||||||
{
|
{
|
||||||
return (isaac64_next_uint64(&rnglist[CORE].rng_state) % x);
|
return (rul() % x);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 0 <= rn2(x) < x, but on a different sequence from the "main" rn2;
|
/* 0 <= rn2(x) < x, but on a different sequence from the "main" rn2;
|
||||||
@@ -69,6 +80,8 @@ int
|
|||||||
rn2_on_display_rng(x)
|
rn2_on_display_rng(x)
|
||||||
register int x;
|
register int x;
|
||||||
{
|
{
|
||||||
|
if (iflags.debug_fuzzer)
|
||||||
|
return rn2(x);
|
||||||
return (isaac64_next_uint64(&rnglist[DISP].rng_state) % x);
|
return (isaac64_next_uint64(&rnglist[DISP].rng_state) % x);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,6 +107,20 @@ register int x;
|
|||||||
seed *= 2739110765;
|
seed *= 2739110765;
|
||||||
return (int)((seed >> 16) % (unsigned)x);
|
return (int)((seed >> 16) % (unsigned)x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned long
|
||||||
|
rul()
|
||||||
|
{
|
||||||
|
#if defined(LINT) && defined(UNIX)
|
||||||
|
return (unsigned long) rand();
|
||||||
|
#else /* LINT */
|
||||||
|
#if defined(UNIX) || defined(RANDOM)
|
||||||
|
return (unsigned long) Rand();
|
||||||
|
#else
|
||||||
|
return (unsigned long) (Rand() >> 3);
|
||||||
|
#endif /* defined(UNIX) || defined(RANDOM) */
|
||||||
|
#endif /* LINT */
|
||||||
|
}
|
||||||
#endif /* USE_ISAAC64 */
|
#endif /* USE_ISAAC64 */
|
||||||
|
|
||||||
/* 0 <= rn2(x) < x */
|
/* 0 <= rn2(x) < x */
|
||||||
|
|||||||
21
src/save.c
21
src/save.c
@@ -132,7 +132,7 @@ dosave0()
|
|||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
HUP if (iflags.window_inited) {
|
HUP if (!iflags.debug_fuzzer && iflags.window_inited) {
|
||||||
nh_uncompress(fq_save);
|
nh_uncompress(fq_save);
|
||||||
nhfp = open_savefile();
|
nhfp = open_savefile();
|
||||||
if (nhfp) {
|
if (nhfp) {
|
||||||
@@ -1225,6 +1225,25 @@ NHFILE *nhfp;
|
|||||||
}
|
}
|
||||||
++msgcount;
|
++msgcount;
|
||||||
}
|
}
|
||||||
|
/* If the fuzzer is stopping and saving, save a seed as a message.
|
||||||
|
In 3.7, we will modify the save file format and save the seed
|
||||||
|
directly in the saved game state. */
|
||||||
|
if (iflags.fuzzer_saving) {
|
||||||
|
char message[BUFSIZ];
|
||||||
|
unsigned long seed = rul();
|
||||||
|
|
||||||
|
sprintf(message, "SEED:%ld:%lu", g.moves, seed);
|
||||||
|
fuzzer_log(LOG_MINIMAL, "STOP:%ld:%lu\n", g.moves, seed);
|
||||||
|
msglen = strlen(message);
|
||||||
|
if (nhfp->structlevel) {
|
||||||
|
bwrite(nhfp->fd, (genericptr_t) &msglen, sizeof msglen);
|
||||||
|
bwrite(nhfp->fd, (genericptr_t) message, msglen);
|
||||||
|
}
|
||||||
|
if (nhfp->fieldlevel) {
|
||||||
|
sfo_int(nhfp, &msglen, "msghistory", "msghistory_length", 1);
|
||||||
|
sfo_str(nhfp, message, "msghistory", "msg", msglen);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (nhfp->structlevel)
|
if (nhfp->structlevel)
|
||||||
bwrite(nhfp->fd, (genericptr_t) &minusone, sizeof (int));
|
bwrite(nhfp->fd, (genericptr_t) &minusone, sizeof (int));
|
||||||
if (nhfp->fieldlevel)
|
if (nhfp->fieldlevel)
|
||||||
|
|||||||
@@ -3742,7 +3742,7 @@ struct opvar *mc;
|
|||||||
{
|
{
|
||||||
int x, y;
|
int x, y;
|
||||||
schar mapc;
|
schar mapc;
|
||||||
xchar lit;
|
uchar lit;
|
||||||
struct opvar *ret = selection_opvar((char *) 0);
|
struct opvar *ret = selection_opvar((char *) 0);
|
||||||
|
|
||||||
if (!ov || !mc || !ret)
|
if (!ov || !mc || !ret)
|
||||||
|
|||||||
@@ -475,8 +475,15 @@ int *x, *y, *mod;
|
|||||||
coord cc;
|
coord cc;
|
||||||
DWORD count;
|
DWORD count;
|
||||||
really_move_cursor();
|
really_move_cursor();
|
||||||
if (iflags.debug_fuzzer)
|
if (iflags.debug_fuzzer) {
|
||||||
return randomkey();
|
int poskey = randomkey();
|
||||||
|
|
||||||
|
if (poskey == 0) {
|
||||||
|
*x = rn2(console.width);
|
||||||
|
*y = rn2(console.height);
|
||||||
|
}
|
||||||
|
return poskey;
|
||||||
|
}
|
||||||
ch = (g.program_state.done_hup)
|
ch = (g.program_state.done_hup)
|
||||||
? '\033'
|
? '\033'
|
||||||
: keyboard_handler.pCheckInput(
|
: keyboard_handler.pCheckInput(
|
||||||
|
|||||||
@@ -337,7 +337,7 @@ attempt_restore:
|
|||||||
resuming = TRUE; /* not starting new game */
|
resuming = TRUE; /* not starting new game */
|
||||||
if (discover)
|
if (discover)
|
||||||
You("are in non-scoring discovery mode.");
|
You("are in non-scoring discovery mode.");
|
||||||
if (discover || wizard) {
|
if ((discover || wizard) && !iflags.fuzzer_auto_start) {
|
||||||
if (yn("Do you want to keep the save file?") == 'n')
|
if (yn("Do you want to keep the save file?") == 'n')
|
||||||
(void) delete_savefile();
|
(void) delete_savefile();
|
||||||
else {
|
else {
|
||||||
@@ -462,6 +462,23 @@ char *argv[];
|
|||||||
case 'X':
|
case 'X':
|
||||||
discover = TRUE, wizard = FALSE;
|
discover = TRUE, wizard = FALSE;
|
||||||
break;
|
break;
|
||||||
|
case 'F':
|
||||||
|
{
|
||||||
|
iflags.fuzzer_auto_start = 1;
|
||||||
|
|
||||||
|
if (argc > 1 && argv[1][0] != '-') {
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
iflags.fuzzer_stop_and_save = atoi(*argv);
|
||||||
|
|
||||||
|
if (argc > 1 && argv[1][0] != '-') {
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
iflags.verbose_logging_start = atoi(*argv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
#ifdef NEWS
|
#ifdef NEWS
|
||||||
case 'n':
|
case 'n':
|
||||||
iflags.news = FALSE;
|
iflags.news = FALSE;
|
||||||
|
|||||||
@@ -720,9 +720,19 @@ nt_assert_failed(expression, filepath, line)
|
|||||||
{
|
{
|
||||||
const char * filename;
|
const char * filename;
|
||||||
|
|
||||||
/* get file name from path */
|
|
||||||
filename = strrchr(filepath, '\\');
|
filename = strrchr(filepath, '\\');
|
||||||
filename = (filename == NULL ? filepath : filename + 1);
|
filename = (filename == NULL ? filepath : filename + 1);
|
||||||
|
|
||||||
|
if (IsDebuggerPresent()) {
|
||||||
|
char message[BUFSIZ];
|
||||||
|
snprintf(message, sizeof(message),
|
||||||
|
"nhassert(%s) failed in file '%s' at line %d",
|
||||||
|
expression, filename, line);
|
||||||
|
OutputDebugStringA(message);
|
||||||
|
DebugBreak();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get file name from path */
|
||||||
impossible("nhassert(%s) failed in file '%s' at line %d",
|
impossible("nhassert(%s) failed in file '%s' at line %d",
|
||||||
expression, filename, line);
|
expression, filename, line);
|
||||||
}
|
}
|
||||||
|
|||||||
142
win/tty/topl.c
142
win/tty/topl.c
@@ -259,7 +259,7 @@ register const char *bp;
|
|||||||
&& cw->cury == 0
|
&& cw->cury == 0
|
||||||
&& n0 + (int) strlen(g.toplines) + 3 < CO - 8 /* room for --More-- */
|
&& n0 + (int) strlen(g.toplines) + 3 < CO - 8 /* room for --More-- */
|
||||||
&& (notdied = strncmp(bp, "You die", 7)) != 0) {
|
&& (notdied = strncmp(bp, "You die", 7)) != 0) {
|
||||||
nhassert((long) strlen(g.toplines) == cw->curx);
|
/* nhassert((long) strlen(g.toplines) == cw->curx); */
|
||||||
Strcat(g.toplines, " ");
|
Strcat(g.toplines, " ");
|
||||||
Strcat(g.toplines, bp);
|
Strcat(g.toplines, bp);
|
||||||
cw->curx += 2;
|
cw->curx += 2;
|
||||||
@@ -617,6 +617,66 @@ boolean purged; /* True: took history's pointers, False: just cloned them */
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
STATIC_OVL ptr_array_t *
|
||||||
|
get_message_history()
|
||||||
|
{
|
||||||
|
char *mesg;
|
||||||
|
int i;
|
||||||
|
struct WinDesc *cw;
|
||||||
|
size_t max_length;
|
||||||
|
ptr_array_t * a;
|
||||||
|
|
||||||
|
nhassert(WIN_MESSAGE != WIN_ERR);
|
||||||
|
nhassert(wins[WIN_MESSAGE] != NULL);
|
||||||
|
|
||||||
|
/* paranoia (too early or too late panic save attempt?) */
|
||||||
|
if (WIN_MESSAGE == WIN_ERR || !wins[WIN_MESSAGE])
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
cw = wins[WIN_MESSAGE];
|
||||||
|
|
||||||
|
max_length = cw->rows;
|
||||||
|
|
||||||
|
if (*g.toplines) max_length++;
|
||||||
|
|
||||||
|
a = ptr_array_new(max_length);
|
||||||
|
|
||||||
|
nhassert(cw->maxrow <= cw->rows);
|
||||||
|
for (i = 0; i < cw->rows; ++i) {
|
||||||
|
mesg = cw->data[(i + cw->maxrow) % cw->rows];
|
||||||
|
if (mesg && *mesg)
|
||||||
|
a->elements[a->length++] = strdup(mesg);
|
||||||
|
}
|
||||||
|
if (*g.toplines)
|
||||||
|
a->elements[a->length++] = strdup(g.toplines);
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATIC_OVL void
|
||||||
|
purge_message_history()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct WinDesc *cw;
|
||||||
|
|
||||||
|
nhassert(WIN_MESSAGE != WIN_ERR);
|
||||||
|
nhassert(wins[WIN_MESSAGE] != NULL);
|
||||||
|
|
||||||
|
cw = wins[WIN_MESSAGE];
|
||||||
|
|
||||||
|
*g.toplines = '\0';
|
||||||
|
|
||||||
|
for (i = 0; i < cw->rows; ++i) {
|
||||||
|
if (cw->data[i]) {
|
||||||
|
free(cw->data[i]);
|
||||||
|
cw->data[i] = (char *) 0;
|
||||||
|
cw->datlen[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cw->maxcol = cw->maxrow = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is called by the core save routines.
|
* This is called by the core save routines.
|
||||||
* Each time we are called, we return one string from the
|
* Each time we are called, we return one string from the
|
||||||
@@ -631,21 +691,25 @@ char *
|
|||||||
tty_getmsghistory(init)
|
tty_getmsghistory(init)
|
||||||
boolean init;
|
boolean init;
|
||||||
{
|
{
|
||||||
static int nxtidx;
|
static size_t nxtidx;
|
||||||
char *nextmesg;
|
static ptr_array_t * saved_messages = NULL;
|
||||||
char *result = 0;
|
char *result = NULL;
|
||||||
|
|
||||||
if (init) {
|
if (init) {
|
||||||
msghistory_snapshot(FALSE);
|
nhassert(saved_messages == NULL);
|
||||||
|
saved_messages = get_message_history();
|
||||||
nxtidx = 0;
|
nxtidx = 0;
|
||||||
|
wins[WIN_MESSAGE]->flags |= WIN_LOCKHISTORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (snapshot_mesgs) {
|
if (saved_messages) {
|
||||||
nextmesg = snapshot_mesgs[nxtidx++];
|
if (nxtidx < saved_messages->length)
|
||||||
if (nextmesg) {
|
result = saved_messages->elements[nxtidx++];
|
||||||
result = (char *) nextmesg;
|
|
||||||
} else {
|
if (result == NULL) {
|
||||||
free_msghistory_snapshot(FALSE);
|
ptr_array_free(saved_messages);
|
||||||
|
saved_messages = NULL;
|
||||||
|
wins[WIN_MESSAGE]->flags &= ~WIN_LOCKHISTORY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@@ -674,7 +738,10 @@ const char *msg;
|
|||||||
boolean restoring_msghist;
|
boolean restoring_msghist;
|
||||||
{
|
{
|
||||||
static boolean initd = FALSE;
|
static boolean initd = FALSE;
|
||||||
int idx;
|
static ptr_array_t * saved_messages = NULL;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
nhassert(!(wins[WIN_MESSAGE]->flags & WIN_LOCKHISTORY));
|
||||||
|
|
||||||
if (restoring_msghist && !initd) {
|
if (restoring_msghist && !initd) {
|
||||||
/* we're restoring history from the previous session, but new
|
/* we're restoring history from the previous session, but new
|
||||||
@@ -682,7 +749,9 @@ boolean restoring_msghist;
|
|||||||
for instance); collect current history (ie, those new messages),
|
for instance); collect current history (ie, those new messages),
|
||||||
and also clear it out so that nothing will be present when the
|
and also clear it out so that nothing will be present when the
|
||||||
restored ones are being put into place */
|
restored ones are being put into place */
|
||||||
msghistory_snapshot(TRUE);
|
nhassert(saved_messages == NULL);
|
||||||
|
saved_messages = get_message_history();
|
||||||
|
purge_message_history();
|
||||||
initd = TRUE;
|
initd = TRUE;
|
||||||
#ifdef DUMPLOG
|
#ifdef DUMPLOG
|
||||||
/* this suffices; there's no need to scrub saved_pline[] pointers */
|
/* this suffices; there's no need to scrub saved_pline[] pointers */
|
||||||
@@ -704,22 +773,39 @@ boolean restoring_msghist;
|
|||||||
#ifdef DUMPLOG
|
#ifdef DUMPLOG
|
||||||
dumplogmsg(g.toplines);
|
dumplogmsg(g.toplines);
|
||||||
#endif
|
#endif
|
||||||
} else if (snapshot_mesgs) {
|
return;
|
||||||
nhassert(ttyDisplay == NULL ||
|
|
||||||
ttyDisplay->toplin != TOPLINE_NEED_MORE);
|
|
||||||
|
|
||||||
/* done putting arbitrary messages in; put the snapshot ones back */
|
|
||||||
for (idx = 0; snapshot_mesgs[idx]; ++idx) {
|
|
||||||
remember_topl();
|
|
||||||
Strcpy(g.toplines, snapshot_mesgs[idx]);
|
|
||||||
#ifdef DUMPLOG
|
|
||||||
dumplogmsg(g.toplines);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
/* now release the snapshot */
|
|
||||||
free_msghistory_snapshot(TRUE);
|
|
||||||
initd = FALSE; /* reset */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* tty_putmsghistory() is called with msg==NULL to indidate that
|
||||||
|
* we are finished restoring the message history. If we saved
|
||||||
|
* some message history when we started, its time now to appened
|
||||||
|
* those saved messages.
|
||||||
|
*
|
||||||
|
* We don't otherwise expect to get called with msg==NULL.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
nhassert(restoring_msghist && initd);
|
||||||
|
|
||||||
|
if (initd && restoring_msghist) {
|
||||||
|
if (saved_messages) {
|
||||||
|
nhassert(ttyDisplay == NULL ||
|
||||||
|
ttyDisplay->toplin != TOPLINE_NEED_MORE);
|
||||||
|
|
||||||
|
for (i = 0; i < saved_messages->length; i++) {
|
||||||
|
const char * mesg = saved_messages->elements[i];
|
||||||
|
remember_topl();
|
||||||
|
nhassert(mesg);
|
||||||
|
Strcpy(g.toplines, mesg);
|
||||||
|
#ifdef DUMPLOG
|
||||||
|
dumplogmsg(g.toplines);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
ptr_array_free(saved_messages);
|
||||||
|
saved_messages = NULL;
|
||||||
|
}
|
||||||
|
initd = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* TTY_GRAPHICS */
|
#endif /* TTY_GRAPHICS */
|
||||||
|
|||||||
8
win/win32/scripts/fuzzer/clean.bat
Normal file
8
win/win32/scripts/fuzzer/clean.bat
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
set BIN_DIR=..\..\..\..\bin\Debug\Win32
|
||||||
|
|
||||||
|
set FUZZER_LOG=%BIN_DIR%\fuzzer.log
|
||||||
|
set FUZZER_DIR=%BIN_DIR%\fuzzer
|
||||||
|
|
||||||
|
if exist %BIN_DIR%\%USERNAME%* del %BIN_DIR%\%USERNAME%*
|
||||||
|
if exist %FUZZER_LOG% del %FUZZER_LOG%
|
||||||
|
|
||||||
23
win/win32/scripts/fuzzer/longtest.bat
Normal file
23
win/win32/scripts/fuzzer/longtest.bat
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
echo off
|
||||||
|
|
||||||
|
SETLOCAL ENABLEEXTENSIONS
|
||||||
|
SETLOCAL ENABLEDELAYEDEXPANSION
|
||||||
|
|
||||||
|
set STEP_SIZE=5000
|
||||||
|
set FINAL_MOVE=500000
|
||||||
|
set START_MOVE=5000
|
||||||
|
|
||||||
|
for /L %%i in (%START_MOVE%, %STEP_SIZE%, %FINAL_MOVE%) do (
|
||||||
|
|
||||||
|
call runtill.bat %%i
|
||||||
|
|
||||||
|
if ERRORLEVEL 1 (
|
||||||
|
echo FAILED getting running to %%i.
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
echo SUCCESS.
|
||||||
|
|
||||||
|
|
||||||
7
win/win32/scripts/fuzzer/restore.bat
Normal file
7
win/win32/scripts/fuzzer/restore.bat
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
call clean.bat
|
||||||
|
|
||||||
|
set BIN_DIR=..\..\..\..\bin\Debug\Win32
|
||||||
|
set SAVED_GAME=%USERNAME%-wizard.NetHack-saved-game
|
||||||
|
set FUZZER_DIR=%BIN_DIR%\fuzzer
|
||||||
|
|
||||||
|
copy %FUZZER_DIR%\%SAVED_GAME% %BIN_DIR%\%SAVED_GAME%
|
||||||
73
win/win32/scripts/fuzzer/runtill.bat
Normal file
73
win/win32/scripts/fuzzer/runtill.bat
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
REM
|
||||||
|
REM runtill target_move
|
||||||
|
REM
|
||||||
|
echo off
|
||||||
|
|
||||||
|
SETLOCAL ENABLEEXTENSIONS
|
||||||
|
SETLOCAL ENABLEDELAYEDEXPANSION
|
||||||
|
|
||||||
|
set TARGET_MOVE=%1
|
||||||
|
|
||||||
|
if %TARGET_MOVE% == "" (
|
||||||
|
echo Usage:runtill target_move
|
||||||
|
goto :eof
|
||||||
|
)
|
||||||
|
|
||||||
|
set BIN_DIR=..\..\..\..\bin\Debug\Win32
|
||||||
|
set SAVED_GAME=%USERNAME%-wizard.NetHack-saved-game
|
||||||
|
set LOG_FILE=%BIN_DIR%\runtil.log
|
||||||
|
set FUZZER_LOG=%BIN_DIR%\fuzzer.log
|
||||||
|
set FUZZER_DIR=%BIN_DIR%\fuzzer
|
||||||
|
set BASELINE=%FUZZER_DIR%\fuzzer.log
|
||||||
|
|
||||||
|
if not exist %FUZZER_DIR% mkdir %FUZZER_DIR%
|
||||||
|
|
||||||
|
call clean.bat
|
||||||
|
|
||||||
|
if not exist %FUZZER_DIR%\%SAVED_GAME% (
|
||||||
|
%BIN_DIR%\nethack -D -F 0
|
||||||
|
|
||||||
|
copy %BIN_DIR%\%SAVED_GAME% %FUZZER_DIR%
|
||||||
|
)
|
||||||
|
|
||||||
|
call restore.bat
|
||||||
|
|
||||||
|
%BIN_DIR%\nethack -D -F %TARGET_MOVE%
|
||||||
|
|
||||||
|
move %BIN_DIR%\*.snap %BIN_DIR%\snapshots
|
||||||
|
copy %FUZZER_LOG% %BASELINE%
|
||||||
|
|
||||||
|
for /f "tokens=2,3 delims=: usebackq" %%i in (`findstr /c:START %BASELINE%`) do (
|
||||||
|
set START_SEED=%%j
|
||||||
|
set START_MOVE=%%i
|
||||||
|
)
|
||||||
|
|
||||||
|
for /f "tokens=2,3 delims=: usebackq" %%i in (`findstr /c:STOP %BASELINE%`) do (
|
||||||
|
set STOP_SEED=%%j
|
||||||
|
set STOP_MOVE=%%i
|
||||||
|
)
|
||||||
|
|
||||||
|
if !STOP_MOVE! LSS %TARGET_MOVE% (
|
||||||
|
cls
|
||||||
|
echo FAILED: Failed to reach target move. !STOP_MOVE! is not GTE %TARGET_MOVE%.
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
call restore.bat
|
||||||
|
|
||||||
|
%BIN_DIR%\nethack -D -F %TARGET_MOVE%
|
||||||
|
|
||||||
|
fc %FUZZER_LOG% %BASELINE%
|
||||||
|
|
||||||
|
if ERRORLEVEL 1 (
|
||||||
|
cls
|
||||||
|
echo FAILED: Unable to reproduce same timeline
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
del /q %FUZZER_DIR%\%SAVED_GAME%
|
||||||
|
|
||||||
|
copy %BIN_DIR%\%SAVED_GAME% %FUZZER_DIR%
|
||||||
|
|
||||||
|
echo !START_MOVE! to !STOP_MOVE!.
|
||||||
|
echo SUCCESS.
|
||||||
Reference in New Issue
Block a user