add CRASHREPORT directly to browser

add CRASHREPORT for Windows
add ^P info to report (via DUMPLOG)

new options: crash_email, crash_name, crash_urlmax
new game command: #bugreport
new config option: CRASHREPORT_EXEC_NOSTDERR
new command line option: --bidshow

deleted helper scripts:
    NetHackCrashReport.Javascript
    nhcrashreport.lua

misc:
    update CRASHREPORTURL (will need to be updated before release)
    update bitrot in winchain
    winchain for Windows
    add missing synch_wait for NetHackW --showpaths
    add PANICTRACE (and CRASHREPORT) in mdlib.c:build_opts

missing:
    packaging (Windows needs the pdb file)
    no testing with MSVC command line build

port status:
    linux: working, but glibc's backtrace doesn't show static functions
    Windows VS: working.  pdb file is large - looking into options
    MacOS: working
    msdos: not supported
    VMS: not supported
    MSVC: planned, but not attempted
    MSYS2: working, but libbacktrace not showing symbols (yet?)
This commit is contained in:
nhkeni
2024-02-06 18:33:59 -05:00
parent cf3cbcf832
commit dbe5c98dca
37 changed files with 1001 additions and 315 deletions

View File

@@ -163,6 +163,9 @@ autounlock when attempting to open a locked door or loot [Apply-Key]
omitted or skipped and Apply-Key is omitted or you aren't omitted or skipped and Apply-Key is omitted or you aren't
carrying an unlocking tool or you decline to use one carrying an unlocking tool or you decline to use one
boulder override the default boulder symbol [`] boulder override the default boulder symbol [`]
crash_email email address to use when filling in crash reports []
crash_name name to use when filling in crash reports []
crash_urlmax length of longest url we can generate for a crash report []
disclose the types of information you want [ni na nv ng nc no] disclose the types of information you want [ni na nv ng nc no]
offered at the end of the game offered at the end of the game
(space separated list of two-character values; (space separated list of two-character values;

View File

@@ -1222,6 +1222,10 @@ Toggle the
.op autopickup .op autopickup
option on/off. option on/off.
Default key is \(oq@\(cq. Default key is \(oq@\(cq.
.lp "#bugreport"
Bring up a browser window to submit a report to the NetHack Development Team.
Can be disabled at the time the program is built; when enabled,
CRASHREPORTURL must be set in the system configuration file.
.lp "#call " .lp "#call "
Call (name) a monster, or an object in inventory, on the floor, Call (name) a monster, or an object in inventory, on the floor,
or in the discoveries list, or add an annotation for the or in the discoveries list, or add an annotation for the
@@ -4910,6 +4914,22 @@ window, windowframe, windowtext).
If NetHack can, it should wrap long lines of text if they don't fit in If NetHack can, it should wrap long lines of text if they don't fit in
the visible area of the window. the visible area of the window.
.hn 2 .hn 2
Crash Report Options
.pg
Please note that NetHack does not send \fBany\fP information off your
computer unless you manually click submit on a form.
.si
.lp "OPTION=crash_email:\fIemail_address\fP
.lp "OPTION=crash_name:\fIyour_name\fP
.ei
These options are used only to save you some typing on the crash
report and #bugreport forms.
.si
.lp "OPTION=crash_urlmax:\fIbytes\fP
.ei
This option is used to limit the length of the URLs generated and is only
needed if your browser cannot handle arbitrarily long URLs.
.hn 2
Platform-specific Customization options Platform-specific Customization options
.pg .pg
Here are explanations of options that are used by specific platforms or ports Here are explanations of options that are used by specific platforms or ports
@@ -6008,10 +6028,11 @@ large unless it is actively maintained.
. .
.lp .lp
CRASHREPORTURL\ =\ If set to CRASHREPORTURL\ =\ If set to
\f(CRhttps://www.nethack.org/common/contact.html\fP \f(CRhttps://www.nethack.org/links/cr-37BETA.html\fP
and support is compiled in, brings up a browser window populated with and support is compiled in, brings up a browser window pre-populated with
the information needed to report a problem if the game panics or ends the information needed to report a problem if the game panics or ends
up in an internally inconsistent state. up in an internally inconsistent state, or if the #bugreport command is
invoked.
.hn 1 .hn 1
Scoring Scoring
.pg .pg

View File

@@ -26,6 +26,8 @@
\newcommand{\elist}{\end{list}} \newcommand{\elist}{\end{list}}
\hyphenation{CRASHREPORTURL}
% this will make \tt underscores look better, but requires that % this will make \tt underscores look better, but requires that
% math subscripts will never be used in this document % math subscripts will never be used in this document
\catcode`\_=12 \catcode`\_=12
@@ -1332,6 +1334,12 @@ Show your attributes. Default key is `{\tt \^{}X}'.
\item[\tb{\#autopickup}] \item[\tb{\#autopickup}]
Toggle the {\it autopickup\/} option. Default key is `{\tt @}'. Toggle the {\it autopickup\/} option. Default key is `{\tt @}'.
%.lp %.lp
\item[\tb{\#bugreport}]
Bring up a browser window to submit a report to the {\it NetHack Development
Team}.
Can be disabled at the time the program is built; when enabled,
CRASHREPORTURL must be set in the system configuration file.
%.lp
\item[\tb{\#call}] \item[\tb{\#call}]
Call (name) a monster, or an object in inventory, on the floor, Call (name) a monster, or an object in inventory, on the floor,
or in the discoveries list, or add an annotation for the or in the discoveries list, or add an annotation for the
@@ -5420,6 +5428,31 @@ If {\it NetHack\/} can, it should wrap long lines of text if they don't fit
in the visible area of the window. in the visible area of the window.
\elist \elist
%.hn 2
\subsection*{Crash Report Options}
%.pg
Please note that NetHack does not send {\textbf any} information off your
computer unless you manually click submit on a form.
%.si
\blist{}
%.lp
\item[OPTION=crash_email:{\it email_address}]
%.lp
\item[OPTION=crash_name:{\it your_name}]
%.ei
\elist
These options are used only to save you some typing on the crash
report and \#bugreport forms.
%.si
\blist{}
%.lp
\item[OPTION=crash_urlmax:{\it bytes}]
%.ei
\elist
This option is used to limit the length of the URLs generated and is only
needed if your browser cannot handle arbitrarily long URLs.
%.hn 2 %.hn 2
\subsection*{Platform-specific Customization options} \subsection*{Platform-specific Customization options}
@@ -6616,10 +6649,11 @@ large unless it is actively maintained.
%.lp %.lp
\item[\ib{CRASHREPORTURL}] \item[\ib{CRASHREPORTURL}]
If set to If set to
{\tt https://www.nethack.org/common/contact.html} {\tt https://www.nethack.org/links/cr-37BETA.html}
and support is compiled in, brings up a browser window populated with and support is compiled in, brings up a browser window populated with
the information needed to report a problem if the game panics or ends the information needed to report a problem if the game panics or ends
up in an internally inconsistent state. up in an internally inconsistent state, or if the \#bugreport command is
invoked.
\elist \elist
%.hn 1 %.hn 1

View File

@@ -530,3 +530,12 @@
# Use highlighting in the status lines when it changes? # Use highlighting in the status lines when it changes?
#OPTIONS=hilite_status:hitpoints/30%/bright-magenta/normal #OPTIONS=hilite_status:hitpoints/30%/bright-magenta/normal
### Crash reports
# CRASHREPORTURL must be set in syscf to enable these options.
# These identify you in crash reports
#OPTIONS=crash_name:Your Name
#OPTIONS=crash_email:user@example.com
# This limits the size of the URL generated for a crash report. Only
# use this if your browser can't handle very long URLs. It should be as
# large as possible.
#OPTIONS=crash_maxurl:4000.

View File

@@ -241,12 +241,33 @@
#ifndef CRASHREPORT #ifndef CRASHREPORT
# ifdef MACOS # ifdef MACOS
/* NB: This needs to be a full path unless it's in the playground. */ # define CRASHREPORT "/usr/bin/open"
//#define CRASHREPORT "NetHackCrashReport.JavaScript"
# endif # endif
# ifdef __linux__ # ifdef __linux__
/* NB: This expects to find the nhlua binary as "./nhlua" */ # define CRASHREPORT "/usr/bin/xdg-open"
//#define CRASHREPORT "nhcrashreport.lua" /* Define this if the terminal is filled with useless error messages
* when the browser launches. */
# define CRASHREPORT_EXEC_NOSTDERR
# endif
# ifdef WIN32
# define CRASHREPORT /* builtin helper */
# endif
#endif
#ifdef CRASHREPORT
# ifndef DUMPLOG
# define DUMPLOG // required to get ^P info
# endif
# ifdef MACOS
# define PANICTRACE
# endif
# ifdef __linux__
# define PANICTRACE
# endif
// This test isn't quite right: CNG is only available from Windows 2000 on.
// But we'll check that at runtime.
# ifdef WIN32
# define PANICTRACE
# endif # endif
#endif #endif

View File

@@ -235,6 +235,11 @@ struct instance_globals_c {
/* dog.c */ /* dog.c */
char catname[PL_PSIZ]; char catname[PL_PSIZ];
/* end.c */
char *crash_email; // email for crash reports
char *crash_name; // human name for crash reports
int crash_urlmax; // maximum length for the url of a crash report
/* symbols.c */ /* symbols.c */
int currentgraphics; int currentgraphics;

View File

@@ -819,10 +819,12 @@ extern struct kinfo *find_delayed_killer(int);
extern void dealloc_killer(struct kinfo *); extern void dealloc_killer(struct kinfo *);
extern void save_killers(NHFILE *); extern void save_killers(NHFILE *);
extern void restore_killers(NHFILE *); extern void restore_killers(NHFILE *);
#ifdef CRASHREPORT #if defined(CRASHREPORT)
extern boolean submit_web_report(const char *, char *); extern boolean submit_web_report(int, const char *, const char *);
extern void crashreport_init(int, char *[]); extern void crashreport_init(int, char *[]);
extern void crashreport_bidshow(void); extern void crashreport_bidshow(void);
extern boolean swr_add_uricoded(const char *, char **, int *, char *);
extern int dobugreport(void);
#endif #endif
extern char *build_english_list(char *); extern char *build_english_list(char *);
#if defined(PANICTRACE) && !defined(NO_SIGNAL) #if defined(PANICTRACE) && !defined(NO_SIGNAL)
@@ -1804,6 +1806,13 @@ extern int dosuspend(void);
extern void nt_regularize(char *); extern void nt_regularize(char *);
extern int(*nt_kbhit)(void); extern int(*nt_kbhit)(void);
extern void Delay(int); extern void Delay(int);
# ifdef CRASHREPORT
struct CRctxt;
extern struct CRctxt *ctxp;
extern int win32_cr_helper(char, struct CRctxt *, void *, int);
extern int win32_cr_gettrace(int, char *, int);
extern int *win32_cr_shellexecute(const char *);
# endif
#endif /* WIN32 */ #endif /* WIN32 */
#endif /* MICRO || WIN32 */ #endif /* MICRO || WIN32 */
@@ -2661,7 +2670,7 @@ extern char *get_sound_effect_filename(int32_t seidint,
char *buf, size_t bufsz, int32_t); char *buf, size_t bufsz, int32_t);
#endif #endif
extern char *base_soundname_to_filename(char *, char *, size_t, int32_t); extern char *base_soundname_to_filename(char *, char *, size_t, int32_t);
extern void set_voice(struct monst *, int32_t, int32_t, int32_t); extern void set_voice(struct monst *, int32_t, int32_t, int32_t);
extern void sound_speak(const char *); extern void sound_speak(const char *);
/* ### sp_lev.c ### */ /* ### sp_lev.c ### */

View File

@@ -418,7 +418,7 @@ enum earlyarg {
#ifdef WIN32 #ifdef WIN32
, ARG_WINDOWS , ARG_WINDOWS
#endif #endif
#ifdef CRASHREPORT #if defined(CRASHREPORT)
, ARG_BIDSHOW , ARG_BIDSHOW
#endif #endif
}; };

View File

@@ -226,6 +226,17 @@ static int optfn_##a(int, int, boolean, char *, char *);
NHOPTB(confirm, Advanced, 0, opt_out, set_in_game, NHOPTB(confirm, Advanced, 0, opt_out, set_in_game,
On, Yes, No, No, NoAlias, &flags.confirm, Term_False, On, Yes, No, No, NoAlias, &flags.confirm, Term_False,
"ask before hitting tame or peaceful monsters") "ask before hitting tame or peaceful monsters")
#ifdef CRASHREPORT
NHOPTC(crash_email, Advanced, PL_NSIZ, opt_in, set_in_game,
No, Yes, No, No, NoAlias,
"email address for reporting")
NHOPTC(crash_name, Advanced, PL_NSIZ, opt_in, set_in_game,
No, Yes, No, No, NoAlias,
"your name for reporting")
NHOPTC(crash_urlmax, Advanced, PL_NSIZ, opt_in, set_in_game,
No, Yes, No, No, NoAlias,
"length of longest url we can generate")
#endif
#ifdef CURSES_GRAPHICS #ifdef CURSES_GRAPHICS
NHOPTC(cursesgraphics, Advanced, 70, opt_in, set_in_config, NHOPTC(cursesgraphics, Advanced, 70, opt_in, set_in_config,
No, Yes, No, No, NoAlias, No, Yes, No, No, NoAlias,

View File

@@ -101,12 +101,7 @@ extern char *windows_exepath(void);
*/ */
#ifdef __MINGW32__ #ifdef __MINGW32__
#if 0
#define MD_USE_TMPFILE_S #define MD_USE_TMPFILE_S
#if !defined(__cplusplus)
extern errno_t tmpfile_s(FILE * restrict * restrict streamptr);
#endif
#endif
# #
#ifdef strncasecmp #ifdef strncasecmp
#undef strncasecmp #undef strncasecmp

View File

@@ -14,8 +14,9 @@ enum wp_ids { wp_tty = 1, wp_X11, wp_Qt, wp_mswin, wp_curses,
wp_chainin, wp_chainout, wp_safestartup, wp_shim, wp_chainin, wp_chainout, wp_safestartup, wp_shim,
wp_hup, wp_guistubs, wp_ttystubs, wp_hup, wp_guistubs, wp_ttystubs,
#ifdef OUTDATED_STUFF #ifdef OUTDATED_STUFF
, wp_mac, wp_Gem, wp_Gnome, wp_amii, wp_amiv wp_mac, wp_Gem, wp_Gnome, wp_amii, wp_amiv,
#endif #endif
wp_trace // XXX do we need this? should chainin/out get an id? TBD
}; };
/* NB: this MUST match chain_procs below */ /* NB: this MUST match chain_procs below */
@@ -107,6 +108,7 @@ extern
/* /*
* If you wish to only support one window system and not use procedure * If you wish to only support one window system and not use procedure
* pointers, add the appropriate #ifdef below. * pointers, add the appropriate #ifdef below.
* XXX which is what?
*/ */
#define init_nhwindows (*windowprocs.win_init_nhwindows) #define init_nhwindows (*windowprocs.win_init_nhwindows)
@@ -359,7 +361,6 @@ struct chain_procs {
void (*win_end_menu)(CARGS, winid, const char *); void (*win_end_menu)(CARGS, winid, const char *);
int (*win_select_menu)(CARGS, winid, int, MENU_ITEM_P **); int (*win_select_menu)(CARGS, winid, int, MENU_ITEM_P **);
char (*win_message_menu)(CARGS, char, int, const char *); char (*win_message_menu)(CARGS, char, int, const char *);
void (*win_update_inventory)(CARGS, int);
void (*win_mark_synch)(CARGS); void (*win_mark_synch)(CARGS);
void (*win_wait_synch)(CARGS); void (*win_wait_synch)(CARGS);
#ifdef CLIPPING #ifdef CLIPPING
@@ -407,6 +408,8 @@ struct chain_procs {
void (*win_status_update)(CARGS, int, genericptr_t, int, int, int, void (*win_status_update)(CARGS, int, genericptr_t, int, int, int,
unsigned long *); unsigned long *);
boolean (*win_can_suspend)(CARGS); boolean (*win_can_suspend)(CARGS);
void (*win_update_inventory)(CARGS, int);
win_request_info *(*win_ctrl_nhwindow)(CARGS, winid, int, win_request_info *);
}; };
#endif /* WINCHAIN */ #endif /* WINCHAIN */

View File

@@ -30,7 +30,7 @@ static void dump_enums(void);
void void
early_init(int argc UNUSED, char *argv[] UNUSED) early_init(int argc UNUSED, char *argv[] UNUSED)
{ {
#ifdef CRASHREPORT #if defined(CRASHREPORT)
// Do this as early as possible, but let ports do other things first. // Do this as early as possible, but let ports do other things first.
crashreport_init(argc, argv); crashreport_init(argc, argv);
#endif #endif
@@ -911,7 +911,7 @@ static const struct early_opt earlyopts[] = {
#ifdef WIN32 #ifdef WIN32
{ ARG_WINDOWS, "windows", 4, TRUE }, { ARG_WINDOWS, "windows", 4, TRUE },
#endif #endif
#ifdef CRASHREPORT #if defined(CRASHREPORT)
{ ARG_BIDSHOW, "bidshow", 7, FALSE }, { ARG_BIDSHOW, "bidshow", 7, FALSE },
#endif #endif
}; };
@@ -935,11 +935,13 @@ argcheck(int argc, char *argv[], enum earlyarg e_arg)
const char *dashdash = ""; const char *dashdash = "";
for (idx = 0; idx < SIZE(earlyopts); idx++) { for (idx = 0; idx < SIZE(earlyopts); idx++) {
if (earlyopts[idx].e == e_arg) if (earlyopts[idx].e == e_arg){
break; break;
}
} }
if (idx >= SIZE(earlyopts) || argc < 1) if (idx >= SIZE(earlyopts) || argc < 1){
return FALSE; return FALSE;
}
for (i = 0; i < argc; ++i) { for (i = 0; i < argc; ++i) {
if (argv[i][0] != '-') if (argv[i][0] != '-')
@@ -1002,10 +1004,12 @@ argcheck(int argc, char *argv[], enum earlyarg e_arg)
dump_glyphids(); dump_glyphids();
return 2; return 2;
#endif #endif
#ifdef CRASHREPORT #if defined(CRASHREPORT)
case ARG_BIDSHOW: case ARG_BIDSHOW:
crashreport_bidshow(); crashreport_bidshow();
return 2; return 2;
#else
#warning "CRASHREPORT CODE NOT INCLUDED"
#endif #endif
#ifdef WIN32 #ifdef WIN32
case ARG_WINDOWS: case ARG_WINDOWS:

View File

@@ -2558,6 +2558,10 @@ struct ext_func_tab extcmdlist[] = {
doattributes, IFBURIED, NULL }, doattributes, IFBURIED, NULL },
{ '@', "autopickup", "toggle the 'autopickup' option on/off", { '@', "autopickup", "toggle the 'autopickup' option on/off",
dotogglepickup, IFBURIED, NULL }, dotogglepickup, IFBURIED, NULL },
#ifdef CRASHREPORT
{ '\0', "bugreport", "file a bug report",
dobugreport, GENERALCMD | NOFUZZERCMD, NULL },
#endif
{ 'C', "call", "name a monster, specific object, or type of object", { 'C', "call", "name a monster, specific object, or type of object",
docallcmd, IFBURIED, NULL }, docallcmd, IFBURIED, NULL },
{ 'Z', "cast", "zap (cast) a spell", { 'Z', "cast", "zap (cast) a spell",

View File

@@ -272,6 +272,10 @@ const struct instance_globals_c g_init_c = {
DUMMY, /* context */ DUMMY, /* context */
/* dog.c */ /* dog.c */
DUMMY, /* catname */ DUMMY, /* catname */
/* end.c */
NULL, /* crash_email */
NULL, /* crash_name */
-1, /* crash_urlmax */
/* symbols.c */ /* symbols.c */
0, /* currentgraphics */ 0, /* currentgraphics */
/* files.c */ /* files.c */

559
src/end.c
View File

@@ -21,9 +21,9 @@
#ifndef NO_SIGNAL #ifndef NO_SIGNAL
static void done_intr(int); static void done_intr(int);
#if defined(UNIX) || defined(VMS) || defined(__EMX__) # if defined(UNIX) || defined(VMS) || defined(__EMX__)
static void done_hangup(int); static void done_hangup(int);
#endif # endif
#endif #endif
static void disclose(int, boolean); static void disclose(int, boolean);
static void get_valuables(struct obj *); static void get_valuables(struct obj *);
@@ -37,6 +37,9 @@ static boolean should_query_disclose_option(int, char *);
static void dump_plines(void); static void dump_plines(void);
#endif #endif
static void dump_everything(int, time_t); static void dump_everything(int, time_t);
#ifdef CRASHREPORT
static const char *get_saved_pline(int);
#endif
#if defined(__BEOS__) || defined(MICRO) || defined(OS2) || defined(WIN32) #if defined(__BEOS__) || defined(MICRO) || defined(OS2) || defined(WIN32)
ATTRNORETURN extern void nethack_exit(int) NORETURN; ATTRNORETURN extern void nethack_exit(int) NORETURN;
@@ -46,9 +49,10 @@ ATTRNORETURN extern void nethack_exit(int) NORETURN;
#define done_stopprint gp.program_state.stopprint #define done_stopprint gp.program_state.stopprint
#ifndef PANICTRACE // XXX is there a configuration that still needs this?
#define NH_abort(x) NH_abort_ //#ifndef PANICTRACE
#endif //#define NH_abort(x) NH_abort_
//#endif
#ifdef AMIGA #ifdef AMIGA
#define NH_abort_ Abort(0) #define NH_abort_ Abort(0)
@@ -64,7 +68,8 @@ ATTRNORETURN extern void nethack_exit(int) NORETURN;
#endif /* !SYSV */ #endif /* !SYSV */
#endif /* !AMIGA */ #endif /* !AMIGA */
#ifdef PANICTRACE /* NB: CRASHREPORT implies PANICTRACE */
#if defined(PANICTRACE)
#include <errno.h> #include <errno.h>
#ifdef PANICTRACE_LIBC #ifdef PANICTRACE_LIBC
#include <execinfo.h> #include <execinfo.h>
@@ -79,32 +84,30 @@ ATTRNORETURN extern void nethack_exit(int) NORETURN;
* -requires -g, which may preclude -O on some compilers * -requires -g, which may preclude -O on some compilers
* *
* And the UI: if sysopt.crashreporturl, and defined(CRASHREPORT) * And the UI: if sysopt.crashreporturl, and defined(CRASHREPORT)
* we gather the stacktrace (etc) and launch a helper to submit a bug report * we gather the stacktrace (etc) and launch a browser to submit a bug report
* otherwise we just use stdout. Requires libc for now. * otherwise we just use stdout. Requires libc for now.
*/ */
#ifdef SYSCF #ifdef SYSCF
#define SYSOPT_PANICTRACE_GDB sysopt.panictrace_gdb # define SYSOPT_PANICTRACE_GDB sysopt.panictrace_gdb
#ifdef PANICTRACE_LIBC # ifdef PANICTRACE_LIBC
#define SYSOPT_PANICTRACE_LIBC sysopt.panictrace_libc # define SYSOPT_PANICTRACE_LIBC sysopt.panictrace_libc
# else
# define SYSOPT_PANICTRACE_LIBC 0
# endif
#else #else
#define SYSOPT_PANICTRACE_LIBC 0 # define SYSOPT_PANICTRACE_GDB (nh_getenv("NETHACK_USE_GDB") == 0 ? 0 : 2)
#endif # ifdef PANICTRACE_LIBC
#else # define SYSOPT_PANICTRACE_LIBC 1
#define SYSOPT_PANICTRACE_GDB (nh_getenv("NETHACK_USE_GDB") == 0 ? 0 : 2) # else
#ifdef PANICTRACE_LIBC # define SYSOPT_PANICTRACE_LIBC 0
#define SYSOPT_PANICTRACE_LIBC 1 # endif
#else
#define SYSOPT_PANICTRACE_LIBC 0
#endif
#endif #endif
#ifdef PANICTRACE
static void NH_abort(char *); static void NH_abort(char *);
#endif
#ifndef NO_SIGNAL #ifndef NO_SIGNAL
static void panictrace_handler(int); static void panictrace_handler(int);
#endif #endif
static boolean NH_panictrace_libc(char *); static boolean NH_panictrace_libc(void);
static boolean NH_panictrace_gdb(void); static boolean NH_panictrace_gdb(void);
#ifndef NO_SIGNAL #ifndef NO_SIGNAL
@@ -171,7 +174,6 @@ panictrace_setsignals(boolean set)
} }
#endif /* NO_SIGNAL */ #endif /* NO_SIGNAL */
#ifdef PANICTRACE
static void static void
NH_abort(char *why) NH_abort(char *why)
{ {
@@ -185,215 +187,394 @@ NH_abort(char *why)
return; return;
aborting = TRUE; aborting = TRUE;
#ifdef CRASHREPORT
if(!submit_web_report(1, "Panic", why))
#endif
{
#ifndef VMS #ifndef VMS
if (gdb_prio == libc_prio && gdb_prio > 0) if (gdb_prio == libc_prio && gdb_prio > 0)
gdb_prio++; gdb_prio++;
if (gdb_prio > libc_prio) { if (gdb_prio > libc_prio) {
(void) (NH_panictrace_gdb() || (libc_prio && NH_panictrace_libc(why))); (void) (NH_panictrace_gdb() || (libc_prio && NH_panictrace_libc()));
} else { } else {
(void) (NH_panictrace_libc(why) || (gdb_prio && NH_panictrace_gdb())); (void) (NH_panictrace_libc() || (gdb_prio && NH_panictrace_gdb()));
} }
#else /* VMS */ #else /* VMS */
/* overload otherwise unused priority for debug mode: 1 = show /* overload otherwise unused priority for debug mode: 1 = show
traceback and exit; 2 = show traceback and stay in debugger */ traceback and exit; 2 = show traceback and stay in debugger */
/* if (wizard && gdb_prio == 1) gdb_prio = 2; */ /* if (wizard && gdb_prio == 1) gdb_prio = 2; */
vms_traceback(gdb_prio); vms_traceback(gdb_prio);
nhUse(libc_prio); nhUse(libc_prio);
#endif /* ?VMS */ #endif /* ?VMS */
}
#ifndef NO_SIGNAL #ifndef NO_SIGNAL
panictrace_setsignals(FALSE); panictrace_setsignals(FALSE);
#endif #endif
NH_abort_; NH_abort_;
} }
#endif
/* Build a URL with a query string and try to launch a new browser window
* to report from panic() or impossible(). Requires libc support for
* the stacktrace. Uses memory on the stack to avoid memory allocation
* (but libc can still do anything it wants). */
/* size of argument list for execve(2) */
#define SWR_LINES 20
/* max stack frames and header lines (details field) */
#define SWR_FRAMES 20
#define SWR_ADD(line) {if(xargc<(SWR_LINES-1)) xargv[xargc++] = line;}
#ifdef CRASHREPORT #ifdef CRASHREPORT
# include <fcntl.h> # include <fcntl.h>
# define HASH_PRAGMA_START \ # ifdef WIN32
# define HASH_PRAGMA_START
# define HASH_PRAGMA_END
# else
# define HASH_PRAGMA_START \
_Pragma("GCC diagnostic push"); \ _Pragma("GCC diagnostic push"); \
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
# define HASH_PRAGMA_END _Pragma("GCC diagnostic pop"); # define HASH_PRAGMA_END _Pragma("GCC diagnostic pop");
# endif
# ifdef MACOS # ifdef MACOS
# include <CommonCrypto/CommonDigest.h> # include <CommonCrypto/CommonDigest.h>
# define HASH_CONTEXT CC_MD4_CTX # define HASH_CONTEXTPTR(CTXP) \
# define HASH_INIT(ctx) CC_MD4_Init(ctx) unsigned char tmp[CC_MD4_DIGEST_LENGTH]; \
# define HASH_UPDATE(ctx, ptr, len) CC_MD4_Update(ctx, ptr, len) CC_MD4_CTX CTXP ## _; \
# define HASH_FINISH(ctx, out) CC_MD4_Final(out, ctx) CC_MD4_CTX *CTXP = &CTXP ## _
# define HASH_RESULT_SIZE CC_MD4_DIGEST_LENGTH # define HASH_INIT(ctxp) !CC_MD4_Init(ctxp)
# define HASH_UPDATE(ctx, ptr, len) !CC_MD4_Update(ctx, ptr, len)
# define HASH_FINISH(ctxp) !CC_MD4_Final(tmp, ctxp)
# define HASH_RESULT_SIZE(ctxp) CC_MD4_DIGEST_LENGTH
# define HASH_RESULT(ctx, inp) *inp = (unsigned char *)ctx
# define HASH_CLEANUP(ctxp)
# define HASH_OFLAGS O_RDONLY
# define HASH_BINFILE_DECL char *binfile = argv[0];
# ifdef BETA
# define HASH_BINFILE \
if (!binfile || !*binfile) { \
/* If this triggers, investigate CFBundleGetMainBundle */ \
/* or CFBundleCopyExecutableURL. */ \
raw_print("BETA warning: crashreport_init called without useful info"); \
goto skip; \
}
# else
# define HASH_BINFILE() \
if (!binfile || !*binfile) { \
goto skip; \
}
# endif
# endif # endif
# ifdef __linux__ # ifdef __linux__
# include <openssl/md4.h> # include <openssl/md4.h>
# define HASH_CONTEXT MD4_CTX # define HASH_CONTEXTPTR(CTXP) \
# define HASH_INIT(ctx) MD4_Init(ctx) unsigned char tmp[MD4_DIGEST_LENGTH]; \
# define HASH_UPDATE(ctx, ptr, len) MD4_Update(ctx, ptr, len) MD4_CTX CTXP ## _; \
# define HASH_FINISH(ctx, out) MD4_Final(out, ctx) MD4_CTX *CTXP = &CTXP ## _
# define HASH_RESULT_SIZE MD4_DIGEST_LENGTH # define HASH_INIT(ctxp) !MD4_Init(ctxp)
# endif # define HASH_UPDATE(ctx, ptr, len) !MD4_Update(ctx, ptr, len)
# define HASH_FINISH(ctxp) !MD4_Final(tmp, ctxp)
# define HASH_RESULT_SIZE(ctxp) MD4_DIGEST_LENGTH
# define HASH_RESULT(ctx, inp) *inp = (unsigned char *)ctx
# define HASH_CLEANUP(ctxp)
# define HASH_OFLAGS O_RDONLY
# define HASH_BINFILE_DECL char binfile[PATH_MAX+1];
# define HASH_BINFILE() \
int len = readlink("/proc/self/exe", binfile, sizeof(binfile)-1); \
if (len>0) { \
binfile[len] = '\0'; \
} else { \
goto skip; \
}
# endif // __linux__
# ifdef WIN32
/* WIN32 takes too much code and is dependent on OS includes we can't
* pull in here, so we call out to code in sys/windows/windsys.c */
# define HASH_CONTEXTPTR(CTXP)
# define HASH_INIT(ctxp) win32_cr_helper('i',ctxp, NULL, 0)
# define HASH_UPDATE(ctxp, ptr, len) win32_cr_helper('u',ctxp, ptr, len)
# define HASH_FINISH(ctxp) win32_cr_helper('f',ctxp,NULL,0)
# define HASH_CLEANUP(ctxp) win32_cr_helper('c',ctxp, NULL, 0)
# define HASH_RESULT_SIZE(ctxp) win32_cr_helper('s',ctxp,NULL,0)
# define HASH_RESULT(ctxp, inp) win32_cr_helper('r',ctxp,inp,0)
# define HASH_OFLAGS _O_RDONLY | _O_BINARY
# define HASH_BINFILE_DECL char *binfile;
# define HASH_BINFILE() \
if(win32_cr_helper('b',NULL,&binfile,0)){ \
goto skip; \
}
# endif // WIN32
// Binary ID - Use only as a hint to contact.html for recognizing our own // Binary ID - Use only as a hint to contact.html for recognizing our own
// binaries. This is easily spoofed! // binaries. This is easily spoofed!
static char bid[(2*HASH_RESULT_SIZE)+1]; static char bid[40];
/* ARGSUSED */ /* ARGSUSED */
void void
crashreport_init(int argc UNUSED, char *argv[] UNUSED){ crashreport_init(int argc UNUSED, char *argv[] UNUSED){
unsigned char tmp[HASH_RESULT_SIZE]; static int once=0; if(once++) return; // NetHackW.exe calls us twice
HASH_BINFILE_DECL;
HASH_PRAGMA_START HASH_PRAGMA_START
HASH_CONTEXT ctx; HASH_CONTEXTPTR(ctxp);
HASH_INIT(&ctx); if(HASH_INIT(ctxp)) goto skip;
#ifdef MACOS HASH_BINFILE(); // Does "goto skip" on error.
char *binfile = argv[0];
if (!binfile || !*binfile) { int fd = open(binfile, HASH_OFLAGS, 0);
# ifdef BETA
// If this triggers, investigate CFBundleGetMainBundle
// or CFBundleCopyExecutableURL.
raw_print("BETA warning: crashreport_init called without useful info");
# endif
goto skip;
}
#endif
#ifdef __linux__
char binfile[PATH_MAX+1];
int len = readlink("/proc/self/exe", binfile, sizeof(binfile)-1);
if (len>0) {
binfile[len] = '\0';
} else {
goto skip;
}
#endif
int fd = open(binfile, O_RDONLY, 0);
if (fd == -1) { if (fd == -1) {
# ifdef BETA # ifdef BETA
raw_printf("open e=%s",strerror(errno)); raw_printf("open e=%s",strerror(errno));
# endif # endif
goto skip; goto skip;
} }
int segsize; int segsize;
char segment[4096]; unsigned char segment[4096];
while (0 < (segsize = read(fd, segment,sizeof(segment)))) { while (0 < (segsize = read(fd, segment,sizeof(segment)))) {
HASH_UPDATE(&ctx, segment, segsize); if(HASH_UPDATE(ctxp, segment, segsize)) goto skip;
} }
HASH_FINISH(&ctx, tmp); if(segsize < 0) {
close(fd);
goto skip;
}
if(HASH_FINISH(ctxp)) goto skip;
close(fd); close(fd);
char *p = bid; char *p = bid;
unsigned char *in = &tmp[0]; unsigned char *in;
char cnt=HASH_RESULT_SIZE; HASH_RESULT(ctxp,&in);
/* Just in case, make sure not to overflow the bid buffer. */
char cnt=min(HASH_RESULT_SIZE(ctxp), (sizeof(bid)-1));
while (cnt--) { while (cnt--) {
p += snprintf(p, HASH_RESULT_SIZE-(p-bid), "%02x",*(in++)); p += snprintf(p, HASH_RESULT_SIZE(ctxp) - (p - bid), "%02x", *(in++));
} }
*p = '\0'; *p = '\0';
return; return;
skip: skip:
strncpy((char *)bid,"unknown",sizeof(bid)-1); strncpy((char *)bid,"unknown",sizeof(bid)-1);
HASH_CLEANUP(ctxp);
HASH_PRAGMA_END HASH_PRAGMA_END
} }
#undef HASH_CONTEXT #undef HASH_CONTEXTPTR
#undef HASH_INIT #undef HASH_INIT
#undef HASH_UPDATE #undef HASH_UPDATE
#undef HASH_FINISH #undef HASH_FINISH
#undef HASH_CLEANUP
#undef HASH_RESULT
#undef HASH_RESULT_SIZE #undef HASH_RESULT_SIZE
#undef HASH_PRAGMA_START #undef HASH_PRAGMA_START
#undef HASH_PRAGMA_END #undef HASH_PRAGMA_END
#undef HASH_BINFILE_DECL
#undef HASH_BINFILE
void void
crashreport_bidshow(void){ crashreport_bidshow(void){
raw_print(bid); #if defined(WIN32) && !defined(WIN32CON)
if(0==win32_cr_helper('D', ctxp, bid, 0))
#endif
{
raw_print(bid);
#ifdef WIN32notyet
wait_synch();
#endif
}
} }
/* Build a URL with a query string and try to launch a new browser window
* to report from panic() or impossible(). Requires libc support for
* the stacktrace. Uses memory on the stack to avoid memory allocation
* (on most platforms) (but libc can still do anything it wants). */
// No theoretial limit for URL length but reality is messy.
// This should work on all modern platforms.
#ifndef MAX_URL
# define MAX_URL 8192
#endif
#ifndef SWR_FRAMES
# define SWR_FRAMES 20
#endif
// mark holds the initial eos; if we can't get the value in
// then we can remove the whole item if desired. For other
// semantics, caller can handle mark.
#define SWR_ADD(str) \
utmp = strlen(str); \
mark = uend; \
if(utmp >= urem) goto full; \
strncpy(uend, str, utmp); \
uend += utmp; urem -= utmp; \
*uend = '\0';
// NB: on overflow this rolls us back to mark, so if we don't
// want to roll back to the last SWR_ADD, update mark before
// calling this macro.
#define SWR_ADD_URIcoded(str) \
if(swr_add_uricoded(str, &uend, &urem, mark))goto full;
// On overflow, truncate to markp (but only if markp != NULL).
boolean boolean
submit_web_report(const char *msg, char *why){ swr_add_uricoded(const char *in, char **out, int *remaining, char *markp){
if (sysopt.crashreporturl) { while(*in){
const char *xargv[SWR_LINES]; if(
char version[100]; isalnum(*in) ||
char versionstring[200]; // used twice as a temp *in == '_' ||
int xargc = 0; *in == '-' ||
char wholetrace[SWR_LINES*80]; // XXX roughly 71 on MacOS, plus buffer *in == '.' ||
int prelines = 0; // count of lines in trace header *in == '~' // ||
char nbuf[6]; // number buffer ){
extern char **environ; **out = *in;
pid_t pid; (*out)++;
(*remaining)--;
SWR_ADD(CRASHREPORT); } else if(*in == ' '){
SWR_ADD(sysopt.crashreporturl); **out = '+';
// then pairs of key value (*out)++;
// subject, generate something useful (*remaining)--;
SWR_ADD("subject"); } else {
snprintf(version, sizeof(version), "%s report for NetHack %s", if(*remaining <= 3){
msg, version_string(versionstring, sizeof(versionstring))); if(markp) *out = markp, *remaining = 0;
SWR_ADD(version); **out = '\0';
// name: someday, this might be stored in nethackcnf return TRUE;
// email: someday, this might be stored in nethackcnf }
// gitver, pull from version.c int x = snprintf(*out, *remaining, "%%%02X", *in);
SWR_ADD("gitver"); *out += x;
SWR_ADD(getversionstring(versionstring, sizeof(versionstring))); *remaining -= x;
// hardware: leave for user
// software: leave for user
// comments: leave for user
// details: stack trace
SWR_ADD("details");
// XXX header for wholetrace - what other info do we want?
// NB: prelines not tested against size of SWR_FRAMES.
#define SWR_HDR(line) \
if (endp<&wholetrace[sizeof(wholetrace)]) { \
endp+=snprintf(endp, sizeof(wholetrace)-(endp-wholetrace), "%s\n",line); \
prelines++; \
}
#define SWR_HDRnonl(line) \
if (endp<&wholetrace[sizeof(wholetrace)]) { \
endp+=snprintf(endp, sizeof(wholetrace)-(endp-wholetrace), "%s",line); \
}
char *endp = wholetrace;
wholetrace[0] = 0;
if (why) {
SWR_HDR(why);
} }
in++;
if(! *remaining){
if(markp) *out = markp, *remaining = 0;
**out = '\0';
return TRUE;
}
**out = '\0';
}
return FALSE; // normal return
}
SWR_HDRnonl("bid: "); static char url[MAX_URL]; // XXX too bad this isn't allocated as needed
SWR_HDR(bid); static int urem = MAX_URL; // adjusted for gc.crash_urlmax below
static char *uend = url;
static int utmp; // used inside macros
static char *mark; // holds previous terminator (generally)
boolean
submit_web_report(int cos, const char *msg, const char *why){
urem = (gc.crash_urlmax < 0 || gc.crash_urlmax > MAX_URL)
? MAX_URL : min(MAX_URL,gc.crash_urlmax);
char temp[200];
char temp2[200];
int countpp=0; // pre and post traceback lines
// URL loaded for creating reports to the NetHack DevTeam
// CRASHREPORTURL=https://nethack.org/links/cr-37BETA.html
if(!sysopt.crashreporturl) return FALSE;
SWR_ADD(sysopt.crashreporturl);
/* cos - operation, v - version */
snprintf(temp, sizeof(temp), "?cos=%d&v=1",cos);
SWR_ADD(temp);
/* msg==NULL for #bugreport */
if(msg){
SWR_ADD("&subject=");
snprintf(temp, sizeof(temp), "%s report for NetHack %s",
msg, version_string(temp2, sizeof(temp2)));
SWR_ADD_URIcoded(temp);
}
SWR_ADD("&gitver=");
SWR_ADD_URIcoded(getversionstring(temp2, sizeof(temp2)));
if(gc.crash_name){
SWR_ADD("&name=");
SWR_ADD_URIcoded(gc.crash_name);
}
if(gc.crash_email){
SWR_ADD("&email=");
SWR_ADD_URIcoded(gc.crash_email);
}
// hardware: leave for user
// software: leave for user
// comments: leave for user
SWR_ADD("&details=");
if (why) {
SWR_ADD_URIcoded(why);
SWR_ADD_URIcoded("\n");
mark=uend;
countpp++;
}
SWR_ADD_URIcoded("bid: ");
SWR_ADD_URIcoded(bid);
SWR_ADD_URIcoded("\n");
mark=uend;
countpp++;
int count = 0;
if(cos==1){
#ifdef WIN32
count=win32_cr_gettrace(SWR_FRAMES,uend, MAX_URL-(uend-url));
uend=eos(url);
#else
void *bt[SWR_FRAMES]; void *bt[SWR_FRAMES];
int count, x; int x;
char **info, buf[BUFSZ]; char **info;
count = backtrace(bt, SIZE(bt)); count = backtrace(bt, SIZE(bt));
info = backtrace_symbols(bt, count); info = backtrace_symbols(bt, count);
for (x = 0; x < count; x++) { for (x = 0; x < count; x++) {
copynchars(buf, info[x], (int) sizeof buf - 1); copynchars(temp, info[x], (int) sizeof temp - 1 - 1); // \n\0
/* try to remove up to 16 blank spaces by removing 8 twice */ /* try to remove up to 16 blank spaces by removing 8 twice */
(void) strsubst(buf, " ", ""); (void) strsubst(temp, " ", "");
(void) strsubst(buf, " ", ""); (void) strsubst(temp, " ", "");
snprintf(endp, SWR_FRAMES*80-(endp-wholetrace), "[%02lu] %s\n", strncat(temp, "\n", sizeof temp - 1);
(unsigned long) x, buf); # if 0 // __linux__
endp = eos(endp); // not needed for MacOS
// XXX is it actually needed for linux? TBD
snprintf(temp2, sizeof(temp2), "[%02lu]\n", (unsigned long) x);
uend--; // remove the \n we added above
SWR_ADD_URIcoded(temp2);
# endif // linux
SWR_ADD_URIcoded(temp);
mark=uend;
} }
*(endp-1) = '\0'; // remove last newline #endif // !WIN32
SWR_ADD(wholetrace); }
// detailrows min(actual,50) Guess since we can't know the #ifdef DUMPLOG
// config.h turns this on, but make it easy to turn off if needed
if(cos==1) {
int k;
SWR_ADD_URIcoded("Latest messages:\n");
mark=uend;
countpp++;
for(k=0;k<5;k++){
const char *line = get_saved_pline(k);
if(!line) break;
SWR_ADD_URIcoded(line);
SWR_ADD_URIcoded("\n");
countpp++;
mark=uend;
}
}
#endif
// detailrows: Guess since we can't know the
// width of the window. // width of the window.
SWR_ADD("detailrows"); SWR_ADD("&detailrows=");
(void)snprintf(nbuf,sizeof(nbuf),"%d",count+prelines); (void)snprintf(temp,sizeof(temp),"%d",min(count+countpp,30));
SWR_ADD(nbuf); SWR_ADD_URIcoded(temp);
xargv[xargc++] = 0; // terminate array
pid = fork(); full: ;
//printf("URL=%ld '%s'\n",strlen(url),url);
#ifdef WIN32
int *rv = win32_cr_shellexecute(url);
// XXX TESTING
printf("ShellExecute returned: %p\n",rv); // >32 is ok
#else
const char *xargv[] = {
CRASHREPORT,
url,
NULL
};
int pid = fork();
extern char **environ;
if (pid == 0) { if (pid == 0) {
#ifdef CRASHREPORT_EXEC_NOSTDERR
/* Keep the output clean - firefox spews useless errors on
* my system. */
(void)close(2);
(void)open("/dev/null", O_WRONLY);
#endif
execve(CRASHREPORT, (char * const *)xargv, environ); execve(CRASHREPORT, (char * const *)xargv, environ);
char err[100]; char err[100];
sprintf(err, "Can't start " CRASHREPORT ": %s", strerror(errno)); sprintf(err, "Can't start " CRASHREPORT ": %s", strerror(errno));
@@ -401,36 +582,45 @@ submit_web_report(const char *msg, char *why){
} else { } else {
int status; int status;
errno=0; errno=0;
// XXX do we _really_ know this is the right pid?
(void)waitpid(pid, &status, 0); (void)waitpid(pid, &status, 0);
if (status) { // XXX check could be more precise if (status) { // XXX check could be more precise
#if 0 #ifdef BETA
// Not useful at the moment. XXX // Not useful at the moment. XXX
char err[100]; char err[100];
sprintf(err, "pid=%d e=%d status=%0x",wpid,errno,status); sprintf(err, "pid=%d e=%d status=%0x",pid,errno,status);
raw_print(err); raw_print(err);
#endif #endif
return FALSE; return FALSE;
} }
} }
/* free(info); -- Don't risk it. */ /* free(info); -- Don't risk it. */
#endif
return TRUE; return TRUE;
}
return FALSE;
} }
int
dobugreport(void){
if(!submit_web_report(2, NULL, "#bugreport command")){
pline("Unable to send bug report. Please visit %s instead.",
sysopt.crashreporturl
? sysopt.crashreporturl
: "https://www.nethack.org"
);
}
return ECMD_OK;
}
#endif /* CRASHREPORT */ #endif /* CRASHREPORT */
#undef SWR_ADD #undef SWR_ADD
#undef SWR_ADD_URIcoded
#undef SWR_FRAMES #undef SWR_FRAMES
#undef SWR_HDR #undef SWR_HDR
#undef SWR_LINES #undef SWR_LINES
/*ARGSUSED*/ /*ARGSUSED*/
static boolean static boolean
NH_panictrace_libc(char *why UNUSED) NH_panictrace_libc(void)
{ {
#ifdef CRASHREPORT
if(submit_web_report("Panic",why)) return TRUE;
#endif
#ifdef PANICTRACE_LIBC #ifdef PANICTRACE_LIBC
void *bt[20]; void *bt[20];
@@ -459,13 +649,13 @@ NH_panictrace_libc(char *why UNUSED)
* fooVAR (possibly const) variable containing fooPATH * fooVAR (possibly const) variable containing fooPATH
*/ */
#ifdef PANICTRACE_GDB #ifdef PANICTRACE_GDB
#ifdef SYSCF # ifdef SYSCF
#define GDBVAR sysopt.gdbpath # define GDBVAR sysopt.gdbpath
#define GREPVAR sysopt.greppath # define GREPVAR sysopt.greppath
#else /* SYSCF */ # else /* SYSCF */
#define GDBVAR GDBPATH # define GDBVAR GDBPATH
#define GREPVAR GREPPATH # define GREPVAR GREPPATH
#endif /* SYSCF */ # endif /* SYSCF */
#endif /* PANICTRACE_GDB */ #endif /* PANICTRACE_GDB */
static boolean static boolean
@@ -878,7 +1068,7 @@ panic VA_DECL(const char *, str)
? "." ? "."
: "\nand it may be possible to rebuild."; : "\nand it may be possible to rebuild.";
// XXX this is probably wrong if defined(CRASHREPORT) // XXX this may need an update if defined(CRASHREPORT) TBD
if (sysopt.support) if (sysopt.support)
raw_printf("To report this error, %s%s", sysopt.support, raw_printf("To report this error, %s%s", sysopt.support,
maybe_rebuild); maybe_rebuild);
@@ -984,6 +1174,27 @@ dump_plines(void)
} }
} }
} }
// lineno==0 gives the most recent message (e.g. "Do you want to call panic..."
// if called from #panic)
static const char *
get_saved_pline(int lineno){
int p;
int limit = DUMPLOG_MSG_COUNT;
if(lineno >= DUMPLOG_MSG_COUNT) return NULL;
p = (gs.saved_pline_index-1) % DUMPLOG_MSG_COUNT;
while(limit--){
if(gs.saved_plines[p]){ // valid line
if(lineno--){
p = (p-1+DUMPLOG_MSG_COUNT) % DUMPLOG_MSG_COUNT;
} else {
return gs.saved_plines[p];
}
}
}
return NULL;
}
#endif #endif
/*ARGSUSED*/ /*ARGSUSED*/

View File

@@ -4736,6 +4736,9 @@ reveal_paths(void)
#endif /* ?UNIX */ #endif /* ?UNIX */
raw_print(""); raw_print("");
#if defined(WIN32) && !defined(WIN32CON)
wait_synch();
#endif
} }
/* ---------- BEGIN TRIBUTE ----------- */ /* ---------- BEGIN TRIBUTE ----------- */

View File

@@ -678,6 +678,12 @@ static const char *const build_opts[] = {
#endif #endif
#ifdef SYSCF #ifdef SYSCF
"system configuration at run-time", "system configuration at run-time",
#endif
#ifdef PANICTRACE
"show stack trace on error",
#endif
#ifdef CRASHREPORT
"launch browser to report issues",
#endif #endif
save_bones_compat_buf, save_bones_compat_buf,
"and basic NetHack features" "and basic NetHack features"

View File

@@ -522,7 +522,7 @@ parseoptions(
* determine_ambiguities() * determine_ambiguities()
* figured out exactly how many characters are required to * figured out exactly how many characters are required to
* unambiguously differentiate one option from all others, and it * unambiguously differentiate one option from all others, and it
* placed that number into each option's alloption[n].minmatch. * placed that number into each option's allopt[n].minmatch.
* *
*/ */
if (!got_match) if (!got_match)
@@ -1205,6 +1205,80 @@ optfn_catname(
return optn_ok; return optn_ok;
} }
static int
optfn_crash_email(int optidx UNUSED, int req, boolean negated UNUSED, char *opts, char *op)
{
if (req == do_init) {
return optn_ok;
}
if (req == do_set) {
if ((op = string_for_opt(opts, FALSE))
!= empty_optstr) {
gc.crash_email = dupstr(op);
} else
return optn_err;
return optn_ok;
}
if (req == get_val || req == get_cnf_val) {
if (!opts)
return optn_err;
Sprintf(opts, "%s", gc.crash_email);
return optn_ok;
}
return optn_ok;
}
static int
optfn_crash_name(int optidx UNUSED, int req, boolean negated UNUSED, char *opts, char *op)
{
if (req == do_init) {
return optn_ok;
}
if (req == do_set) {
if ((op = string_for_opt(opts, FALSE))
!= empty_optstr) {
gc.crash_name = dupstr(op);
} else
return optn_err;
return optn_ok;
}
if (req == get_val || req == get_cnf_val) {
if (!opts)
return optn_err;
Sprintf(opts, "%s", gc.crash_name);
return optn_ok;
}
return optn_ok;
}
static int
optfn_crash_urlmax(int optidx UNUSED, int req, boolean negated UNUSED, char *opts, char *op)
{
if (req == do_init) {
return optn_ok;
}
if (req == do_set) {
if ((op = string_for_opt(opts, FALSE))
!= empty_optstr) {
int temp = atoi(op);
if(temp < 75){
config_error_add("Invalid value %d for crash_urlmax. Minimum value is 75.",temp);
return optn_err;
}
gc.crash_urlmax = temp;
} else
return optn_err;
return optn_ok;
}
if (req == get_val || req == get_cnf_val) {
if (!opts)
return optn_err;
Sprintf(opts, "%d", gc.crash_urlmax);
return optn_ok;
}
return optn_ok;
}
#ifdef CURSES_GRAPHICS #ifdef CURSES_GRAPHICS
static int static int
optfn_cursesgraphics(int optidx, int req, boolean negated, optfn_cursesgraphics(int optidx, int req, boolean negated,
@@ -6694,8 +6768,6 @@ initoptions(void)
{ {
int i; int i;
go.opt_phase = builtin_opt;
initoptions_init();
/* /*
* Call each option function with an init flag and give it a chance * Call each option function with an init flag and give it a chance
* to make any preparations that it might require. We do this * to make any preparations that it might require. We do this
@@ -6740,6 +6812,7 @@ initoptions_init(void)
#endif #endif
int i; int i;
go.opt_phase = builtin_opt; // Did I need to move this here?
memcpy(allopt, allopt_init, sizeof(allopt)); memcpy(allopt, allopt_init, sizeof(allopt));
determine_ambiguities(); determine_ambiguities();

View File

@@ -537,7 +537,7 @@ impossible(const char *s, ...)
boolean report = ('y' == yn_function("Report now?","yn",'n',FALSE)); boolean report = ('y' == yn_function("Report now?","yn",'n',FALSE));
raw_print(""); // prove to the user the character was accepted raw_print(""); // prove to the user the character was accepted
if(report){ if(report){
submit_web_report("Impossible", pbuf); submit_web_report(1,"Impossible", pbuf);
} }
} }
#endif #endif

View File

@@ -112,7 +112,7 @@ LUA2NHTOP = ../../..
LUABASELIB = liblua-$(LUA_VERSION).a LUABASELIB = liblua-$(LUA_VERSION).a
TOPLUALIB = lib/lua/$(LUABASELIB) TOPLUALIB = lib/lua/$(LUABASELIB)
ALLDEP = $(GAME) recover Guidebook $(VARDAT) spec_levs check-dlb check-nhlua ALLDEP = $(GAME) recover Guidebook $(VARDAT) spec_levs check-dlb
# first target is also the default target for 'make' without any arguments # first target is also the default target for 'make' without any arguments
all: $(ALLDEP) all: $(ALLDEP)
@@ -148,10 +148,6 @@ luabin:
( cd $(LUATOP) \ ( cd $(LUATOP) \
&& make $(LUAMAKEFILES) all && cd $(LUA2NHTOP) ) && make $(LUAMAKEFILES) all && cd $(LUA2NHTOP) )
check-nhlua:
( util/makedefs --grep-defined CRASHREPORT && ( \
cd $(LUATOP) && make $(LUAMAKEFLAGS) ); true )
# hints file could set LUATESTTARGET to this if GITSUBMODULES is defined # hints file could set LUATESTTARGET to this if GITSUBMODULES is defined
submodules/lua/lua.h: submodules/lua/lua.h:
git submodule init submodules/lua git submodule init submodules/lua

View File

@@ -291,11 +291,7 @@ VARDIR = $(HACKDIR)
POSTINSTALL+= cp -n sys/unix/sysconf $(INSTDIR)/sysconf; \ POSTINSTALL+= cp -n sys/unix/sysconf $(INSTDIR)/sysconf; \
$(CHOWN) $(GAMEUID) $(INSTDIR)/sysconf; \ $(CHOWN) $(GAMEUID) $(INSTDIR)/sysconf; \
$(CHGRP) $(GAMEGRP) $(INSTDIR)/sysconf; \ $(CHGRP) $(GAMEGRP) $(INSTDIR)/sysconf; \
chmod $(VARFILEPERM) $(INSTDIR)/sysconf; \ chmod $(VARFILEPERM) $(INSTDIR)/sysconf;
( util/makedefs --grep-defined CRASHREPORT && \
( cp win/share/nhcrashreport.lua $(INSTDIR) ; \
chmod 555 $(INSTDIR)/nhcrashreport.lua ; \
cp $(LUATOP)/lua $(INSTDIR)/nhlua); true)
ifneq "$(CCISCLANG)" "" ifneq "$(CCISCLANG)" ""
# gdb may not be installed if clang is chosen compiler so the game # gdb may not be installed if clang is chosen compiler so the game

View File

@@ -31,6 +31,8 @@ ifndef LIBXPM
LIBXPM= -L/opt/X11/lib -lXpm LIBXPM= -L/opt/X11/lib -lXpm
endif endif
#WANT_WIN_CHAIN=1
# 4. Other # 4. Other
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
@@ -98,7 +100,7 @@ NHCFLAGS+=-DNOMAIL
#NHCFLAGS+=-DNO_CHRONICLE #NHCFLAGS+=-DNO_CHRONICLE
#NHCFLAGS+=-DLIVELOG #NHCFLAGS+=-DLIVELOG
# not NHCFLAGS - needed for makedefs # not NHCFLAGS - needed for makedefs
CFLAGS+=-DCRASHREPORT=\"NetHackCrashReport.JavaScript\" CFLAGS+=-DCRASHREPORT=\"/usr/bin/open\"
ifdef MAKEFILE_SRC ifdef MAKEFILE_SRC
# default # default
@@ -334,10 +336,7 @@ PREINSTALL= . sys/unix/hints/macosx.sh user2 $(GAMEUID); \
POSTINSTALL+= sys/unix/hints/macosx.sh editsysconf sys/unix/sysconf $(HACKDIR)/sysconf; \ POSTINSTALL+= sys/unix/hints/macosx.sh editsysconf sys/unix/sysconf $(HACKDIR)/sysconf; \
$(CHOWN) $(GAMEUID) $(HACKDIR)/sysconf; \ $(CHOWN) $(GAMEUID) $(HACKDIR)/sysconf; \
$(CHGRP) $(GAMEGRP) $(HACKDIR)/sysconf; \ $(CHGRP) $(GAMEGRP) $(HACKDIR)/sysconf; \
chmod $(VARFILEPERM) $(HACKDIR)/sysconf; \ chmod $(VARFILEPERM) $(HACKDIR)/sysconf;
util/makedefs --grep-defined CRASHREPORT && \
( cp win/macosx/NetHackCrashReport.JavaScript $(HACKDIR) && \
chmod 0500 $(HACKDIR)/NetHackCrashReport.JavaScript )
else ifdef WANT_SOURCE_INSTALL else ifdef WANT_SOURCE_INSTALL
@@ -353,10 +352,7 @@ CHGRP=/usr/bin/true
GAMEPERM = 0700 GAMEPERM = 0700
VARFILEPERM = 0600 VARFILEPERM = 0600
VARDIRPERM = 0700 VARDIRPERM = 0700
POSTINSTALL+= sys/unix/hints/macosx.sh editsysconf sys/unix/sysconf $(HACKDIR)/sysconf; \ POSTINSTALL+= sys/unix/hints/macosx.sh editsysconf sys/unix/sysconf $(HACKDIR)/sysconf;
util/makedefs --grep-defined CRASHREPORT && \
( cp win/macosx/NetHackCrashReport.JavaScript $(HACKDIR) && \
chmod 0500 $(HACKDIR)/NetHackCrashReport.JavaScript )
# We can use "make all" to build the whole thing - but it misses some things: # We can use "make all" to build the whole thing - but it misses some things:
MOREALL=$(MAKE) install MOREALL=$(MAKE) install
@@ -385,10 +381,7 @@ PREINSTALL+= (mkdir $(SHELLDIR) || true);
POSTINSTALL+= sys/unix/hints/macosx.sh editsysconf sys/unix/sysconf $(HACKDIR)/sysconf; \ POSTINSTALL+= sys/unix/hints/macosx.sh editsysconf sys/unix/sysconf $(HACKDIR)/sysconf; \
$(CHOWN) $(GAMEUID) $(HACKDIR)/sysconf; \ $(CHOWN) $(GAMEUID) $(HACKDIR)/sysconf; \
$(CHGRP) $(GAMEGRP) $(HACKDIR)/sysconf; \ $(CHGRP) $(GAMEGRP) $(HACKDIR)/sysconf; \
chmod $(VARFILEPERM) $(HACKDIR)/sysconf; \ chmod $(VARFILEPERM) $(HACKDIR)/sysconf;
util/makedefs --grep-defined CRASHREPORT && \
( cp win/macosx/NetHackCrashReport.JavaScript $(HACKDIR) && \
chmod 0500 $(HACKDIR)/NetHackCrashReport.JavaScript )
endif # !WANT_SHARE_INSTALL endif # !WANT_SHARE_INSTALL
@@ -731,7 +724,6 @@ build_package_root:
install -p doc/recover.6 $(PKGROOT_UG)/man/man6 install -p doc/recover.6 $(PKGROOT_UG)/man/man6
install -p doc/Guidebook $(PKGROOT_UG)/doc install -p doc/Guidebook $(PKGROOT_UG)/doc
install -p dat/nhdat $(PKGROOT_UGLN) install -p dat/nhdat $(PKGROOT_UGLN)
#XXX no code to package NetHackCrashReport.JavaScript
sys/unix/hints/macosx.sh editsysconf sys/unix/sysconf $(PKGROOT_UGLN)/sysconf sys/unix/hints/macosx.sh editsysconf sys/unix/sysconf $(PKGROOT_UGLN)/sysconf
cd dat; install -p $(DATNODLB) ../$(PKGROOT_UGLN) cd dat; install -p $(DATNODLB) ../$(PKGROOT_UGLN)
# XXX these files should be somewhere else for good Mac form # XXX these files should be somewhere else for good Mac form

View File

@@ -159,6 +159,9 @@ GREPPATH=/bin/grep
PANICTRACE_GDB=1 PANICTRACE_GDB=1
PANICTRACE_LIBC=2 PANICTRACE_LIBC=2
# URL loaded for creating reports to the NetHack DevTeam
#CRASHREPORTURL=https://nethack.org/links/cr-37BETA.html
# 'portable_device_paths' is only supported for Windows. Starting with # 'portable_device_paths' is only supported for Windows. Starting with
# 3.6.3, nethack on Windows treats the folder containing nethack.exe and # 3.6.3, nethack on Windows treats the folder containing nethack.exe and
# nethackW.exe as read-only and puts data files which are generated or # nethackW.exe as read-only and puts data files which are generated or

View File

@@ -151,6 +151,7 @@ main(int argc, char *argv[])
check_linux_console(); check_linux_console();
#endif #endif
initoptions_init();
initoptions(); initoptions();
#ifdef PANICTRACE #ifdef PANICTRACE
ARGV0 = gh.hname; /* save for possible stack trace */ ARGV0 = gh.hname; /* save for possible stack trace */
@@ -766,6 +767,7 @@ opt_showpaths(const char *dir)
nhUse(dir); nhUse(dir);
#endif #endif
iflags.initoptions_noterminate = TRUE; iflags.initoptions_noterminate = TRUE;
initoptions_init();
initoptions(); initoptions();
iflags.initoptions_noterminate = FALSE; iflags.initoptions_noterminate = FALSE;
reveal_paths(); reveal_paths();

View File

@@ -233,3 +233,7 @@ OPTIONS=hilite_status:gold/up/yellow/down/brown
# St, Dx, Co, In, Wi, Ch # St, Dx, Co, In, Wi, Ch
OPTIONS=hilite_status:characteristics/up/green/down/red OPTIONS=hilite_status:characteristics/up/green/down/red
# CRASHREPORTURL must be set in syscf to enable these options.
# These identify you in crash reports
#OPTIONS=crash_name:Your Name
#OPTIONS=crash_email:user@example.com

View File

@@ -52,9 +52,10 @@ SOUND_LIBRARIES = windsound
# #
#--------------------------------------------------------------- #---------------------------------------------------------------
# Do you want debug information in the executable? # Do you want debug information in the executable?
# Required for CRASHREPORT.
# #
DEBUGINFO = N DEBUGINFO = Y
# #
#--------------------------------------------------------------- #---------------------------------------------------------------
@@ -243,6 +244,7 @@ NHV=$(subst ",,$(NHV1))
# TTY - window port files (tty) # TTY - window port files (tty)
# MSWIN - window port files (win32) # MSWIN - window port files (win32)
# WCURSES - window port files (curses) # WCURSES - window port files (curses)
# WCHAIN - window port files (chain)
# WSHR - Tile support files # WSHR - Tile support files
# SNDSYS - sound suppport files for win32 # SNDSYS - sound suppport files for win32
# QT - QT window support files # QT - QT window support files
@@ -257,6 +259,7 @@ SNDSYS =../sound/windsound
MSWSYS =../sys/windows MSWSYS =../sys/windows
TTY =../win/tty TTY =../win/tty
MSWIN =../win/win32 MSWIN =../win/win32
WCHAIN =../win/chain
WCURSES =../win/curses WCURSES =../win/curses
WSHR =../win/share WSHR =../win/share
QT =../win/Qt QT =../win/Qt
@@ -357,7 +360,7 @@ $(OBJ):
CLEAN_DIR = $(GAMEDIR) $(OBJ) CLEAN_DIR = $(GAMEDIR) $(OBJ)
#===============-================================================= #=================================================================
# LUA library # LUA library
# Source from http://www.lua.org/ftp/lua-5.4.6.tar.gz # Source from http://www.lua.org/ftp/lua-5.4.6.tar.gz
#================================================================= #=================================================================
@@ -987,6 +990,15 @@ CFLAGSW += $(NHCURSESFLAGS)
NHWONLY += $(addsuffix .o, cursdial cursinit cursinvt cursmain cursmesg cursmisc cursstat curswins guitty) NHWONLY += $(addsuffix .o, cursdial cursinit cursinvt cursmain cursmesg cursmisc cursstat curswins guitty)
endif endif
# uncomment for WINCHAIN
#COREOBJS += $(addsuffix .o, wc_chainin wc_chainout wc_trace)
# XXX mess for testing libbacktrace
ifeq "$(DEBUGINFO)" "Y"
CFLAGS += -I/mingw64/include -g -static -gdwarf
LIBS += -L/mingw64/lib -lbacktrace
endif
nethackw: $(NHWTARGETS) nethackw: $(NHWTARGETS)
$(GAMEDIR)/NetHackW.exe: $(NHWOBJS) $(NHWRES) $(DATEW_O) $(LUALIB) $(PDCWLIB) | $(GAMEDIR) $(GAMEDIR)/NetHackW.exe: $(NHWOBJS) $(NHWRES) $(DATEW_O) $(LUALIB) $(PDCWLIB) | $(GAMEDIR)
@@ -1028,6 +1040,9 @@ $(ONHW)/%.o: $(MSWSYS)/%.c $(NHLUAH) | $(ONHW)
$(ONHW)/%.o: $(MSWIN)/%.c $(NHLUAH) | $(ONHW) $(ONHW)/%.o: $(MSWIN)/%.c $(NHLUAH) | $(ONHW)
$(cc) $(CFLAGSW) $< -o$@ $(cc) $(CFLAGSW) $< -o$@
$(ONHW)/%.o: $(WCHAIN)/%.c $(NHLUAH) | $(ONHW)
$(cc) $(CFLAGSW) $< -o$@
$(ONHW)/%.o: $(WSHR)/%.c $(NHLUAH) | $(ONHW) $(ONHW)/%.o: $(WSHR)/%.c $(NHLUAH) | $(ONHW)
$(cc) $(CFLAGSW) $< -o$@ $(cc) $(CFLAGSW) $< -o$@
@@ -1068,6 +1083,7 @@ NHCURSESFLAGS = -DCURSES_GRAPHICS -DCURSES_UNICODE $(PDCURSESFLAGS) -DPDC_NCMOUS
CFLAGSNH += $(NHCURSESFLAGS) CFLAGSNH += $(NHCURSESFLAGS)
NHONLY += $(addsuffix .o, cursdial cursinit cursinvt cursmain cursmesg cursmisc cursstat curswins) NHONLY += $(addsuffix .o, cursdial cursinit cursinvt cursmain cursmesg cursmisc cursstat curswins)
endif endif
DATE_O = $(addsuffix .o, $(addprefix $(ONH)/, date)) DATE_O = $(addsuffix .o, $(addprefix $(ONH)/, date))
NHOBJS = $(addprefix $(ONH)/, $(COREOBJS) $(NHONLY)) NHOBJS = $(addprefix $(ONH)/, $(COREOBJS) $(NHONLY))
@@ -1115,6 +1131,9 @@ $(ONH)/%.o: $(MSWSYS)/%.c $(NHLUAH) | $(ONH)
$(ONH)/%.o: $(MSWIN)/%.c $(NHLUAH) | $(ONH) $(ONH)/%.o: $(MSWIN)/%.c $(NHLUAH) | $(ONH)
$(cc) $(CFLAGSNH) $< -o$@ $(cc) $(CFLAGSNH) $< -o$@
$(ONH)/%.o: $(WCHAIN)/%.c $(NHLUAH) | $(ONH)
$(cc) $(CFLAGSNH) $< -o$@
$(ONH)/%.o: $(WSHR)/%.c $(NHLUAH) | $(ONH) $(ONH)/%.o: $(WSHR)/%.c $(NHLUAH) | $(ONH)
$(cc) $(CFLAGSNH) $< -o$@ $(cc) $(CFLAGSNH) $< -o$@
@@ -1148,8 +1167,9 @@ CLEAN_FILE += $(NHTARGET) $(NHOBJS) $(NHRES)
all: install all: install
TO_INSTALL = $(GAMEDIR)/NetHack.exe $(RTARGETS) $(GAMEDIRDLLS) \ TO_INSTALL = $(GAMEDIR)/NetHack.exe $(RTARGETS) $(GAMEDIRDLLS) \
$(addprefix $(GAMEDIR)/, $(addsuffix .template, sysconf .nethackrc) \ $(addprefix $(GAMEDIR)/, \
Guidebook.txt NetHack.txt license opthelp record symbols) $(addsuffix .template, sysconf .nethackrc symbols) \
Guidebook.txt NetHack.txt license opthelp record)
ifeq "$(HAVE_SOUNDLIB)" "Y" ifeq "$(HAVE_SOUNDLIB)" "Y"
TO_INSTALL += $(addprefix $(GAMEDIR)/, $(addsuffix .wav, $(WAVLIST))) TO_INSTALL += $(addprefix $(GAMEDIR)/, $(addsuffix .wav, $(WAVLIST)))
@@ -1183,7 +1203,7 @@ $(GAMEDIR)/$(FMODLIBDLL): $(FMODLIBDIR)/$(FMODLIBDLL)
cp $< $@ cp $< $@
endif endif
$(GAMEDIR)/symbols: $(DAT)/symbols $(GAMEDIR)/symbols.template: $(DAT)/symbols
cp $< $@ cp $< $@
$(GAMEDIR)/NetHack.txt: $(DOC)/nethack.txt $(GAMEDIR)/NetHack.txt: $(DOC)/nethack.txt

View File

@@ -121,3 +121,6 @@ HIDEUSAGE=1
# #
# The location that file synchronization locks are stored (writeable) # The location that file synchronization locks are stored (writeable)
#LOCKDIR=c:\ProgramData\NetHack\3.7 #LOCKDIR=c:\ProgramData\NetHack\3.7
# URL loaded for creating reports to the NetHack DevTeam
#CRASHREPORTURL=https://nethack.org/links/cr-37BETA.html

View File

@@ -49,7 +49,7 @@
<PreprocessorDefinitions>WIN32CON;NO_TILE_C;DLB;SAFEPROCS;SND_LIB_WINDSOUND;USER_SOUNDS;_LIB;HAS_STDINT_H;%(PreprocessorDefinitions)</PreprocessorDefinitions> <PreprocessorDefinitions>WIN32CON;NO_TILE_C;DLB;SAFEPROCS;SND_LIB_WINDSOUND;USER_SOUNDS;_LIB;HAS_STDINT_H;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile> </ClCompile>
<Link> <Link>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;winmm.lib;Winmm.lib;bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>kernel32.lib;dbghelp.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;winmm.lib;Winmm.lib;bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
<ResourceCompile> <ResourceCompile>
<AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SndWavDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <AdditionalIncludeDirectories Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SndWavDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
@@ -297,4 +297,4 @@
<Target Name="AfterRebuild"> <Target Name="AfterRebuild">
<MSBuild Projects="afternethack.proj" Targets="Build" Properties="Configuration=$(Configuration)" /> <MSBuild Projects="afternethack.proj" Targets="Build" Properties="Configuration=$(Configuration)" />
</Target> </Target>
</Project> </Project>

View File

@@ -62,7 +62,7 @@
</ResourceCompile> </ResourceCompile>
<Link> <Link>
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
<AdditionalDependencies>comctl32.lib;winmm.lib;bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>dbghelp.lib;comctl32.lib;winmm.lib;bcrypt.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
<Manifest> <Manifest>
<AdditionalManifestFiles>$(WinWin32Dir)NethackW.exe.manifest;%(AdditionalManifestFiles)</AdditionalManifestFiles> <AdditionalManifestFiles>$(WinWin32Dir)NethackW.exe.manifest;%(AdditionalManifestFiles)</AdditionalManifestFiles>
@@ -351,4 +351,4 @@
<Target Name="AfterRebuild"> <Target Name="AfterRebuild">
<MSBuild Projects="$(vsDir)NetHack\afternethack.proj" Targets="Build" Properties="Configuration=$(Configuration)" /> <MSBuild Projects="$(vsDir)NetHack\afternethack.proj" Targets="Build" Properties="Configuration=$(Configuration)" />
</Target> </Target>
</Project> </Project>

View File

@@ -545,7 +545,7 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/
if (getcwd(orgdir, sizeof orgdir) == (char *) 0) if (getcwd(orgdir, sizeof orgdir) == (char *) 0)
error("NetHack: current directory path too long"); error("NetHack: current directory path too long");
#endif #endif
initoptions_init(); // This allows OPTIONS in syscf on Windows.
set_default_prefix_locations(argv[0]); set_default_prefix_locations(argv[0]);
#if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) #if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS)
@@ -638,6 +638,9 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/
if (WINDOWPORT(tty)) if (WINDOWPORT(tty))
consoletty_open(1); consoletty_open(1);
#endif #endif
#ifdef WINCHAIN
commit_windowchain();
#endif
init_nhwindows(&argc, argv); init_nhwindows(&argc, argv);
@@ -812,6 +815,11 @@ process_options(int argc, char * argv[])
argc--; argc--;
argv++; argv++;
} }
#if defined(CRASHREPORT)
if (argcheck(argc, argv, ARG_BIDSHOW) == 2) {
nethack_exit(EXIT_SUCCESS);
}
#endif
if (argc > 1 && !strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') { if (argc > 1 && !strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') {
/* avoid matching "-dec" for DECgraphics; since the man page /* avoid matching "-dec" for DECgraphics; since the man page
* says -d directory, hope nobody's using -desomething_else * says -d directory, hope nobody's using -desomething_else

View File

@@ -24,7 +24,10 @@
#ifdef TTY_GRAPHICS #ifdef TTY_GRAPHICS
#include "wintty.h" #include "wintty.h"
#endif #endif
#include <inttypes.h>
#ifdef WIN32 #ifdef WIN32
#include <VersionHelpers.h>
/* /*
* The following WIN32 API routines are used in this file. * The following WIN32 API routines are used in this file.
@@ -758,6 +761,281 @@ nt_assert_failed(const char *expression, const char *filepath, int line)
expression, filename, line); expression, filename, line);
} }
/* Windows helpers for CRASHREPORT etc */
#ifdef CRASHREPORT
struct CRctxt {
BCRYPT_ALG_HANDLE bah;
BCRYPT_HASH_HANDLE bhh;
PBYTE pbhashobj;
DWORD cbhashobj; /* temp */
DWORD cbhash; /* hash length */
DWORD cbdata; /* temp */
PBYTE pbhash; /* binary hash */
NTSTATUS st;
} ctxp_ = { NULL, NULL, NULL, 0, 0, 0, NULL, 0 };
struct CRctxt *ctxp = &ctxp_; // XXX should this now be in gc.* ?
#define win32err(fn) errname = fn; goto error
int
win32_cr_helper(char cmd, struct CRctxt *ctxp, void *p, int d){
char *errname = "unknown";
switch (cmd) {
default:
/* Not panic - we don't want to upgrade an impossible to a
* panic due to a bug in the CRASHREPORT code. */
impossible("win_cr_helper bad cmd %d", cmd);
return 1;
case 'D': {
char *bidstr = (char *) p;
wchar_t lbidstr[40]; // sizeof(bid), but const
swprintf_s(lbidstr, 40, L"%S", bidstr);
// XXX TODO: need something that will allow copy of just the bid
return MessageBoxW(NULL, lbidstr, L"bidshow", MB_SETFOREGROUND);
}
break;
case 'i': /* HASH_INIT(ctxp) */
if (!IsWindowsVistaOrGreater())
return 1; // CNG not available.
ctxp->bah = NULL;
ctxp->bhh = NULL;
ctxp->pbhashobj = NULL;
ctxp->cbhashobj = 0;
ctxp->cbhash = 0;
ctxp->cbdata = 0;
ctxp->pbhash = NULL;
ctxp->st = 0;
// win32err("test"); // TESTING - FAKE AN ERROR
if (0 > (ctxp->st = BCryptOpenAlgorithmProvider(
&ctxp->bah, BCRYPT_MD4_ALGORITHM, NULL, 0))) {
win32err("BCryptOpenAlgorithmProvider");
};
if (0 > (ctxp->st =
BCryptGetProperty(ctxp->bah, BCRYPT_OBJECT_LENGTH,
(unsigned char *) &ctxp->cbhashobj,
sizeof(DWORD), &ctxp->cbdata, 0))) {
win32err("BCryptGetProperty1");
};
if (0
== (ctxp->pbhashobj =
HeapAlloc(GetProcessHeap(), 0, ctxp->cbhashobj))) {
win32err("HeapAlloc1");
};
if (0 > (ctxp->st = BCryptGetProperty(
ctxp->bah, BCRYPT_HASH_LENGTH, (PBYTE) &ctxp->cbhash,
sizeof(DWORD), &ctxp->cbdata, 0))) {
win32err("BCryptGetProperty2");
}
if (0
== (ctxp->pbhash =
HeapAlloc(GetProcessHeap(), 0, ctxp->cbhash))) {
win32err("HeapAlloc2\n");
}
if (0 > BCryptCreateHash(ctxp->bah, &ctxp->bhh, ctxp->pbhashobj,
ctxp->cbhashobj, NULL, 0, 0)) {
win32err("BCryptCreateHash");
}
break;
case 'u': /* HASH_UPDATE(ctxp, ptr, len) */
if (0 > (ctxp->st = BCryptHashData(ctxp->bhh, p, d, 0))) {
win32err("BCryptHashData");
}
break;
case 'f': /* HASH_FINISH(ctxp) */
if (0 > BCryptFinishHash(ctxp->bhh, ctxp->pbhash, ctxp->cbhash, 0)) {
win32err("BCryptFinishHash");
}
break;
case 'c': /* HASH_CLEANUP(ctxp) */
if (ctxp->bah) {
BCryptCloseAlgorithmProvider(ctxp->bah, 0);
}
if (ctxp->bhh) {
BCryptDestroyHash(ctxp->bhh);
}
if (ctxp->pbhashobj) {
HeapFree(GetProcessHeap(), 0, ctxp->pbhashobj);
}
if (ctxp->pbhash) {
HeapFree(GetProcessHeap(), 0, ctxp->pbhash);
}
break;
case 's': /* HASH_RESULT_SIZE(ctxp) */
return ctxp->cbhash;
case 'r': /* HASH_RESULT(ctxp, resp) */
*(unsigned char **)p = ctxp->pbhash;
break;
case 'b': /* HASH_BINFILE(NULL,&binfile,0) */
// XXX This buffer should be allocated, not static (and freed in
// HASH_CLEANUP).
// NB: assumes !longPathAware in manifest (Win10+)
{
static char binfile[MAX_PATH];
DWORD rv = GetModuleFileNameA(NULL, binfile, sizeof(binfile));
if (rv == 0 || rv == sizeof(binfile))
return 1;
#ifdef BETA
printf("FILE '%s'\n", binfile);
#endif
*(unsigned char **) p = (unsigned char *) binfile;
return 0;
}
}
return 0; /* ok */
error:
raw_printf("WIN32 function %s failed: status=%" PRIx64 "\n",
errname, (uint64)ctxp->st);
return 1; /* fail */
}
#undef win32err
#include <shellapi.h>
#define MAX_SYM_SIZE 100
#ifdef __GNUC__
// gcc can't generate .pdb files. llvm can almost do it.
// For these platforms, use github/ianlancetaylor/libbacktrace.
// XXX this doesn't work yet - we get correct addresses but no symbol info
// XXX so still needs cleanup
// XXX no mark (overflow held to last valid segment) handling yet
#include <backtrace.h>
struct userstate {
int error_count;
int good_count;
char *out;
int outsize;
int maxframes;
} userstate;
//backtrace_full_callback
static int
btfcb_fn(void *us0, uintptr_t pc, const char *filename,
int lineno, const char *fnname){
struct userstate *us = us0;
//XXX generate a stack frame line
printf("C: pc=%llx f=%s line=%d fn=%s\n",pc,filename,lineno,fnname);
us->good_count++;
return 0;
}
//backtrace_error_callback
static void
btecb_fn(void *us0, const char *msg, int errnum){
struct userstate *us = us0;
us->error_count++;
if(errnum < 0){
printf("E1: M=%s e=%d\n",msg,errnum);
// XXX save error message
} else {
printf("E2: M=%s e=%d\n",msg,errnum);
// errnum is an errno
//XXX save error message with strerror
}
}
int
win32_cr_gettrace(int maxframes, char *out, int outsize){
userstate.error_count = 0;
userstate.good_count = 0;
userstate.out = out;
userstate.outsize = outsize;
userstate.maxframes = maxframes;
static char binfile[MAX_PATH];// assumes !longPathAware in manifest (Win10+)
DWORD rv = GetModuleFileNameA(NULL, binfile, sizeof(binfile));
struct backtrace_state *state
= backtrace_create_state(binfile, 0, btecb_fn, &userstate);
if(!state) return userstate.error_count + userstate.good_count;
rv=backtrace_full(state, 0, btfcb_fn, btecb_fn, &userstate);
printf("rv=%d\n",rv);
// XXX rv not checked
// XXX this API leaks its memory; there is no free function
return userstate.error_count + userstate.good_count;
}
#else
// Use win32 API with Visual Studio (and probably MSVC).
#include <dbghelp.h>
int
win32_cr_gettrace(int maxframes, char *out, int outsize){
char *mark = out;
void *frames[200]; // XXX why does VS fail var array? wrong C std?
int x;
int tmp;
#define BSIZE (MAX_SYM_SIZE+50)
char buf[BSIZE];
HANDLE me = GetCurrentProcess();
SetLastError(0);
// XXX may need to pass the binary's dir
//XXX check for different flags
if(!SymInitialize(me, NULL, TRUE)){
snprintf(buf, BSIZE, "no stack trace: SymInitialize: %d\n",
GetLastError());
return 1;
}
int fcount = CaptureStackBackTrace(0, maxframes,frames,NULL);
if(!fcount)goto finish;
char symbol_info_space[sizeof(SYMBOL_INFO)+MAX_SYM_SIZE];
SYMBOL_INFO *si = (SYMBOL_INFO *)symbol_info_space;
si->MaxNameLen = MAX_SYM_SIZE;
si->SizeOfStruct = sizeof(SYMBOL_INFO);
for(x=0;x<fcount;x++){
DWORD64 disp64 =0 ;
DWORD64 adr = (DWORD64)(frames[x]);
if(!adr) break;
if(SymFromAddr(me, adr, &disp64, si)){
//printf("A %x\n",GetLastError());fflush(stdout);
tmp = snprintf(buf, BSIZE, "%d %p %s+%lld\n",
x, frames[x], &si->Name[0], (long long int)disp64);
if(swr_add_uricoded(buf, &out, &outsize, mark))
goto finish;
#if 1
// XXX does this block do anything useful?
DWORD disp = (DWORD) disp64;
IMAGEHLP_LINE ihl;
ihl.SizeOfStruct = sizeof(IMAGEHLP_LINE);
if (SymGetLineFromAddr(me, adr, &disp, &ihl)) {
printf("L=%d\n", ihl.LineNumber);
} else {
// 7e/1e7 - no info. May need to call SymLoadModule if we need those addrs
// BUT probably system code, so we don't care - experiment
// printf("SGLFA failed: $%08x\n", GetLastError());
}
//XXXnow format the line
#endif
} else {
// Error 487 (invalid address) seems to mean
// "I can't find any info for this address".
tmp = snprintf(buf, BSIZE, "%d %p (error %d)\n",
x, frames[x], GetLastError());
if(swr_add_uricoded(buf, &out, &outsize, mark))
goto finish;
}
if(tmp < 0 || tmp >= outsize){ // XXX is test now wrong?
//printf("FAIL tmp=%d\n",tmp);
fcount = x+1;
goto finish;
}
mark = out;
}
finish:
SymCleanup(me);
return fcount; // XXX if output truncated, fcount could be wrong
}
#endif
int *
win32_cr_shellexecute(const char *url){
//XXX Docs say to do this, but has so many caveats I'm going to try skipping it.
//CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
int *rv = (int*)ShellExecuteA(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL);
return rv;
}
#endif /* CRASHREPORT */
#endif /* WIN32 */ #endif /* WIN32 */
/*windsys.c*/ /*windsys.c*/

View File

@@ -84,3 +84,8 @@ OPTIONS=catname:Ghisteslwchlohm
# 048 035 064 042 \ # 048 035 064 042 \
# 047 045 092 124 124 092 045 047 \ # 047 045 092 124 124 092 045 047 \
# 047 064 092 064 064 064 092 064 047 # 047 064 092 064 064 064 092 064 047
# CRASHREPORTURL must be set in syscf to enable these options.
# These identify you in crash reports
#OPTIONS=crash_name:Your Name
#OPTIONS=crash_email:user@example.com

View File

@@ -108,7 +108,7 @@ chainin_procs_chain(
tdp->nprocs = 0; tdp->nprocs = 0;
tdp->ndata = 0; tdp->ndata = 0;
tdp->linknum = n; tdp->linknum = n;
cibase = 0; cibase = tdp;
break; break;
case WINCHAIN_INIT: case WINCHAIN_INIT:
tdp = me; tdp = me;
@@ -584,7 +584,7 @@ chainin_ctrl_nhwindow(
int request, int request,
win_request_info *wri) win_request_info *wri)
{ {
boolean rv; win_request_info *rv;
rv = (*cibase->nprocs->win_ctrl_nhwindow)(cibase->ndata, window, rv = (*cibase->nprocs->win_ctrl_nhwindow)(cibase->ndata, window,
request, wri); request, wri);
@@ -609,7 +609,7 @@ struct window_procs chainin_procs = {
chainin_display_nhwindow, chainin_destroy_nhwindow, chainin_curs, chainin_display_nhwindow, chainin_destroy_nhwindow, chainin_curs,
chainin_putstr, chainin_putmixed, chainin_display_file, chainin_putstr, chainin_putmixed, chainin_display_file,
chainin_start_menu, chainin_add_menu, chainin_end_menu, chainin_start_menu, chainin_add_menu, chainin_end_menu,
chainin_select_menu, chainin_message_menu, chainin_update_inventory, chainin_select_menu, chainin_message_menu,
chainin_mark_synch, chainin_wait_synch, chainin_mark_synch, chainin_wait_synch,
#ifdef CLIPPING #ifdef CLIPPING
chainin_cliparound, chainin_cliparound,

View File

@@ -702,12 +702,13 @@ chainout_can_suspend(void *vp)
win_request_info * win_request_info *
chainout_ctrl_nhwindow( chainout_ctrl_nhwindow(
void *vp,
winid window, winid window,
int request, int request,
win_request_info *wri) win_request_info *wri)
{ {
struct chainout_data *tdp = vp; struct chainout_data *tdp = vp;
boolean rv; win_request_info *rv;
rv = (*tdp->nprocs->win_ctrl_nhwindow)(window, rv = (*tdp->nprocs->win_ctrl_nhwindow)(window,
request, wri); request, wri);
@@ -733,7 +734,8 @@ struct chain_procs chainout_procs = {
chainout_destroy_nhwindow, chainout_curs, chainout_putstr, chainout_destroy_nhwindow, chainout_curs, chainout_putstr,
chainout_putmixed, chainout_display_file, chainout_start_menu, chainout_putmixed, chainout_display_file, chainout_start_menu,
chainout_add_menu, chainout_end_menu, chainout_select_menu, chainout_add_menu, chainout_end_menu, chainout_select_menu,
chainout_message_menu, chainout_update_inventory, chainout_mark_synch, chainout_message_menu,
chainout_mark_synch,
chainout_wait_synch, chainout_wait_synch,
#ifdef CLIPPING #ifdef CLIPPING
chainout_cliparound, chainout_cliparound,

View File

@@ -9,8 +9,15 @@
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
FILE *wc_tracelogf; /* Should be static, but it's just too useful to have #ifdef WIN32
* access to this logfile from arbitrary other files. */ long getpid(void);
long
getpid(){
return 0;
}
#endif
FILE *wc_tracelogf;
static unsigned int indent_level; /* Some winfuncs call other winfuncs, so static unsigned int indent_level; /* Some winfuncs call other winfuncs, so
* we need to support nesting. */ * we need to support nesting. */
@@ -55,7 +62,6 @@ void trace_add_menu(void *,winid, const glyph_info *, const ANY_P *,
void trace_end_menu(void *,winid, const char *); void trace_end_menu(void *,winid, const char *);
int trace_select_menu(void *,winid, int, MENU_ITEM_P **); int trace_select_menu(void *,winid, int, MENU_ITEM_P **);
char trace_message_menu(void *,char, int, const char *); char trace_message_menu(void *,char, int, const char *);
void trace_update_inventory(void *,int);
void trace_mark_synch(void *); void trace_mark_synch(void *);
void trace_wait_synch(void *); void trace_wait_synch(void *);
#ifdef CLIPPING #ifdef CLIPPING
@@ -101,6 +107,8 @@ void trace_status_update(void *,int, genericptr_t, int, int, int,
unsigned long *); unsigned long *);
boolean trace_can_suspend(void *); boolean trace_can_suspend(void *);
void trace_update_inventory(void *,int);
win_request_info *trace_ctrl_nhwindow(void *, winid, int, win_request_info *);
void trace_procs_init(int dir); void trace_procs_init(int dir);
void *trace_procs_chain(int cmd, int n, void *me, void *nextprocs, void *nextdata); void *trace_procs_chain(int cmd, int n, void *me, void *nextprocs, void *nextdata);
@@ -144,7 +152,7 @@ trace_procs_chain(
void void
trace_procs_init(int dir) trace_procs_init(int dir)
{ {
char fname[200]; char tfile[20];
long pid; long pid;
/* processors shouldn't need this test, but just in case */ /* processors shouldn't need this test, but just in case */
@@ -152,8 +160,14 @@ trace_procs_init(int dir)
return; return;
pid = (long) getpid(); pid = (long) getpid();
Sprintf(fname, "%s/tlog.%ld", HACKDIR, pid);
Sprintf(tfile, "tlog.%ld", pid);
// XXX FQN_NUMBUF is private to files.c
const char *fname = fqname(tfile, TROUBLEPREFIX,7);
printf("TRACEFILE: %s\n",fname);
fflush(stdout);
wc_tracelogf = fopen(fname, "w"); wc_tracelogf = fopen(fname, "w");
(void)setvbuf(wc_tracelogf, NULL, _IONBF, 0);
if (!wc_tracelogf) { if (!wc_tracelogf) {
fprintf(stderr, "Can't open trace log file %s: %s\n", fname, fprintf(stderr, "Can't open trace log file %s: %s\n", fname,
strerror(errno)); strerror(errno));
@@ -578,6 +592,16 @@ trace_update_inventory(void *vp, int arg)
POST; POST;
} }
win_request_info *
trace_ctrl_nhwindow(void *vp, winid w, int request, win_request_info *wri){
struct trace_data *tdp = vp;
fprintf(wc_tracelogf, "%sctrl_nhwindow(%d, %d, %p)\n", INDENT, w, request, wri);
PRE;
(*tdp->nprocs->win_ctrl_nhwindow)(tdp->ndata, w, request, wri);
POST;
}
void void
trace_mark_synch(void *vp) trace_mark_synch(void *vp)
{ {
@@ -1186,7 +1210,8 @@ trace_can_suspend(void *vp)
} }
struct chain_procs trace_procs = { struct chain_procs trace_procs = {
"+trace", 0, /* wincap */ "+trace", wp_trace,
0, /* wincap */
0, /* wincap2 */ 0, /* wincap2 */
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, /* color availability */
/* /*
@@ -1202,7 +1227,7 @@ struct chain_procs trace_procs = {
trace_create_nhwindow, trace_clear_nhwindow, trace_display_nhwindow, trace_create_nhwindow, trace_clear_nhwindow, trace_display_nhwindow,
trace_destroy_nhwindow, trace_curs, trace_putstr, trace_putmixed, trace_destroy_nhwindow, trace_curs, trace_putstr, trace_putmixed,
trace_display_file, trace_start_menu, trace_add_menu, trace_end_menu, trace_display_file, trace_start_menu, trace_add_menu, trace_end_menu,
trace_select_menu, trace_message_menu, trace_update_inventory, trace_select_menu, trace_message_menu,
trace_mark_synch, trace_wait_synch, trace_mark_synch, trace_wait_synch,
#ifdef CLIPPING #ifdef CLIPPING
trace_cliparound, trace_cliparound,
@@ -1228,4 +1253,6 @@ struct chain_procs trace_procs = {
trace_status_init, trace_status_finish, trace_status_enablefield, trace_status_init, trace_status_finish, trace_status_enablefield,
trace_status_update, trace_status_update,
trace_can_suspend, trace_can_suspend,
trace_update_inventory,
trace_ctrl_nhwindow
}; };

View File

@@ -1,28 +0,0 @@
#!/usr/bin/osascript -l JavaScript
// NetHack 3.7 tile.h $NHDT-Date: 1693083762 2023/08/26 21:02:42 $ $NHDT-Branch: keni-crashweb2 $:$NHDT-Revision: 1.1 $
// Copyright (c) 2023 Kenneth Lorber
// NetHack may be freely redistributed. See license for details.
// Call with URL then field value pairs. Opens a new browser window
// to: URL?field=value+field=value.....
// This program encodes the values; fieldnames don't require encoding.
// Should be installed in the playground.
function run(argv){
var url = argv[0];
var argcp = 1;
url += "?cos=1"; // Start the query string and set mode
while(argcp < argv.length){
url += "&" + argv[argcp] + "=" + encodeURIComponent(argv[argcp+1])
argcp += 2;
}
var safari = Application('Safari');
var nw = safari.make({ new:"document" });
nw.url = url;
safari.activate();
}

View File

@@ -1,38 +0,0 @@
#!./nhlua
-- NetHack 3.7 nhcrashreport.lua $NHDT-Date: 1693083824 2023/08/26 21:03:44 $ $NHDT-Branch: keni-crashweb2 $:$NHDT-Revision: 1.0 $
-- Copyright (c) 2023 Kenneth Lorber
-- NetHack may be freely redistributed. See license for details.
-- Call with URL then field value pairs. Opens a new browser window
-- to: URL?field=value+field=value.....
-- This program encodes the values; fieldnames don't require encoding.
--
-- Should be installed in the playground.
----
-- from
-- https://github.com/daurnimator/lua-http/blob/master/http/util.lua
-- Encodes a character as a percent encoded string
local function char_to_pchar(c)
return string.format("%%%02X", c:byte(1,1))
end
-- encodeURIComponent escapes all characters except the following: alphabetic, decimal digits, - _ . ! ~ * ' ( )
local function encodeURIComponent(str)
return (str:gsub("[^%w%-_%.%!%~%*%'%(%)]", char_to_pchar))
end
----
function un20(str)
return str:gsub("%%20","+")
end
url = table.remove(arg,1) .. "?cos=1"; -- Start the query string and set mode
while #arg > 0 do
local field = table.remove(arg,1)
local value = table.remove(arg,1)
url = url .. "&" .. field .. "=" .. un20(encodeURIComponent(value))
end
--print("url='"..url.."'")
cmd = '/usr/bin/xdg-open "'..url..'"'
os.execute(cmd)
os.exit()