diff --git a/DEVEL/Developer.txt b/DEVEL/Developer.txt index 1316f23e0..e9b943499 100644 --- a/DEVEL/Developer.txt +++ b/DEVEL/Developer.txt @@ -4,7 +4,7 @@ |___/\___|\_/\___|_\___/ .__/\___|_| |_| -$NHDT-Date: 1518800857 2018/02/16 17:07:37 $ +$NHDT-Date: 1519228647 2018/02/21 15:57:27 $ Welcome to the NetHack Infrastructure Developer's Guide. @@ -25,6 +25,7 @@ CONTENTS 5. variable expansion 6. reserved names 7. nhadd/nhcommit +8. hooks ------------------------------------------------------------------------------ 1. email Email to devteam@nethack.org will usually get a response, but it may take a @@ -38,7 +39,8 @@ available can be obtained via git from either of two locations: or https://sourceforge.net/p/nethack/NetHack/ -XXX need to discuss what branches are available +Branches: +NetHack-3.6.0 The 3.6.0 release code and subsequent fixes and additions. ------------------------------------------------------------------------------ 3. bug reporting Please use the form at http://www.nethack.org/common/contact.html (or send @@ -95,7 +97,8 @@ C. Configure the repository: -v verbose -n dry run You can re-run nhgitset.pl as often as needed; occasionally we will - update it and ask you to run it again. + update it (or something it installs) and you will need to run it again + so the changes take effect. D. aliases Two aliases are installed by nhgitset.pl: nhadd @@ -212,3 +215,19 @@ D. Using your own hooks "perldoc DEVEL/hooksdir/nhsub". ------------------------------------------------------------------------------ +8. hooks + + nhgitset.pl also installs hooks into .git/hooks. These hooks provide + a framework which allows local hook code to co-exist with hook code we + supply - see DEVEL/hooksdir/NHgithook.pm for details. + + We currently use the following hooks: + post-checkout + post-commit + post-merge + These are used to generate dat/gitinfo.txt which provides the data that + ends up available through the game command #version and the command line + option --version. + +------------------------------------------------------------------------------ + diff --git a/DEVEL/gitinfo.pl b/DEVEL/gitinfo.pl new file mode 100644 index 000000000..d62f1a588 --- /dev/null +++ b/DEVEL/gitinfo.pl @@ -0,0 +1,33 @@ +#!/usr/bin/perl + +#STARTUP-START +BEGIN { + # OS hackery has to be duplicated in each of the hooks :/ + # first the directory separator + my $DS = quotemeta('/'); + my $PDS = '/'; + # msys: POSIXish over a Windows filesystem (so / not \ but \r\n not \n). + # temporarily removed because inconsistent behavior + # if ($^O eq "msys") + # { + # $/ = "\r\n"; + # $\ = "\r\n"; + # } + if($^O eq "MSWin32"){ + $DS = quotemeta('\\'); + $PDS = '\\'; + } + $gitdir = `git rev-parse --git-dir`; + chomp $gitdir; + push(@INC, $gitdir.$PDS."hooks"); + + # special case for this script only: allow + # it to run from DEVEL or $TOP + if (-f "hooksdir/NHgithook.pm" || -f "DEVEL/hooksdir/NHgithook.pm"){ + push(@INC, "DEVEL/hooksdir"); + } + chdir("..") if (-f "hooksdir/NHgithook.pm"); +} +use NHgithook; + +&NHgithook::nhversioning; diff --git a/DEVEL/hooksdir/.NHgithook.pm.swp b/DEVEL/hooksdir/.NHgithook.pm.swp deleted file mode 100644 index 19e7ec873..000000000 Binary files a/DEVEL/hooksdir/.NHgithook.pm.swp and /dev/null differ diff --git a/DEVEL/hooksdir/NHgithook.pm b/DEVEL/hooksdir/NHgithook.pm index 6024c1c03..0d586cfb7 100644 --- a/DEVEL/hooksdir/NHgithook.pm +++ b/DEVEL/hooksdir/NHgithook.pm @@ -1,7 +1,7 @@ # # NHgithook.pm # NetHack Git Hook Module -# $NHDT-Date$ +# $NHDT-Date: 1519164205 2018/02/20 22:03:25 $ package NHgithook; use Cwd; @@ -60,6 +60,41 @@ sub POST { &do_hook("POST"); } +### +### store githash and gitbranch in dat/gitinfo.txt +### + +sub nhversioning { + use strict; + use warnings; + + my $git_sha = `git rev-parse HEAD`; + $git_sha =~ s/\s+//g; + my $git_branch = `git rev-parse --abbrev-ref HEAD`; + $git_branch =~ s/\s+//g; + die "git rev-parse failed" unless(length $git_sha and length $git_branch); + + if (open my $fh, '<', 'dat/gitinfo.txt') { + while(my $line = <$fh>) { + if ((index $line, $git_sha) >= 0) { + close $fh; + print "No update made to dat/gitinfo.txt, existing githash=".$git_sha."\n"; + return; + } + } + close $fh; + } else { + print "WARNING: Can't find dat directory\n" unless(-d "dat"); + } + if (open my $fh, '>', 'dat/gitinfo.txt') { + print $fh 'githash='.$git_sha."\n"; + print $fh 'gitbranch='.$git_branch."\n"; + print "An updated dat/gitinfo.txt was written, githash=".$git_sha."\n"; + } else { + print "WARNING: Unable to open dat/gitinfo.txt: $!\n"; + } +} + # PRIVATE sub do_hook { my($p) = @_; diff --git a/DEVEL/hooksdir/post-checkout b/DEVEL/hooksdir/post-checkout index b5bf990fe..2df107a2f 100755 --- a/DEVEL/hooksdir/post-checkout +++ b/DEVEL/hooksdir/post-checkout @@ -26,5 +26,6 @@ use NHgithook; #STARTUP-END &NHgithook::PRE; +&NHgithook::nhversioning; &NHgithook::POST; exit 0; diff --git a/DEVEL/hooksdir/post-commit b/DEVEL/hooksdir/post-commit index b5bf990fe..2df107a2f 100755 --- a/DEVEL/hooksdir/post-commit +++ b/DEVEL/hooksdir/post-commit @@ -26,5 +26,6 @@ use NHgithook; #STARTUP-END &NHgithook::PRE; +&NHgithook::nhversioning; &NHgithook::POST; exit 0; diff --git a/DEVEL/hooksdir/post-merge b/DEVEL/hooksdir/post-merge index b5bf990fe..2dc7f3628 100755 --- a/DEVEL/hooksdir/post-merge +++ b/DEVEL/hooksdir/post-merge @@ -22,9 +22,11 @@ BEGIN { chomp $gitdir; push(@INC, $gitdir.$PDS."hooks"); } + use NHgithook; #STARTUP-END &NHgithook::PRE; +&NHgithook::nhversioning; &NHgithook::POST; exit 0; diff --git a/README b/README index 5c4117f46..c428e146d 100644 --- a/README +++ b/README @@ -122,7 +122,10 @@ Please read items (1), (2) and (3) BEFORE doing anything with your new code. If you have problems building the game, or you find bugs in it, we recommend filing a bug report from our "Contact Us" web page at: - http://www.nethack.org/ + https://www.nethack.org/common/contact.html or + http://www.nethack.org/common/contact.html +Please include the version information from #version or the command line +option --version in the apropriate field. A public repository of the latest NetHack code that we've made available can be obtained via git here: diff --git a/doc/makedefs.6 b/doc/makedefs.6 index 7b55de3e4..29d4899be 100644 --- a/doc/makedefs.6 +++ b/doc/makedefs.6 @@ -85,6 +85,14 @@ Generate .I date.h and .I options +file. It will read +.I dat/gitinfo.txt +,only if it is present, to obtain +.B githash= +and +.B gitbranch= + info and include related preprocessor #defines in +.I date.h file. .br .TP diff --git a/doc/nethack.6 b/doc/nethack.6 index 3803ae583..f2ef799f1 100644 --- a/doc/nethack.6 +++ b/doc/nethack.6 @@ -1,5 +1,5 @@ .TH NETHACK 6 "7 December 2015" -.\" NetHack 3.6 nethack.6 $NHDT-Date: 1449616496 2015/12/08 23:14:56 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.11 $ +.\" NetHack 3.6 nethack.6 $NHDT-Date: 1519228609 2018/02/21 15:56:49 $ $NHDT-Branch: githash $:$NHDT-Revision: 1.13 $ .SH NAME nethack \- Exploring The Mazes of Menace .SH SYNOPSIS @@ -34,6 +34,9 @@ nethack \- Exploring The Mazes of Menace [ .B \-ibm ] +[ +.BR \-\-version [ :paste ] +] .PP .B nethack [ @@ -207,6 +210,17 @@ The playground must contain several auxiliary files such as help files, the list of top scorers, and a subdirectory .I save where games are saved. +.PP +.B \-\-version +can be used to cause NetHack to show the version information it +was compiled with, then exit. That will include the +.I git +commit hash if the information was available when the game was compiled. +On some platforms, such as windows and macosx, a variation +.B \-\-version:paste +can be used to cause NetHack to show the version information, then exit, +while also leaving a copy of the version information in the paste buffer +or clipboard for potential insertion into things like bug reports. .SH AUTHORS .PP Jay Fenlason (+ Kenny Woodland, Mike Thome and Jon Payne) wrote the diff --git a/doc/nethack.txt b/doc/nethack.txt index 9e6275edf..4c9986349 100644 --- a/doc/nethack.txt +++ b/doc/nethack.txt @@ -7,7 +7,7 @@ NAME SYNOPSIS nethack [ -d directory ] [ -n ] [ -p profession ] [ -r race ] [ -[DX] ] - [ -u playername ] [ -dec ] [ -ibm ] + [ -u playername ] [ -dec ] [ -ibm ] [ --version[:paste] ] nethack [ -d directory ] -s [ -v ] [ -p profession ] [ -r race ] [ playernames ] diff --git a/include/decl.h b/include/decl.h index f6d5764cb..bf99227f9 100644 --- a/include/decl.h +++ b/include/decl.h @@ -422,6 +422,15 @@ E struct plinemsg_type *plinemsg_types; E const char *ARGV0; #endif +enum earlyarg {ARG_DEBUG, ARG_VERSION}; + +struct early_opt { + enum earlyarg e; + const char *name; + int minlength; + boolean valallowed; +}; + #undef E #endif /* DECL_H */ diff --git a/include/extern.h b/include/extern.h index 24a0c06cd..4ea4915c4 100644 --- a/include/extern.h +++ b/include/extern.h @@ -26,6 +26,7 @@ E void NDECL(display_gamewindows); E void NDECL(newgame); E void FDECL(welcome, (BOOLEAN_P)); E time_t NDECL(get_realtime); +E boolean FDECL(argcheck, (int, char **, enum earlyarg)); /* ### apply.c ### */ @@ -2567,10 +2568,14 @@ E void FDECL(store_version, (int)); E unsigned long FDECL(get_feature_notice_ver, (char *)); E unsigned long NDECL(get_current_feature_ver); E const char *FDECL(copyright_banner_line, (int)); +E void FDECL(early_version_info, (BOOLEAN_P)); #ifdef RUNTIME_PORT_ID E char *FDECL(get_port_id, (char *)); #endif +#ifdef RUNTIME_PASTEBUF_SUPPORT +E void FDECL(port_insert_pastebuf, (char *)); +#endif /* ### video.c ### */ diff --git a/include/ntconf.h b/include/ntconf.h index a096a2ff1..534fa6e5d 100644 --- a/include/ntconf.h +++ b/include/ntconf.h @@ -69,6 +69,12 @@ #define PORT_DEBUG /* include ability to debug international keyboard issues \ */ +#define RUNTIME_PORT_ID /* trigger run-time port identification for \ + * identification of exe CPU architecture \ + */ +#define RUNTIME_PASTEBUF_SUPPORT + + #define SAFERHANGUP /* Define SAFERHANGUP to delay hangup processing \ * until the main command loop. 'safer' because it \ * avoids certain cheats and also avoids losing \ @@ -117,11 +123,6 @@ extern void FDECL(interject, (int)); #endif #endif /* _MSC_VER */ - -#define RUNTIME_PORT_ID /* trigger run-time port identification for \ - * identification of exe CPU architecture \ - */ - /* The following is needed for prototypes of certain functions */ #if defined(_MSC_VER) #include /* Provides prototypes of exit(), spawn() */ diff --git a/include/unixconf.h b/include/unixconf.h index 0d4fbce17..88e309d55 100644 --- a/include/unixconf.h +++ b/include/unixconf.h @@ -387,5 +387,9 @@ #endif /* LINUX */ #endif /* GNOME_GRAPHICS */ +#ifdef __APPLE__ +# define RUNTIME_PASTEBUF_SUPPORT +#endif + #endif /* UNIXCONF_H */ #endif /* UNIX */ diff --git a/src/allmain.c b/src/allmain.c index 4a0cfaf8f..eab1fce3d 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 allmain.c $NHDT-Date: 1513130016 2017/12/13 01:53:36 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.81 $ */ +/* NetHack 3.6 allmain.c $NHDT-Date: 1518193644 2018/02/09 16:27:24 $ $NHDT-Branch: githash $:$NHDT-Revision: 1.86 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -737,5 +737,88 @@ const char *msg; } } +/* + * Argument processing helpers - for xxmain() to share + * and call. + * + * These should return TRUE if the argument matched, + * whether the processing of the argument was + * successful or not. + * + * Most of these do their thing, then after returning + * to xxmain(), the code exits without starting a game. + * + */ + +static struct early_opt earlyopts[] = { + {ARG_DEBUG, "debug", 5, FALSE}, + {ARG_VERSION, "version", 4, TRUE}, +}; + +boolean +argcheck(argc, argv, e_arg) +int argc; +char *argv[]; +enum earlyarg e_arg; +{ + int i, idx; + boolean match = FALSE; + char *userea = (char *)0; + const char *dashdash = ""; + + for (idx = 0; idx < SIZE(earlyopts); idx++) { + if (earlyopts[idx].e == e_arg) + break; + } + if ((idx >= SIZE(earlyopts)) || (argc <= 1)) + return FALSE; + + for (i = 1; i < argc; ++i) { + if (argv[i][0] != '-') + continue; + if (argv[i][1] == '-') { + userea = &argv[i][2]; + dashdash = "-"; + } else { + userea = &argv[i][1]; + } + match = match_optname(userea, earlyopts[idx].name, + earlyopts[idx].minlength, earlyopts[idx].valallowed); + if (match) break; + } + + if (match) { + switch(e_arg) { + case ARG_DEBUG: + break; + case ARG_VERSION: { + boolean insert_into_pastebuf = FALSE; + const char *extended_opt = index(userea,':'); + + if (!extended_opt) + extended_opt = index(userea, '='); + + if (extended_opt) { + extended_opt++; + if (match_optname(extended_opt, "paste", + 5, FALSE)) { + insert_into_pastebuf = TRUE; + } else { + raw_printf( + "-%sversion can only be extended with -%sversion:paste.\n", + dashdash, dashdash); + return TRUE; + } + } + early_version_info(insert_into_pastebuf); + return TRUE; + break; + } + default: + break; + } + }; + return FALSE; +} /*allmain.c*/ diff --git a/src/version.c b/src/version.c index 19f74c265..30e4ce75f 100644 --- a/src/version.c +++ b/src/version.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 version.c $NHDT-Date: 1506993902 2017/10/03 01:25:02 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.44 $ */ +/* NetHack 3.6 version.c $NHDT-Date: 1519155525 2018/02/20 19:38:45 $ $NHDT-Branch: githash $:$NHDT-Revision: 1.47 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ @@ -15,6 +15,13 @@ #include "patchlevel.h" #endif +#if defined(NETHACK_GIT_SHA) +const char * NetHack_git_sha = NETHACK_GIT_SHA; +#endif +#if defined(NETHACK_GIT_BRANCH) +const char * NetHack_git_branch = NETHACK_GIT_BRANCH; +#endif + STATIC_DCL void FDECL(insert_rtoption, (char *)); /* fill buffer with short version (so caller can avoid including date.h) */ @@ -30,23 +37,36 @@ char * getversionstring(buf) char *buf; { - int details = 0; + boolean details = FALSE; Strcpy(buf, VERSION_ID); -#if defined(RUNTIME_PORT_ID) - details++; +#if defined(RUNTIME_PORT_ID) || \ + defined(NETHACK_GIT_SHA) || defined(NETHACK_GIT_BRANCH) + details = TRUE; #endif if (details) { +#if defined(RUNTIME_PORT_ID) || defined(NETHACK_GIT_SHA) || defined(NETHACK_GIT_BRANCH) int c = 0; +#endif +#if defined(RUNTIME_PORT_ID) char tmpbuf[BUFSZ]; char *tmp = (char *)0; +#endif Sprintf(eos(buf), " ("); #if defined(RUNTIME_PORT_ID) tmp = get_port_id(tmpbuf); if (tmp) Sprintf(eos(buf), "%s%s", c++ ? "," : "", tmp); +#endif +#if defined(NETHACK_GIT_SHA) + if (NetHack_git_sha) + Sprintf(eos(buf), "%s%s", c++ ? "," : "", NetHack_git_sha); +#endif +#if defined(NETHACK_GIT_BRANCH) + if (NetHack_git_branch) + Sprintf(eos(buf), "%s%s", c++ ? "," : "", NetHack_git_branch); #endif Sprintf(eos(buf), ")"); } @@ -130,6 +150,37 @@ doextversion() return 0; } +void early_version_info(pastebuf) +boolean pastebuf; +{ + char buf[BUFSZ], buf2[BUFSZ]; + char *tmp = getversionstring(buf); + + /* this is early enough that we have to do + our own line-splitting */ + if (tmp) { + tmp = strstri(buf," ("); + if (tmp) *tmp++ = '\0'; + } + + Sprintf(buf2, "%s\n", buf); + if (tmp) Sprintf(eos(buf2), "%s\n", tmp); + raw_printf("%s", buf2); + + if (pastebuf) { +#ifdef RUNTIME_PASTEBUF_SUPPORT + /* + * Call a platform/port-specific routine to insert the + * version information into a paste buffer. Useful for + * easy inclusion in bug reports. + */ + port_insert_pastebuf(buf2); +#else + raw_printf("%s", "Paste buffer copy is not available.\n"); +#endif + } +} + extern const char regex_id[]; /* diff --git a/sys/share/pcmain.c b/sys/share/pcmain.c index a18157639..64a175c14 100644 --- a/sys/share/pcmain.c +++ b/sys/share/pcmain.c @@ -329,6 +329,9 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ Strcpy(hackdir, HACKDIR); #endif if (argc > 1) { + if (argcheck(argc, argv, ARG_VERSION)) + nethack_exit(EXIT_SUCCESS); + if (!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/unix/Makefile.src b/sys/unix/Makefile.src index 451067a93..19f41ca81 100644 --- a/sys/unix/Makefile.src +++ b/sys/unix/Makefile.src @@ -1,5 +1,5 @@ # NetHack Makefile. -# NetHack 3.6 Makefile.src $NHDT-Date: 1459122529 2016/03/27 23:48:49 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.46 $ +# NetHack 3.6 Makefile.src $NHDT-Date: 1519228664 2018/02/21 15:57:44 $ $NHDT-Branch: githash $:$NHDT-Revision: 1.51 $ # Root of source tree: NHSROOT=.. @@ -610,6 +610,9 @@ tile.c: ../win/share/tilemap.c $(HACK_H) # hack.h depends on makedefs' output, so we know makedefs will be # up to date before being executed ../include/date.h: $(VERSOURCES) $(HACK_H) + if [[ ! -f ../dat/gitinfo.txt ]]; then \ + (cd ..;perl -IDEVEL/hooksdir -MNHgithook -e '&NHgithook::nhversioning') || true; \ + fi ../util/makedefs -v diff --git a/sys/unix/hints/macosx.sh b/sys/unix/hints/macosx.sh index 93e28ca51..c6cf10c31 100755 --- a/sys/unix/hints/macosx.sh +++ b/sys/unix/hints/macosx.sh @@ -1,5 +1,5 @@ #!/bin/sh -# NetHack 3.6 macosx.sh $NHDT-Date: 1518800856 2018/02/16 17:07:36 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.19 $ +# NetHack 3.6 macosx.sh $NHDT-Date: 1517231957 2018/01/29 13:19:17 $ $NHDT-Branch: githash $:$NHDT-Revision: 1.20 $ # Copyright (c) Kenneth Lorber, Kensington, Maryland, 2007. # NetHack may be freely redistributed. See license for details. # diff --git a/sys/unix/unixmain.c b/sys/unix/unixmain.c index b9ab44526..95e48cc14 100644 --- a/sys/unix/unixmain.c +++ b/sys/unix/unixmain.c @@ -110,6 +110,9 @@ char *argv[]; dir = nh_getenv("HACKDIR"); if (argc > 1) { + if (argcheck(argc, argv, ARG_VERSION)) + exit(EXIT_SUCCESS); + if (!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 @@ -720,4 +723,40 @@ get_login_name() return buf; } +#ifdef __APPLE__ +extern int errno; + +void +port_insert_pastebuf(buf) +char *buf; +{ + /* This should be replaced when there is a Cocoa port. */ + const char *errfmt; + size_t len; + FILE *PB = popen("/usr/bin/pbcopy","w"); + if(!PB){ + errfmt = "Unable to start pbcopy (%d)\n"; + goto error; + } + + len = strlen(buf); + /* Remove the trailing \n, carefully. */ + if(buf[len-1] == '\n') len--; + + /* XXX Sorry, I'm too lazy to write a loop for output this short. */ + if(len!=fwrite(buf,1,len,PB)){ + errfmt = "Error sending data to pbcopy (%d)\n"; + goto error; + } + + if(pclose(PB)!=-1){ + return; + } + errfmt = "Error finishing pbcopy (%d)\n"; + +error: + raw_printf(errfmt,strerror(errno)); +} +#endif + /*unixmain.c*/ diff --git a/sys/winnt/winnt.c b/sys/winnt/winnt.c index 842bfd036..cfd27acac 100644 --- a/sys/winnt/winnt.c +++ b/sys/winnt/winnt.c @@ -35,6 +35,9 @@ /* globals required within here */ HANDLE ffhandle = (HANDLE) 0; WIN32_FIND_DATA ffd; +typedef HWND(WINAPI *GETCONSOLEWINDOW)(); +static HWND GetConsoleHandle(void); +static HWND GetConsoleHwnd(void); /* The function pointer nt_kbhit contains a kbhit() equivalent * which varies depending on which window port is active. @@ -316,6 +319,119 @@ int interjection_type; msmsg(interjection_buf[interjection_type]); } +#ifdef RUNTIME_PASTEBUF_SUPPORT + +void port_insert_pastebuf(buf) +char *buf; +{ + /* This implementation will utilize the windows clipboard + * to accomplish this. + */ + + char *tmp = buf; + HWND hwndConsole = GetConsoleHandle(); + HGLOBAL hglbCopy; + WCHAR *w, w2[2]; + int cc, rc, abytes; + LPWSTR lpwstrCopy; + HANDLE hresult; + + if (!buf || (hwndConsole == NULL)) + return; + + cc = strlen(buf); + /* last arg=0 means "tell me the size of the buffer that I need" */ + rc = MultiByteToWideChar(GetConsoleOutputCP(), 0, buf, -1, w2, 0); + if (!rc) return; + + abytes = rc * sizeof(WCHAR); + w = (WCHAR *)alloc(abytes); + /* Housekeeping need: +free(w) */ + + rc = MultiByteToWideChar(GetConsoleOutputCP(), 0, buf, -1, w, rc); + if (!rc) { + free(w); + return; + } + if (!OpenClipboard(hwndConsole)) { + free(w); + return; + } + /* Housekeeping need: +CloseClipboard(), free(w) */ + + EmptyClipboard(); + + /* allocate global mem obj to hold the text */ + + hglbCopy = GlobalAlloc(GMEM_MOVEABLE, abytes); + if (hglbCopy == NULL) { + CloseClipboard(); + free(w); + return; + } + /* Housekeeping need: +GlobalFree(hglbCopy), CloseClipboard(), free(w) */ + + lpwstrCopy = (LPWSTR)GlobalLock(hglbCopy); + /* Housekeeping need: +GlobalUnlock(hglbCopy), GlobalFree(hglbCopy), + CloseClipboard(), free(w) */ + + memcpy(lpwstrCopy, w, abytes); + GlobalUnlock(hglbCopy); + /* Housekeeping need: GlobalFree(hglbCopy), CloseClipboard(), free(w) */ + + /* put it on the clipboard */ + hresult = SetClipboardData(CF_UNICODETEXT, hglbCopy); + if (!hresult) { + raw_printf("Error copying to clipboard.\n"); + GlobalFree(hglbCopy); /* only needed if clipboard didn't accept data */ + } + /* Housekeeping need: CloseClipboard(), free(w) */ + + CloseClipboard(); + free(w); + return; +} + +static HWND +GetConsoleHandle(void) +{ + HMODULE hMod = GetModuleHandle("kernel32.dll"); + GETCONSOLEWINDOW pfnGetConsoleWindow = + (GETCONSOLEWINDOW) GetProcAddress(hMod, "GetConsoleWindow"); + if (pfnGetConsoleWindow) + return pfnGetConsoleWindow(); + else + return GetConsoleHwnd(); +} + +static HWND +GetConsoleHwnd(void) +{ + int iterations = 0; + HWND hwndFound = 0; + char OldTitle[1024], NewTitle[1024], TestTitle[1024]; + + /* Get current window title */ + GetConsoleTitle(OldTitle, sizeof OldTitle); + + (void) sprintf(NewTitle, "NETHACK%d/%d", GetTickCount(), + GetCurrentProcessId()); + SetConsoleTitle(NewTitle); + + GetConsoleTitle(TestTitle, sizeof TestTitle); + while (strcmp(TestTitle, NewTitle) != 0) { + iterations++; + /* sleep(0); */ + GetConsoleTitle(TestTitle, sizeof TestTitle); + } + hwndFound = FindWindow(NULL, NewTitle); + SetConsoleTitle(OldTitle); + /* printf("%d iterations\n", iterations); */ + return hwndFound; +} + +#endif + #ifdef RUNTIME_PORT_ID /* * _M_IX86 is Defined for x86 processors. This is not defined for x64 diff --git a/util/makedefs.c b/util/makedefs.c index f3f7135be..2726816e8 100644 --- a/util/makedefs.c +++ b/util/makedefs.c @@ -72,6 +72,7 @@ static const char SCCS_Id[] = "@(#)makedefs.c\t3.6\t2016/02/12"; #define QTXT_O_FILE "quest.dat" #define VIS_TAB_H "vis_tab.h" #define VIS_TAB_C "vis_tab.c" +#define GITINFO_FILE "gitinfo.txt" /* locations for those files */ #ifdef AMIGA #define FILE_PREFIX @@ -177,6 +178,7 @@ static char *FDECL(bannerc_string, (char *, const char *)); static char *FDECL(xcrypt, (const char *)); static unsigned long FDECL(read_rumors_file, (const char *, int *, long *, unsigned long)); +static boolean FDECL(get_gitinfo, (char *, char *)); static void FDECL(do_rnd_access_file, (const char *)); static boolean FDECL(d_filter, (char *)); static boolean FDECL(h_filter, (char *)); @@ -209,6 +211,7 @@ static char *FDECL(fgetline, (FILE*)); static char *FDECL(tmpdup, (const char *)); static char *FDECL(limit, (char *, int)); static char *FDECL(eos, (char *)); +static int FDECL(case_insensitive_comp, (const char *, const char *)); /* input, output, tmp */ static FILE *ifp, *ofp, *tfp; @@ -1239,6 +1242,7 @@ do_date() #else time_t clocktim = 0; #endif + char githash[BUFSZ], gitbranch[BUFSZ]; char *c, cbuf[60], buf[BUFSZ]; const char *ul_sfx; @@ -1372,6 +1376,10 @@ do_date() Fprintf(ofp, "#define COPYRIGHT_BANNER_C \\\n \"%s\"\n", bannerc_string(buf, cbuf)); Fprintf(ofp, "\n"); + if (get_gitinfo(githash, gitbranch)) { + Fprintf(ofp, "#define NETHACK_GIT_SHA \"%s\"\n", githash); + Fprintf(ofp, "#define NETHACK_GIT_BRANCH \"%s\"\n", gitbranch); + } #ifdef AMIGA { struct tm *tm = localtime((time_t *) &clocktim); @@ -1386,6 +1394,84 @@ do_date() return; } +boolean +get_gitinfo(githash, gitbranch) +char *githash, *gitbranch; +{ + FILE *gifp; + size_t len; + char infile[600]; + char *line, *strval, *opt, *c, *end; + boolean havebranch = FALSE, havehash = FALSE; + + if (!githash || !gitbranch) return FALSE; + + Sprintf(infile, DATA_IN_TEMPLATE, GITINFO_FILE); + if (!(gifp = fopen(infile, RDTMODE))) { + /* perror(infile); */ + return FALSE; + } + + /* read the gitinfo file */ + while ((line = fgetline(gifp)) != 0) { + strval = index(line, '='); + if (strval && strlen(strval) < (BUFSZ-1)) { + opt = line; + *strval++ = '\0'; + /* strip off the '\n' */ + if ((c = index(strval, '\n')) != 0) + *c = '\0'; + if ((c = index(opt, '\n')) != 0) + *c = '\0'; + /* strip leading and trailing white space */ + while (*strval == ' ' || *strval == '\t') + strval++; + end = eos(strval); + while (--end >= strval && (*end == ' ' || *end == '\t')) + *end = '\0'; + while (*opt == ' ' || *opt == '\t') + opt++; + end = eos(opt); + while (--end >= opt && (*end == ' ' || *end == '\t')) + *end = '\0'; + + len = strlen(opt); + if ((len >= strlen("gitbranch")) && !case_insensitive_comp(opt, "gitbranch")) { + Strcpy(gitbranch, strval); + havebranch = TRUE; + } + if ((len >= strlen("githash")) && !case_insensitive_comp(opt, "githash")) { + Strcpy(githash, strval); + havehash = TRUE; + } + } + } + Fclose(gifp); + if (havebranch && havehash) + return TRUE; + return FALSE; +} + +static int +case_insensitive_comp(s1, s2) +const char *s1; +const char *s2; +{ + uchar u1, u2; + + for (;; s1++, s2++) { + u1 = (uchar) *s1; + if (isupper(u1)) + u1 = tolower(u1); + u2 = (uchar) *s2; + if (isupper(u2)) + u2 = tolower(u2); + if (u1 == '\0' || u1 != u2) + break; + } + return u1 - u2; +} + static char save_bones_compat_buf[BUFSZ]; static void