From: nhmall Date: Mon, 29 Jan 2018 03:54:08 +0000 (-0500) Subject: Incorporate some git information into NetHack X-Git-Tag: NetHack-3.6.1_RC01~162^2~3 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=65655d2ceefa2eb7099b05c5034d72044b9b1176;p=nethack Incorporate some git information into NetHack Incorporate some git information into NetHack so that it is potentially visible to a player. That's useful when collecting details about the version that they are running and, if the gitinfo is present, it can tie the code to a specific git commit in the repository. This modifies 'makedefs -v' to check for the presence of a data file called dat/gitinfo.txt and if it is there, parse out its contents, then write additional lines to include/date.h beyond what 'makedefs -v' was previously putting in there, similar to this sample: #define NETHACK_GIT_SHA "0c84e564c78e2024e562d39539376ce2e21eec8e" #define NETHACK_GIT_BRANCH "NetHack-3.6.0" The contents of an appropriate dat/gitinfo.txt are as follows, and trailing/leading whitespace is not significant: githash = 0c84e564c78e2024e562d39539376ce2e21eec8e gitbranch = NetHack-3.6.0 It also adjusts the contents of the 'v' version information to include the additional git info when available. Also adds some hooks DEVEL/hooksdir and a perl file to DEVEL for simplifying and automating the deposit of dat/gitinfo.txt so that it generally reflects the most current git commit. DEVEL/gitinfo.pl can be used to build dat/gitinfo.txt at any time without doing a commit, merge, or checkout. perl DEVEL/gitinfo.pl command line --version and -version support To complement the extra information being provided in the version by the 'v' command, this also adds support for the following new command line arguments: --version -version Output the NetHack version string then exit. --version:paste Output the NetHack version string and also copy it to -version:paste the platform's paste buffer for insertion somewhere, then exit. If the paste variation of -version is requested on a platform that hasn't incorporated any support for the capability, it will deliver the version info then an error message, prior to exiting. To support the extended -version:paste variation, a port needs to: - provide a port-specific routine to perform the paste buffer copy in a port code file. - #define RUNTIME_PASTEBUF_SUPPORT in the include/portconf.h header file. --skeleton-- void port_insert_pastebuf(buf) char *buf; { /* insert code to copy the version info from buf into platform's paste buffer in a supported way */ } macosx and Windows have both added support for RUNTIME_PASTEBUF_SUPPORT --- diff --git a/DEVEL/gitinfo.pl b/DEVEL/gitinfo.pl new file mode 100644 index 000000000..b62428975 --- /dev/null +++ b/DEVEL/gitinfo.pl @@ -0,0 +1,26 @@ +#!/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"); +} +use NHgithook; + +&NHgithook::nhversioning; diff --git a/DEVEL/hooksdir/NHgithook.pm b/DEVEL/hooksdir/NHgithook.pm index 6024c1c03..1bb92cf7e 100644 --- a/DEVEL/hooksdir/NHgithook.pm +++ b/DEVEL/hooksdir/NHgithook.pm @@ -60,6 +60,36 @@ 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; + + 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; + } + 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"; + } +} + # 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/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..6b38a68ba 100644 --- a/doc/nethack.6 +++ b/doc/nethack.6 @@ -55,6 +55,9 @@ nethack \- Exploring The Mazes of Menace [ .I playernames ] +[ +.B \-\-version +] .ad .hy 14 .\" Make sure path is not hyphenated below @@ -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/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..789c5d48f 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -737,5 +737,87 @@ 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, *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..514665663 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: 1517140532 2018/01/28 11:55:32 $ $NHDT-Branch: nhmall-githash3 $:$NHDT-Revision: 1.50 $ */ /* 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,34 @@ 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) { int c = 0; +#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 +148,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/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