diff --git a/dat/opthelp b/dat/opthelp index d865c468c..dc9cee07a 100644 --- a/dat/opthelp +++ b/dat/opthelp @@ -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 carrying an unlocking tool or you decline to use one 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] offered at the end of the game (space separated list of two-character values; diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index 15cdfd321..2ed8cfc1d 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -1228,6 +1228,10 @@ Toggle the .op autopickup option on/off. 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 " Call (name) a monster, or an object in inventory, on the floor, or in the discoveries list, or add an annotation for the @@ -4995,6 +4999,22 @@ window, windowframe, windowtext). If NetHack can, it should wrap long lines of text if they don't fit in the visible area of the window. .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 .pg Here are explanations of options that are used by specific platforms or ports @@ -6100,10 +6120,11 @@ large unless it is actively maintained. . .lp CRASHREPORTURL\ =\ If set to -\f(CRhttps://www.nethack.org/common/contact.html\fP -and support is compiled in, brings up a browser window populated with +\f(CRhttps://www.nethack.org/links/cr-37BETA.html\fP +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 -up in an internally inconsistent state. +up in an internally inconsistent state, or if the #bugreport command is +invoked. .hn 1 Scoring .pg diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index 5ba5e1c90..9f8f610ff 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -26,6 +26,8 @@ \newcommand{\elist}{\end{list}} +\hyphenation{CRASHREPORTURL} + % this will make \tt underscores look better, but requires that % math subscripts will never be used in this document \catcode`\_=12 @@ -1332,6 +1334,12 @@ Show your attributes. Default key is `{\tt \^{}X}'. \item[\tb{\#autopickup}] Toggle the {\it autopickup\/} option. Default key is `{\tt @}'. %.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}] Call (name) a monster, or an object in inventory, on the floor, or in the discoveries list, or add an annotation for the @@ -5509,6 +5517,31 @@ If {\it NetHack\/} can, it should wrap long lines of text if they don't fit in the visible area of the window. \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 \subsection*{Platform-specific Customization options} @@ -6715,10 +6748,11 @@ large unless it is actively maintained. %.lp \item[\ib{CRASHREPORTURL}] 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 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 %.hn 1 diff --git a/doc/config.nh b/doc/config.nh index 659d70757..d8be02055 100644 --- a/doc/config.nh +++ b/doc/config.nh @@ -530,3 +530,12 @@ # Use highlighting in the status lines when it changes? #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. diff --git a/include/config.h b/include/config.h index 1093463ef..48613c5d2 100644 --- a/include/config.h +++ b/include/config.h @@ -242,12 +242,33 @@ #ifndef CRASHREPORT # ifdef MACOS - /* NB: This needs to be a full path unless it's in the playground. */ -/*#define CRASHREPORT "NetHackCrashReport.JavaScript"*/ +# define CRASHREPORT "/usr/bin/open" # endif # ifdef __linux__ - /* NB: This expects to find the nhlua binary as "./nhlua" */ -/*#define CRASHREPORT "nhcrashreport.lua"*/ +# define CRASHREPORT "/usr/bin/xdg-open" + /* 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 diff --git a/include/decl.h b/include/decl.h index 108f5d8a0..31c030b1c 100644 --- a/include/decl.h +++ b/include/decl.h @@ -248,6 +248,11 @@ struct instance_globals_c { /* dog.c */ 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 */ int currentgraphics; diff --git a/include/extern.h b/include/extern.h index 03b86baa5..8647997af 100644 --- a/include/extern.h +++ b/include/extern.h @@ -905,9 +905,11 @@ extern void dealloc_killer(struct kinfo *); extern void save_killers(NHFILE *) NONNULLARG1; extern void restore_killers(NHFILE *) NONNULLARG1; #ifdef 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_bidshow(void); +extern boolean swr_add_uricoded(const char *, char **, int *, char *); +extern int dobugreport(void); #endif extern char *build_english_list(char *) NONNULLARG1; #if defined(PANICTRACE) && !defined(NO_SIGNAL) @@ -1924,6 +1926,13 @@ extern int dosuspend(void); extern void nt_regularize(char *); extern int(*nt_kbhit)(void); 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 /* MICRO || WIN32 */ diff --git a/include/hack.h b/include/hack.h index e93595777..584228510 100644 --- a/include/hack.h +++ b/include/hack.h @@ -418,7 +418,7 @@ enum earlyarg { #ifdef WIN32 , ARG_WINDOWS #endif -#ifdef CRASHREPORT +#if defined(CRASHREPORT) , ARG_BIDSHOW #endif }; diff --git a/include/optlist.h b/include/optlist.h index dc2f05466..ca47ea81b 100644 --- a/include/optlist.h +++ b/include/optlist.h @@ -232,6 +232,17 @@ static int optfn_##a(int, int, boolean, char *, char *); NHOPTB(confirm, Advanced, 0, opt_out, set_in_game, On, Yes, No, No, NoAlias, &flags.confirm, Term_False, "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 NHOPTC(cursesgraphics, Advanced, 70, opt_in, set_in_config, No, Yes, No, No, NoAlias, diff --git a/include/winprocs.h b/include/winprocs.h index 40e68a6b8..b5ab5b0c3 100644 --- a/include/winprocs.h +++ b/include/winprocs.h @@ -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_hup, wp_guistubs, wp_ttystubs, #ifdef OUTDATED_STUFF - , wp_mac, wp_Gem, wp_Gnome, wp_amii, wp_amiv + wp_mac, wp_Gem, wp_Gnome, wp_amii, wp_amiv, #endif + wp_trace // XXX do we need this? should chainin/out get an id? TBD }; /* 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 * pointers, add the appropriate #ifdef below. + * XXX which is what? */ #define init_nhwindows (*windowprocs.win_init_nhwindows) @@ -370,7 +372,6 @@ struct chain_procs { void (*win_end_menu)(CARGS, winid, const char *); int (*win_select_menu)(CARGS, winid, int, MENU_ITEM_P **); char (*win_message_menu)(CARGS, char, int, const char *); - void (*win_update_inventory)(CARGS, int); void (*win_mark_synch)(CARGS); void (*win_wait_synch)(CARGS); #ifdef CLIPPING @@ -418,6 +419,8 @@ struct chain_procs { void (*win_status_update)(CARGS, int, genericptr_t, int, int, int, unsigned long *); 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 */ diff --git a/src/allmain.c b/src/allmain.c index b35a03a85..db8d2c5a9 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -908,7 +908,7 @@ static const struct early_opt earlyopts[] = { #ifdef WIN32 { ARG_WINDOWS, "windows", 4, TRUE }, #endif -#ifdef CRASHREPORT +#if defined(CRASHREPORT) { ARG_BIDSHOW, "bidshow", 7, FALSE }, #endif }; @@ -932,8 +932,9 @@ argcheck(int argc, char *argv[], enum earlyarg e_arg) const char *dashdash = ""; for (idx = 0; idx < SIZE(earlyopts); idx++) { - if (earlyopts[idx].e == e_arg) + if (earlyopts[idx].e == e_arg){ break; + } } if (idx >= SIZE(earlyopts) || argc < 1) return 0; diff --git a/src/cmd.c b/src/cmd.c index 0940eb93b..3f61dba95 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -2548,6 +2548,10 @@ struct ext_func_tab extcmdlist[] = { doattributes, IFBURIED, NULL }, { '@', "autopickup", "toggle the 'autopickup' option on/off", 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", docallcmd, IFBURIED, NULL }, { 'Z', "cast", "zap (cast) a spell", diff --git a/src/decl.c b/src/decl.c index be1826fdf..db80503d9 100644 --- a/src/decl.c +++ b/src/decl.c @@ -278,6 +278,10 @@ const struct instance_globals_c g_init_c = { DUMMY, /* context */ /* dog.c */ DUMMY, /* catname */ + /* end.c */ + NULL, /* crash_email */ + NULL, /* crash_name */ + -1, /* crash_urlmax */ /* symbols.c */ 0, /* currentgraphics */ /* files.c */ diff --git a/src/end.c b/src/end.c index 7d12473f9..522a6c919 100644 --- a/src/end.c +++ b/src/end.c @@ -21,9 +21,9 @@ #ifndef NO_SIGNAL static void done_intr(int); -#if defined(UNIX) || defined(VMS) || defined(__EMX__) +# if defined(UNIX) || defined(VMS) || defined(__EMX__) static void done_hangup(int); -#endif +# endif #endif static void disclose(int, boolean); static void get_valuables(struct obj *) NO_NNARGS; @@ -37,6 +37,9 @@ static boolean should_query_disclose_option(int, char *); static void dump_plines(void); #endif 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) 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 -#ifndef PANICTRACE -#define NH_abort(x) NH_abort_ -#endif +// XXX is there a configuration that still needs this? +//#ifndef PANICTRACE +//#define NH_abort(x) NH_abort_ +//#endif #ifdef AMIGA #define NH_abort_ Abort(0) @@ -64,7 +68,8 @@ ATTRNORETURN extern void nethack_exit(int) NORETURN; #endif /* !SYSV */ #endif /* !AMIGA */ -#ifdef PANICTRACE +/* NB: CRASHREPORT implies PANICTRACE */ +#if defined(PANICTRACE) #include #ifdef PANICTRACE_LIBC #include @@ -79,32 +84,30 @@ ATTRNORETURN extern void nethack_exit(int) NORETURN; * -requires -g, which may preclude -O on some compilers * * 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. */ #ifdef SYSCF -#define SYSOPT_PANICTRACE_GDB sysopt.panictrace_gdb -#ifdef PANICTRACE_LIBC -#define SYSOPT_PANICTRACE_LIBC sysopt.panictrace_libc +# define SYSOPT_PANICTRACE_GDB sysopt.panictrace_gdb +# ifdef PANICTRACE_LIBC +# define SYSOPT_PANICTRACE_LIBC sysopt.panictrace_libc +# else +# define SYSOPT_PANICTRACE_LIBC 0 +# endif #else -#define SYSOPT_PANICTRACE_LIBC 0 -#endif -#else -#define SYSOPT_PANICTRACE_GDB (nh_getenv("NETHACK_USE_GDB") == 0 ? 0 : 2) -#ifdef PANICTRACE_LIBC -#define SYSOPT_PANICTRACE_LIBC 1 -#else -#define SYSOPT_PANICTRACE_LIBC 0 -#endif +# define SYSOPT_PANICTRACE_GDB (nh_getenv("NETHACK_USE_GDB") == 0 ? 0 : 2) +# ifdef PANICTRACE_LIBC +# define SYSOPT_PANICTRACE_LIBC 1 +# else +# define SYSOPT_PANICTRACE_LIBC 0 +# endif #endif -#ifdef PANICTRACE static void NH_abort(char *); -#endif #ifndef NO_SIGNAL static void panictrace_handler(int); #endif -static boolean NH_panictrace_libc(char *); +static boolean NH_panictrace_libc(void); static boolean NH_panictrace_gdb(void); #ifndef NO_SIGNAL @@ -171,7 +174,6 @@ panictrace_setsignals(boolean set) } #endif /* NO_SIGNAL */ -#ifdef PANICTRACE static void NH_abort(char *why) { @@ -185,233 +187,396 @@ NH_abort(char *why) return; aborting = TRUE; +#ifdef CRASHREPORT + if(!submit_web_report(1, "Panic", why)) +#endif + { #ifndef VMS - if (gdb_prio == libc_prio && gdb_prio > 0) - gdb_prio++; + if (gdb_prio == libc_prio && gdb_prio > 0) + gdb_prio++; - if (gdb_prio > libc_prio) { - (void) (NH_panictrace_gdb() || (libc_prio && NH_panictrace_libc(why))); - } else { - (void) (NH_panictrace_libc(why) || (gdb_prio && NH_panictrace_gdb())); - } + if (gdb_prio > libc_prio) { + (void) (NH_panictrace_gdb() || (libc_prio && NH_panictrace_libc())); + } else { + (void) (NH_panictrace_libc() || (gdb_prio && NH_panictrace_gdb())); + } #else /* VMS */ - /* overload otherwise unused priority for debug mode: 1 = show - traceback and exit; 2 = show traceback and stay in debugger */ - /* if (wizard && gdb_prio == 1) gdb_prio = 2; */ - vms_traceback(gdb_prio); - nhUse(libc_prio); + /* overload otherwise unused priority for debug mode: 1 = show + traceback and exit; 2 = show traceback and stay in debugger */ + /* if (wizard && gdb_prio == 1) gdb_prio = 2; */ + vms_traceback(gdb_prio); + nhUse(libc_prio); #endif /* ?VMS */ + } #ifndef NO_SIGNAL panictrace_setsignals(FALSE); #endif NH_abort_; } + +#ifdef CRASHREPORT +# include +# ifdef WIN32 +# define HASH_PRAGMA_START +# define HASH_PRAGMA_END +# else +# define HASH_PRAGMA_START \ + _Pragma("GCC diagnostic push"); \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +# define HASH_PRAGMA_END _Pragma("GCC diagnostic pop"); +# endif +# ifdef MACOS +# include +# define HASH_CONTEXTPTR(CTXP) \ + unsigned char tmp[CC_MD4_DIGEST_LENGTH]; \ + CC_MD4_CTX CTXP ## _; \ + CC_MD4_CTX *CTXP = &CTXP ## _ +# 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 +# ifdef __linux__ +# include +# define HASH_CONTEXTPTR(CTXP) \ + unsigned char tmp[MD4_DIGEST_LENGTH]; \ + MD4_CTX CTXP ## _; \ + MD4_CTX *CTXP = &CTXP ## _ +# define HASH_INIT(ctxp) !MD4_Init(ctxp) +# 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 +// binaries. This is easily spoofed! +static char bid[40]; + +/* ARGSUSED */ +void +crashreport_init(int argc UNUSED, char *argv[] UNUSED){ + static int once=0; if(once++) return; // NetHackW.exe calls us twice + HASH_BINFILE_DECL; + HASH_PRAGMA_START + HASH_CONTEXTPTR(ctxp); + if(HASH_INIT(ctxp)) goto skip; + HASH_BINFILE(); // Does "goto skip" on error. + + int fd = open(binfile, HASH_OFLAGS, 0); + if (fd == -1) { +# ifdef BETA + raw_printf("open e=%s", strerror(errno)); +# endif + goto skip; + } + + int segsize; + unsigned char segment[4096]; + + while (0 < (segsize = read(fd, segment,sizeof(segment)))) { + if(HASH_UPDATE(ctxp, segment, segsize)) goto skip; + } + if(segsize < 0) { + close(fd); + goto skip; + } + if(HASH_FINISH(ctxp)) goto skip; + close(fd); + + char *p = bid; + unsigned char *in; + 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--) { + p += snprintf(p, HASH_RESULT_SIZE(ctxp) - (p - bid), "%02x", *(in++)); + } + *p = '\0'; + return; +skip: + strncpy((char *)bid,"unknown",sizeof(bid)-1); + HASH_CLEANUP(ctxp); + HASH_PRAGMA_END +} +#undef HASH_CONTEXTPTR +#undef HASH_INIT +#undef HASH_UPDATE +#undef HASH_FINISH +#undef HASH_CLEANUP +#undef HASH_RESULT +#undef HASH_RESULT_SIZE +#undef HASH_PRAGMA_START +#undef HASH_PRAGMA_END +#undef HASH_BINFILE_DECL +#undef HASH_BINFILE + +void +crashreport_bidshow(void){ +#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 - * (but libc can still do anything it wants). */ + * (on most platforms) (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 -# include -# define HASH_PRAGMA_START \ - _Pragma("GCC diagnostic push"); \ - _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") -# define HASH_PRAGMA_END _Pragma("GCC diagnostic pop"); -# ifdef MACOS -# include -# define HASH_CONTEXT CC_MD4_CTX -# define HASH_INIT(ctx) CC_MD4_Init(ctx) -# define HASH_UPDATE(ctx, ptr, len) CC_MD4_Update(ctx, ptr, len) -# define HASH_FINISH(ctx, out) CC_MD4_Final(out, ctx) -# define HASH_RESULT_SIZE CC_MD4_DIGEST_LENGTH -# endif -# ifdef __linux__ -# include -# define HASH_CONTEXT MD4_CTX -# define HASH_INIT(ctx) MD4_Init(ctx) -# define HASH_UPDATE(ctx, ptr, len) MD4_Update(ctx, ptr, len) -# define HASH_FINISH(ctx, out) MD4_Final(out, ctx) -# define HASH_RESULT_SIZE MD4_DIGEST_LENGTH -# endif -/* Binary ID - Use only as a hint to contact.html for recognizing our own - * binaries. This is easily spoofed! */ -static char bid[(2 * HASH_RESULT_SIZE) + 1]; - -/* ARGSUSED */ -void -crashreport_init(int argc UNUSED, char *argv[] UNUSED) -{ - unsigned char tmp[HASH_RESULT_SIZE]; - HASH_PRAGMA_START - HASH_CONTEXT ctx; - HASH_INIT(&ctx); -#ifdef MACOS - char *binfile = argv[0]; - - if (!binfile || !*binfile) { -#ifdef BETA - /* If this triggers, investigate CFBundleGetMainBundle - * or CFBundleCopyExecutableURL. */ - raw_print("BETA warning: crashreport_init called without useful info"); +// 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 - goto skip; - } +#ifndef SWR_FRAMES +# define SWR_FRAMES 20 #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; +// 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 +swr_add_uricoded(const char *in, char **out, int *remaining, char *markp){ + while(*in){ + if( + isalnum(*in) || + *in == '_' || + *in == '-' || + *in == '.' || + *in == '~' // || + ){ + **out = *in; + (*out)++; + (*remaining)--; + } else if(*in == ' '){ + **out = '+'; + (*out)++; + (*remaining)--; + } else { + if(*remaining <= 3){ + if(markp) *out = markp, *remaining = 0; + **out = '\0'; + return TRUE; + } + int x = snprintf(*out, *remaining, "%%%02X", *in); + *out += x; + *remaining -= x; + } + in++; + if(! *remaining){ + if(markp) *out = markp, *remaining = 0; + **out = '\0'; + return TRUE; + } + **out = '\0'; } -#endif - int fd = open(binfile, O_RDONLY, 0); - - if (fd == -1) { -#ifdef BETA - raw_printf("open e=%s", strerror(errno)); -#endif - goto skip; - } - int segsize; - char segment[4096]; - - while (0 < (segsize = read(fd, segment,sizeof(segment)))) { - HASH_UPDATE(&ctx, segment, segsize); - } - HASH_FINISH(&ctx, tmp); - close(fd); - - char *p = bid; - unsigned char *in = &tmp[0]; - char cnt = HASH_RESULT_SIZE; - - while (cnt--) { - p += snprintf(p, HASH_RESULT_SIZE - (p - bid), "%02x", *(in++)); - } - *p = '\0'; - return; - skip: - strncpy((char *) bid, "unknown", sizeof bid - 1); - HASH_PRAGMA_END + return FALSE; // normal return } -#undef HASH_CONTEXT -#undef HASH_INIT -#undef HASH_UPDATE -#undef HASH_FINISH -#undef HASH_RESULT_SIZE -#undef HASH_PRAGMA_START -#undef HASH_PRAGMA_END -void -crashreport_bidshow(void) -{ - raw_print(bid); -} +static char url[MAX_URL]; // XXX too bad this isn't allocated as needed +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(const char *msg, char *why) -{ - if (sysopt.crashreporturl) { - const char *xargv[SWR_LINES]; - char version[100]; - char versionstring[200]; /* used twice as a temp */ - int xargc = 0; - char wholetrace[SWR_LINES * 80]; /* XXX roughly 71 on MacOS, - * plus buffer */ - int prelines = 0; /* count of lines in trace header */ - char nbuf[6]; /* number buffer */ - extern char **environ; - pid_t pid; +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); - SWR_ADD(CRASHREPORT); - SWR_ADD(sysopt.crashreporturl); - /* then pairs of key value */ - /* subject, generate something useful */ - SWR_ADD("subject"); - snprintf(version, sizeof version, "%s report for NetHack %s", - msg, version_string(versionstring, sizeof versionstring)); - SWR_ADD(version); - /* name: someday, this might be stored in nethackcnf - * email: someday, this might be stored in nethackcnf - * gitver, pull from version.c */ - SWR_ADD("gitver"); - SWR_ADD(getversionstring(versionstring, sizeof versionstring)); - /* hardware: leave for user - * software: leave for user - * comments: leave for user - * details: stack trace */ - SWR_ADD("details"); + /* 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); + } -/* // XXX header for wholetrace - what other info do we want? */ -/* // NB: prelines not tested against size of SWR_FRAMES. */ -#define SWR_HDR(line) \ - do { \ - if (endp < &wholetrace[sizeof wholetrace]) { \ - endp += snprintf(endp, sizeof wholetrace - (endp - wholetrace), \ - "%s\n", line); \ - prelines++; \ - } \ - } while (0) -#define SWR_HDRnonl(line) \ - do { \ - if (endp < &wholetrace[sizeof wholetrace]) { \ - endp += snprintf(endp, sizeof wholetrace - (endp - wholetrace), \ - "%s", line); \ - } \ - } while (0) + SWR_ADD("&gitver="); + SWR_ADD_URIcoded(getversionstring(temp2, sizeof(temp2))); - char *endp = wholetrace; + if(gc.crash_name){ + SWR_ADD("&name="); + SWR_ADD_URIcoded(gc.crash_name); + } - wholetrace[0] = '\0'; - if (why) { - SWR_HDR(why); - } + 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_HDRnonl("bid: "); - SWR_HDR(bid); + 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]; - int count, x; - char **info, buf[BUFSZ]; + int x; + char **info; count = backtrace(bt, SIZE(bt)); info = backtrace_symbols(bt, count); 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 */ - (void) strsubst(buf, " ", ""); - (void) strsubst(buf, " ", ""); - snprintf(endp, SWR_FRAMES * 80 - (endp - wholetrace), - "[%02lu] %s\n", (unsigned long) x, buf); - endp = eos(endp); + (void) strsubst(temp, " ", ""); + (void) strsubst(temp, " ", ""); + strncat(temp, "\n", sizeof temp - 1); +# if 0 // __linux__ +// 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 */ - SWR_ADD(wholetrace); +#endif // !WIN32 + } - /* detailrows min(actual,50) Guess since we can't know the - * width of the window. */ - SWR_ADD("detailrows"); - (void) snprintf(nbuf, sizeof nbuf, "%d", count + prelines); - SWR_ADD(nbuf); - xargv[xargc++] = 0; /* terminate array */ +#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 - pid = fork(); + // detailrows: Guess since we can't know the + // width of the window. + SWR_ADD("&detailrows="); + (void)snprintf(temp,sizeof(temp),"%d",min(count+countpp,30)); + SWR_ADD_URIcoded(temp); + +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) { char err[100]; +#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 (void) execve(CRASHREPORT, (char * const *) xargv, environ); Sprintf(err, "Can't start " CRASHREPORT ": %s", strerror(errno)); @@ -419,11 +584,10 @@ submit_web_report(const char *msg, char *why) } else { int status; errno=0; - /* XXX do we _really_ know this is the right pid? */ (void) waitpid(pid, &status, 0); - if (status) { /* // XXX check could be more precise */ -#if 0 - /* // Not useful at the moment. XXX */ + if (status) { /* XXX check could be more precise */ +#ifdef BETA + /* Not useful at the moment. XXX */ char err[100]; Sprintf(err, "pid=%d e=%d status=%0x", wpid, errno, status); @@ -433,25 +597,39 @@ submit_web_report(const char *msg, char *why) } } /* free(info); -- Don't risk it. */ +#endif 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 */ #undef SWR_ADD +#undef SWR_ADD_URIcoded #undef SWR_FRAMES #undef SWR_HDR -#undef SWR_HDRnonl #undef SWR_LINES /*ARGSUSED*/ static boolean -NH_panictrace_libc(char *why UNUSED) +NH_panictrace_libc(void) { +#if 0 /* XXX how did this get left here? */ #ifdef CRASHREPORT if (submit_web_report("Panic", why)) return TRUE; #endif +#endif #ifdef PANICTRACE_LIBC void *bt[20]; @@ -480,13 +658,13 @@ NH_panictrace_libc(char *why UNUSED) * fooVAR (possibly const) variable containing fooPATH */ #ifdef PANICTRACE_GDB -#ifdef SYSCF -#define GDBVAR sysopt.gdbpath -#define GREPVAR sysopt.greppath -#else /* SYSCF */ -#define GDBVAR GDBPATH -#define GREPVAR GREPPATH -#endif /* SYSCF */ +# ifdef SYSCF +# define GDBVAR sysopt.gdbpath +# define GREPVAR sysopt.greppath +# else /* SYSCF */ +# define GDBVAR GDBPATH +# define GREPVAR GREPPATH +# endif /* SYSCF */ #endif /* PANICTRACE_GDB */ static boolean @@ -901,7 +1079,7 @@ panic VA_DECL(const char *, str) ? "." : "\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) raw_printf("To report this error, %s%s", sysopt.support, maybe_rebuild); @@ -1007,6 +1185,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 /*ARGSUSED*/ diff --git a/src/files.c b/src/files.c index 4ef8caca1..e64d9f3a5 100644 --- a/src/files.c +++ b/src/files.c @@ -4733,6 +4733,9 @@ reveal_paths(void) #endif /* ?UNIX */ raw_print(""); +#if defined(WIN32) && !defined(WIN32CON) + wait_synch(); +#endif } /* ---------- BEGIN TRIBUTE ----------- */ diff --git a/src/mdlib.c b/src/mdlib.c index 1e9b90435..d925435ad 100644 --- a/src/mdlib.c +++ b/src/mdlib.c @@ -677,6 +677,12 @@ static const char *const build_opts[] = { #endif #ifdef SYSCF "system configuration at run-time", +#endif +#ifdef PANICTRACE + "show stack trace on error", +#endif +#ifdef CRASHREPORT + "launch browser to report issues", #endif save_bones_compat_buf, "and basic NetHack features" diff --git a/src/options.c b/src/options.c index 93e63de59..b8d7a3fb4 100644 --- a/src/options.c +++ b/src/options.c @@ -537,7 +537,7 @@ parseoptions( * determine_ambiguities() * figured out exactly how many characters are required to * 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) @@ -1213,6 +1213,80 @@ optfn_catname( return petname_optfn(optidx, req, negated, opts, op); } +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 static int optfn_cursesgraphics(int optidx, int req, boolean negated, @@ -6631,8 +6705,6 @@ initoptions(void) { int i; - go.opt_phase = builtin_opt; - initoptions_init(); /* * Call each option function with an init flag and give it a chance * to make any preparations that it might require. We do this @@ -6677,6 +6749,7 @@ initoptions_init(void) #endif int i; + go.opt_phase = builtin_opt; // Did I need to move this here? memcpy(allopt, allopt_init, sizeof(allopt)); determine_ambiguities(); diff --git a/src/pline.c b/src/pline.c index 897beec05..f64cd6742 100644 --- a/src/pline.c +++ b/src/pline.c @@ -596,7 +596,7 @@ impossible(const char *s, ...) boolean report = ('y' == yn_function("Report now?","yn",'n',FALSE)); raw_print(""); // prove to the user the character was accepted if(report){ - submit_web_report("Impossible", pbuf); + submit_web_report(1, "Impossible", pbuf); } } #endif diff --git a/sys/unix/Makefile.top b/sys/unix/Makefile.top index 50466d12a..f10f04c35 100644 --- a/sys/unix/Makefile.top +++ b/sys/unix/Makefile.top @@ -127,7 +127,7 @@ LUA2NHTOP = ../../.. LUABASELIB = liblua-$(LUA_VERSION).a TOPLUALIB = lib/lua/$(LUABASELIB) -ALLDEP = $(PRECHECK) $(GAME) recover Guidebook $(VARDAT) spec_levs check-dlb check-nhlua +ALLDEP = $(PRECHECK) $(GAME) recover Guidebook $(VARDAT) spec_levs check-dlb # first target is also the default target for 'make' without any arguments all: $(ALLDEP) @@ -163,10 +163,6 @@ luabin: ( cd $(LUATOP) \ && 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 submodules/lua/lua.h: git submodule init submodules/lua diff --git a/sys/unix/hints/linux.370 b/sys/unix/hints/linux.370 index 081ec8c8c..f34bbee06 100755 --- a/sys/unix/hints/linux.370 +++ b/sys/unix/hints/linux.370 @@ -329,10 +329,12 @@ endif #?WANT_SOURCE_INSTALL INSTDIR=$(HACKDIR) VARDIR = $(HACKDIR) -POSTINSTALL+= ( util/makedefs --grep-defined CRASHREPORT && \ - ( cp win/share/nhcrashreport.lua $(INSTDIR) ; \ - chmod 555 $(INSTDIR)/nhcrashreport.lua ; \ - cp $(LUATOP)/lua $(INSTDIR)/nhlua); true ); +#======= XXX can this go away? +#POSTINSTALL+= cp -n sys/unix/sysconf $(INSTDIR)/sysconf; \ +# $(CHOWN) $(GAMEUID) $(INSTDIR)/sysconf; \ +# $(CHGRP) $(GAMEGRP) $(INSTDIR)/sysconf; \ +# chmod $(VARFILEPERM) $(INSTDIR)/sysconf; +#>>>>>>> keni-wincw2 ifneq "$(CCISCLANG)" "" # gdb may not be installed if clang is chosen compiler so the game diff --git a/sys/unix/hints/macOS.370 b/sys/unix/hints/macOS.370 index 981bf4396..047bff67b 100755 --- a/sys/unix/hints/macOS.370 +++ b/sys/unix/hints/macOS.370 @@ -46,6 +46,8 @@ ifndef LIBXPM LIBXPM= -L/opt/X11/lib -lXpm endif +#WANT_WIN_CHAIN=1 + # 4. Other #----------------------------------------------------------------------------- @@ -117,7 +119,7 @@ NHCFLAGS+=-DNOMAIL #NHCFLAGS+=-DNO_CHRONICLE #NHCFLAGS+=-DLIVELOG # not NHCFLAGS - needed for makedefs -CFLAGS+=-DCRASHREPORT=\"NetHackCrashReport.JavaScript\" +CFLAGS+=-DCRASHREPORT=\"/usr/bin/open\" ifdef MAKEFILE_SRC # default @@ -350,9 +352,12 @@ ROOTCHECK= [[ `id -u` == 0 ]] || ( echo "Must run install with sudo."; exit 1) PREINSTALL= . sys/unix/hints/macosx.sh user2 $(GAMEUID); \ . sys/unix/hints/macosx.sh group2 $(GAMEGRP); \ (mkdir $(SHELLDIR) || true); chown $(GAMEUID) $(SHELLDIR) -POSTINSTALL+= util/makedefs --grep-defined CRASHREPORT && \ - ( cp win/macosx/NetHackCrashReport.JavaScript $(HACKDIR) && \ - chmod 0500 $(HACKDIR)/NetHackCrashReport.JavaScript ) +#======= XXX can this go away? +#POSTINSTALL+= sys/unix/hints/macosx.sh editsysconf sys/unix/sysconf $(HACKDIR)/sysconf; \ +# $(CHOWN) $(GAMEUID) $(HACKDIR)/sysconf; \ +# $(CHGRP) $(GAMEGRP) $(HACKDIR)/sysconf; \ +# chmod $(VARFILEPERM) $(HACKDIR)/sysconf; +#>>>>>>> keni-wincw2 else ifdef WANT_SOURCE_INSTALL @@ -368,10 +373,7 @@ CHGRP=/usr/bin/true GAMEPERM = 0700 VARFILEPERM = 0600 VARDIRPERM = 0700 -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 ) +POSTINSTALL+= sys/unix/hints/macosx.sh editsysconf sys/unix/sysconf $(HACKDIR)/sysconf; # We can use "make all" to build the whole thing - but it misses some things: MOREALL=$(MAKE) install @@ -400,10 +402,7 @@ PREINSTALL+= (mkdir $(SHELLDIR) || true); POSTINSTALL+= sys/unix/hints/macosx.sh editsysconf sys/unix/sysconf $(HACKDIR)/sysconf; \ $(CHOWN) $(GAMEUID) $(HACKDIR)/sysconf; \ $(CHGRP) $(GAMEGRP) $(HACKDIR)/sysconf; \ - chmod $(VARFILEPERM) $(HACKDIR)/sysconf; \ - util/makedefs --grep-defined CRASHREPORT && \ - ( cp win/macosx/NetHackCrashReport.JavaScript $(HACKDIR) && \ - chmod 0500 $(HACKDIR)/NetHackCrashReport.JavaScript ) + chmod $(VARFILEPERM) $(HACKDIR)/sysconf; endif # !WANT_SHARE_INSTALL @@ -770,7 +769,6 @@ build_package_root: install -p doc/recover.6 $(PKGROOT_UG)/man/man6 install -p doc/Guidebook $(PKGROOT_UG)/doc 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 cd dat; install -p $(DATNODLB) ../$(PKGROOT_UGLN) # XXX these files should be somewhere else for good Mac form diff --git a/sys/unix/sysconf b/sys/unix/sysconf index 7114a1bbd..e10b4e34c 100644 --- a/sys/unix/sysconf +++ b/sys/unix/sysconf @@ -159,6 +159,9 @@ GREPPATH=/bin/grep PANICTRACE_GDB=1 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 # 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 diff --git a/sys/unix/unixmain.c b/sys/unix/unixmain.c index 11aaa3e48..65ece2246 100644 --- a/sys/unix/unixmain.c +++ b/sys/unix/unixmain.c @@ -150,6 +150,7 @@ main(int argc, char *argv[]) check_linux_console(); #endif + initoptions_init(); initoptions(); #ifdef PANICTRACE ARGV0 = gh.hname; /* save for possible stack trace */ @@ -785,6 +786,7 @@ opt_showpaths(const char *dir) nhUse(dir); #endif iflags.initoptions_noterminate = TRUE; + initoptions_init(); initoptions(); iflags.initoptions_noterminate = FALSE; reveal_paths(); diff --git a/sys/windows/.nethackrc.template b/sys/windows/.nethackrc.template index d7e870cae..7cfdd1b4b 100644 --- a/sys/windows/.nethackrc.template +++ b/sys/windows/.nethackrc.template @@ -233,3 +233,7 @@ OPTIONS=hilite_status:gold/up/yellow/down/brown # St, Dx, Co, In, Wi, Ch 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 diff --git a/sys/windows/Makefile.mingw32 b/sys/windows/Makefile.mingw32 index 5d94edab8..94b83cffc 100644 --- a/sys/windows/Makefile.mingw32 +++ b/sys/windows/Makefile.mingw32 @@ -52,9 +52,10 @@ SOUND_LIBRARIES = windsound # #--------------------------------------------------------------- # Do you want debug information in the executable? +# Required for CRASHREPORT. # -DEBUGINFO = N +DEBUGINFO = Y # #--------------------------------------------------------------- @@ -237,6 +238,7 @@ NHV=$(subst ",,$(NHV1)) # TTY - window port files (tty) # MSWIN - window port files (win32) # WCURSES - window port files (curses) +# WCHAIN - window port files (chain) # WSHR - Tile support files # SNDSYS - sound suppport files for win32 # QT - QT window support files @@ -251,6 +253,7 @@ SNDSYS =../sound/windsound MSWSYS =../sys/windows TTY =../win/tty MSWIN =../win/win32 +WCHAIN =../win/chain WCURSES =../win/curses WSHR =../win/share QT =../win/Qt @@ -351,7 +354,7 @@ $(OBJ): CLEAN_DIR = $(GAMEDIR) $(OBJ) -#===============-================================================= +#================================================================= # LUA library # Source from http://www.lua.org/ftp/lua-5.4.6.tar.gz #================================================================= @@ -985,6 +988,15 @@ CFLAGSW += $(NHCURSESFLAGS) NHWONLY += $(addsuffix .o, cursdial cursinit cursinvt cursmain cursmesg cursmisc cursstat curswins guitty) 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) $(GAMEDIR)/NetHackW.exe: $(NHWOBJS) $(NHWRES) $(DATEW_O) $(LUALIB) $(PDCWLIB) | $(GAMEDIR) @@ -1026,6 +1038,9 @@ $(ONHW)/%.o: $(MSWSYS)/%.c $(NHLUAH) | $(ONHW) $(ONHW)/%.o: $(MSWIN)/%.c $(NHLUAH) | $(ONHW) $(cc) $(CFLAGSW) $< -o$@ +$(ONHW)/%.o: $(WCHAIN)/%.c $(NHLUAH) | $(ONHW) + $(cc) $(CFLAGSW) $< -o$@ + $(ONHW)/%.o: $(WSHR)/%.c $(NHLUAH) | $(ONHW) $(cc) $(CFLAGSW) $< -o$@ @@ -1066,6 +1081,7 @@ NHCURSESFLAGS = -DCURSES_GRAPHICS -DCURSES_UNICODE $(PDCURSESFLAGS) -DPDC_NCMOUS CFLAGSNH += $(NHCURSESFLAGS) NHONLY += $(addsuffix .o, cursdial cursinit cursinvt cursmain cursmesg cursmisc cursstat curswins) endif + DATE_O = $(addsuffix .o, $(addprefix $(ONH)/, date)) NHOBJS = $(addprefix $(ONH)/, $(COREOBJS) $(NHONLY)) @@ -1113,6 +1129,9 @@ $(ONH)/%.o: $(MSWSYS)/%.c $(NHLUAH) | $(ONH) $(ONH)/%.o: $(MSWIN)/%.c $(NHLUAH) | $(ONH) $(cc) $(CFLAGSNH) $< -o$@ +$(ONH)/%.o: $(WCHAIN)/%.c $(NHLUAH) | $(ONH) + $(cc) $(CFLAGSNH) $< -o$@ + $(ONH)/%.o: $(WSHR)/%.c $(NHLUAH) | $(ONH) $(cc) $(CFLAGSNH) $< -o$@ diff --git a/sys/windows/sysconf.template b/sys/windows/sysconf.template index 5bb6bcff6..36f3651bc 100644 --- a/sys/windows/sysconf.template +++ b/sys/windows/sysconf.template @@ -121,3 +121,6 @@ HIDEUSAGE=1 # # The location that file synchronization locks are stored (writeable) #LOCKDIR=c:\ProgramData\NetHack\3.7 + +# URL loaded for creating reports to the NetHack DevTeam +#CRASHREPORTURL=https://nethack.org/links/cr-37BETA.html diff --git a/sys/windows/vs/NetHack/NetHack.vcxproj b/sys/windows/vs/NetHack/NetHack.vcxproj index 3ce5fdf6e..a84e06d3a 100644 --- a/sys/windows/vs/NetHack/NetHack.vcxproj +++ b/sys/windows/vs/NetHack/NetHack.vcxproj @@ -49,7 +49,7 @@ WIN32CON;NO_TILE_C;DLB;SAFEPROCS;SND_LIB_WINDSOUND;USER_SOUNDS;_LIB;HAS_STDINT_H;%(PreprocessorDefinitions) - 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) + 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) $(SndWavDir);%(AdditionalIncludeDirectories) @@ -297,4 +297,4 @@ - + \ No newline at end of file diff --git a/sys/windows/vs/NetHackW/NetHackW.vcxproj b/sys/windows/vs/NetHackW/NetHackW.vcxproj index eaff925d8..15ccd14d7 100644 --- a/sys/windows/vs/NetHackW/NetHackW.vcxproj +++ b/sys/windows/vs/NetHackW/NetHackW.vcxproj @@ -65,7 +65,7 @@ Windows - comctl32.lib;winmm.lib;bcrypt.lib;%(AdditionalDependencies) + dbghelp.lib;comctl32.lib;winmm.lib;bcrypt.lib;%(AdditionalDependencies) $(WinWin32Dir)NethackW.exe.manifest;%(AdditionalManifestFiles) diff --git a/sys/windows/windmain.c b/sys/windows/windmain.c index 0be7ef9cd..342273238 100644 --- a/sys/windows/windmain.c +++ b/sys/windows/windmain.c @@ -545,7 +545,7 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ if (getcwd(orgdir, sizeof orgdir) == (char *) 0) error("NetHack: current directory path too long"); #endif - + initoptions_init(); // This allows OPTIONS in syscf on Windows. set_default_prefix_locations(argv[0]); #if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) @@ -638,6 +638,9 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ if (WINDOWPORT(tty)) consoletty_open(1); #endif +#ifdef WINCHAIN + commit_windowchain(); +#endif init_nhwindows(&argc, argv); @@ -812,6 +815,11 @@ process_options(int argc, char * argv[]) argc--; 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') { /* avoid matching "-dec" for DECgraphics; since the man page * says -d directory, hope nobody's using -desomething_else diff --git a/sys/windows/windsys.c b/sys/windows/windsys.c index a64367d07..e98fd5be8 100644 --- a/sys/windows/windsys.c +++ b/sys/windows/windsys.c @@ -24,7 +24,10 @@ #ifdef TTY_GRAPHICS #include "wintty.h" #endif +#include + #ifdef WIN32 +#include /* * The following WIN32 API routines are used in this file. @@ -768,6 +771,281 @@ nt_assert_failed(const char *expression, const char *filepath, int 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 +#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 + +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 + +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;xName[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 */ /*windsys.c*/ diff --git a/win/X11/nethack.rc b/win/X11/nethack.rc index cc6a88277..417679492 100644 --- a/win/X11/nethack.rc +++ b/win/X11/nethack.rc @@ -84,3 +84,8 @@ OPTIONS=catname:Ghisteslwchlohm # 048 035 064 042 \ # 047 045 092 124 124 092 045 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 diff --git a/win/chain/wc_chainin.c b/win/chain/wc_chainin.c index d6df8de4b..6573fe826 100644 --- a/win/chain/wc_chainin.c +++ b/win/chain/wc_chainin.c @@ -108,7 +108,7 @@ chainin_procs_chain( tdp->nprocs = 0; tdp->ndata = 0; tdp->linknum = n; - cibase = 0; + cibase = tdp; break; case WINCHAIN_INIT: tdp = me; @@ -584,7 +584,7 @@ chainin_ctrl_nhwindow( int request, win_request_info *wri) { - boolean rv; + win_request_info *rv; rv = (*cibase->nprocs->win_ctrl_nhwindow)(cibase->ndata, window, request, wri); @@ -609,7 +609,7 @@ struct window_procs chainin_procs = { chainin_display_nhwindow, chainin_destroy_nhwindow, chainin_curs, chainin_putstr, chainin_putmixed, chainin_display_file, 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, #ifdef CLIPPING chainin_cliparound, diff --git a/win/chain/wc_chainout.c b/win/chain/wc_chainout.c index 0f4ebcb57..a0198173c 100644 --- a/win/chain/wc_chainout.c +++ b/win/chain/wc_chainout.c @@ -702,12 +702,13 @@ chainout_can_suspend(void *vp) win_request_info * chainout_ctrl_nhwindow( + void *vp, winid window, int request, win_request_info *wri) { struct chainout_data *tdp = vp; - boolean rv; + win_request_info *rv; rv = (*tdp->nprocs->win_ctrl_nhwindow)(window, request, wri); @@ -733,7 +734,8 @@ struct chain_procs chainout_procs = { chainout_destroy_nhwindow, chainout_curs, chainout_putstr, chainout_putmixed, chainout_display_file, chainout_start_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, #ifdef CLIPPING chainout_cliparound, diff --git a/win/chain/wc_trace.c b/win/chain/wc_trace.c index d710f4479..6738d0b0b 100644 --- a/win/chain/wc_trace.c +++ b/win/chain/wc_trace.c @@ -9,8 +9,15 @@ #include #include -FILE *wc_tracelogf; /* Should be static, but it's just too useful to have - * access to this logfile from arbitrary other files. */ +#ifdef WIN32 +long getpid(void); +long +getpid(){ + return 0; +} +#endif + +FILE *wc_tracelogf; static unsigned int indent_level; /* Some winfuncs call other winfuncs, so * 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 *); int trace_select_menu(void *,winid, int, MENU_ITEM_P **); char trace_message_menu(void *,char, int, const char *); -void trace_update_inventory(void *,int); void trace_mark_synch(void *); void trace_wait_synch(void *); #ifdef CLIPPING @@ -101,6 +107,8 @@ void trace_status_update(void *,int, genericptr_t, int, int, int, unsigned long *); 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_chain(int cmd, int n, void *me, void *nextprocs, void *nextdata); @@ -144,7 +152,7 @@ trace_procs_chain( void trace_procs_init(int dir) { - char fname[200]; + char tfile[20]; long pid; /* processors shouldn't need this test, but just in case */ @@ -152,8 +160,14 @@ trace_procs_init(int dir) return; 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"); + (void)setvbuf(wc_tracelogf, NULL, _IONBF, 0); if (!wc_tracelogf) { fprintf(stderr, "Can't open trace log file %s: %s\n", fname, strerror(errno)); @@ -578,6 +592,16 @@ trace_update_inventory(void *vp, int arg) 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 trace_mark_synch(void *vp) { @@ -1186,7 +1210,8 @@ trace_can_suspend(void *vp) } struct chain_procs trace_procs = { - "+trace", 0, /* wincap */ + "+trace", wp_trace, + 0, /* wincap */ 0, /* wincap2 */ {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_destroy_nhwindow, trace_curs, trace_putstr, trace_putmixed, 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, #ifdef CLIPPING trace_cliparound, @@ -1228,4 +1253,6 @@ struct chain_procs trace_procs = { trace_status_init, trace_status_finish, trace_status_enablefield, trace_status_update, trace_can_suspend, + trace_update_inventory, + trace_ctrl_nhwindow }; diff --git a/win/macosx/NetHackCrashReport.JavaScript b/win/macosx/NetHackCrashReport.JavaScript deleted file mode 100755 index f6f02c88a..000000000 --- a/win/macosx/NetHackCrashReport.JavaScript +++ /dev/null @@ -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(); -} diff --git a/win/share/nhcrashreport.lua b/win/share/nhcrashreport.lua deleted file mode 100755 index a5b073381..000000000 --- a/win/share/nhcrashreport.lua +++ /dev/null @@ -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()