538 lines
14 KiB
C
538 lines
14 KiB
C
/* NetHack 3.6 version.c $NHDT-Date: 1575161965 2019/12/01 00:59:25 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.69 $ */
|
|
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
|
|
/*-Copyright (c) Michael Allison, 2018. */
|
|
/* NetHack may be freely redistributed. See license for details. */
|
|
|
|
#include "hack.h"
|
|
#include "dlb.h"
|
|
#include "date.h"
|
|
|
|
/*
|
|
* All the references to the contents of patchlevel.h have been moved
|
|
* into makedefs....
|
|
*/
|
|
#ifdef SHORT_FILENAMES
|
|
#include "patchlev.h"
|
|
#else
|
|
#include "patchlevel.h"
|
|
#endif
|
|
|
|
#if defined(CROSSCOMPILE)
|
|
struct cross_target_s cross_target = {
|
|
/* https://groups.google.com/forum/#!original/
|
|
comp.sources.games/91SfKYg_xzI/dGnR3JnspFkJ */
|
|
"Tue, 28-Jul-87 13:18:57 EDT",
|
|
"Version 1.0, built Jul 28 13:18:57 1987.",
|
|
"0000000000000000000000000000000000000000",
|
|
"master",
|
|
"1.0.0-0",
|
|
"NetHack Version 1.0.0-0 - last build Tue Jul 28 13:18:57 1987.",
|
|
0x01010000UL,
|
|
0x00000000UL,
|
|
0x00000000UL,
|
|
0x00000000UL,
|
|
0x00000000UL,
|
|
0x00000000UL,
|
|
554476737UL,
|
|
};
|
|
#endif /* CROSSCOMPILE */
|
|
|
|
#if defined(NETHACK_GIT_SHA)
|
|
const char *NetHack_git_sha
|
|
#if !defined(CROSSCOMPILE) || (defined(CROSSCOMPILE) && defined(CROSSCOMPILE_HOST))
|
|
= NETHACK_GIT_SHA
|
|
#else
|
|
#ifdef NETHACK_HOST_GIT_SHA
|
|
= NETHACK_HOST_GIT_SHA
|
|
#endif
|
|
#endif
|
|
;
|
|
#endif
|
|
|
|
#if defined(NETHACK_GIT_BRANCH)
|
|
const char *NetHack_git_branch
|
|
#if !defined(CROSSCOMPILE) || (defined(CROSSCOMPILE) && defined(CROSSCOMPILE_HOST))
|
|
= NETHACK_GIT_BRANCH
|
|
#else
|
|
#ifdef NETHACK_HOST_GIT_BRANCH
|
|
= NETHACK_HOST_GIT_BRANCH
|
|
#endif
|
|
#endif
|
|
;
|
|
#endif
|
|
|
|
static void FDECL(insert_rtoption, (char *));
|
|
|
|
/* fill buffer with short version (so caller can avoid including date.h) */
|
|
char *
|
|
version_string(buf)
|
|
char *buf;
|
|
{
|
|
return strcpy(buf, VERSION_STRING);
|
|
}
|
|
|
|
/* fill and return the given buffer with the long nethack version string */
|
|
char *
|
|
getversionstring(buf)
|
|
char *buf;
|
|
{
|
|
Strcpy(buf, VERSION_ID);
|
|
|
|
#if defined(RUNTIME_PORT_ID) \
|
|
|| defined(NETHACK_GIT_SHA) || defined(NETHACK_GIT_BRANCH)
|
|
{
|
|
int c = 0;
|
|
#if defined(RUNTIME_PORT_ID)
|
|
char tmpbuf[BUFSZ], *tmp;
|
|
#endif
|
|
char *p = eos(buf);
|
|
boolean dotoff = (p > buf && p[-1] == '.');
|
|
|
|
if (dotoff)
|
|
--p;
|
|
Strcpy(p, " (");
|
|
#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 (NH_DEVEL_STATUS != NH_STATUS_RELEASED)
|
|
if (NetHack_git_branch)
|
|
Sprintf(eos(buf), "%sbranch:%s",
|
|
c++ ? "," : "", NetHack_git_branch);
|
|
#endif
|
|
#endif
|
|
if (c)
|
|
Strcat(buf, ")");
|
|
else /* if nothing has been added, strip " (" back off */
|
|
*p = '\0';
|
|
if (dotoff)
|
|
Strcat(buf, ".");
|
|
}
|
|
#endif /* RUNTIME_PORT_ID || NETHACK_GIT_SHA || NETHACK_GIT_BRANCH */
|
|
|
|
return buf;
|
|
}
|
|
|
|
/* the 'v' command */
|
|
int
|
|
doversion()
|
|
{
|
|
char buf[BUFSZ];
|
|
|
|
pline("%s", getversionstring(buf));
|
|
return 0;
|
|
}
|
|
|
|
/* the '#version' command; also a choice for '?' */
|
|
int
|
|
doextversion()
|
|
{
|
|
int rtcontext = 0;
|
|
const char *rtbuf;
|
|
dlb *f = (dlb *) 0;
|
|
char buf[BUFSZ], *p = 0;
|
|
winid win = create_nhwindow(NHW_TEXT);
|
|
boolean use_dlb = TRUE,
|
|
done_rt = FALSE,
|
|
done_dlb = FALSE,
|
|
prolog;
|
|
#if 0 /* moved to util/mdlib.c and rendered via do_runtime_info() */
|
|
const char *lua_info[] = {
|
|
"About Lua: Copyright (c) 1994-2017 Lua.org, PUC-Rio.",
|
|
/* 1 2 3 4 5 6 7
|
|
1234567890123456789012345678901234567890123456789012345678901234567890123456789
|
|
*/
|
|
" \"Permission is hereby granted, free of charge, to any person obtaining",
|
|
" a copy of this software and associated documentation files (the ",
|
|
" \"Software\"), to deal in the Software without restriction including",
|
|
" without limitation the rights to use, copy, modify, merge, publish,",
|
|
" distribute, sublicense, and/or sell copies of the Software, and to ",
|
|
" permit persons to whom the Software is furnished to do so, subject to",
|
|
" the following conditions:",
|
|
" The above copyright notice and this permission notice shall be",
|
|
" included in all copies or substantial portions of the Software.\"",
|
|
(const char *) 0
|
|
};
|
|
#endif /*0*/
|
|
#if defined(OPTIONS_AT_RUNTIME) || defined(CROSSCOMPILE_TARGET)
|
|
use_dlb = FALSE;
|
|
#else
|
|
done_rt = TRUE;
|
|
#endif
|
|
|
|
/* instead of using ``display_file(OPTIONS_USED,TRUE)'' we handle
|
|
the file manually so we can include dynamic version info */
|
|
|
|
(void) getversionstring(buf);
|
|
/* if extra text (git info) is present, put it on separate line */
|
|
if (strlen(buf) >= COLNO)
|
|
p = rindex(buf, '(');
|
|
if (p && p > buf && p[-1] == ' ')
|
|
p[-1] = '\0';
|
|
else
|
|
p = 0;
|
|
putstr(win, 0, buf);
|
|
if (p) {
|
|
*--p = ' ';
|
|
putstr(win, 0, p);
|
|
}
|
|
|
|
if (use_dlb) {
|
|
f = dlb_fopen(OPTIONS_USED, "r");
|
|
if (!f) {
|
|
putstr(win, 0, "");
|
|
Sprintf(buf, "[Configuration '%s' not available?]", OPTIONS_USED);
|
|
putstr(win, 0, buf);
|
|
done_dlb = TRUE;
|
|
}
|
|
}
|
|
/*
|
|
* already inserted above:
|
|
* + outdented program name and version plus build date and time
|
|
* dat/options; display contents with lines prefixed by '-' deleted:
|
|
* - blank-line
|
|
* - indented program name and version
|
|
* blank-line
|
|
* outdented feature header
|
|
* - blank-line
|
|
* indented feature list
|
|
* spread over multiple lines
|
|
* blank-line
|
|
* outdented windowing header
|
|
* - blank-line
|
|
* indented windowing choices with
|
|
* optional second line for default
|
|
* - blank-line
|
|
* - EOF
|
|
*/
|
|
|
|
prolog = TRUE; /* to skip indented program name */
|
|
for (;;) {
|
|
if (use_dlb && !done_dlb) {
|
|
if (!dlb_fgets(buf, BUFSZ, f)) {
|
|
done_dlb = TRUE;
|
|
continue;
|
|
}
|
|
} else if (!done_rt) {
|
|
if (!(rtbuf = do_runtime_info(&rtcontext))) {
|
|
done_rt = TRUE;
|
|
continue;
|
|
}
|
|
(void) strncpy(buf, rtbuf, BUFSZ - 1);
|
|
buf[BUFSZ - 1] = '\0';
|
|
} else {
|
|
break;
|
|
}
|
|
(void) strip_newline(buf);
|
|
if (index(buf, '\t') != 0)
|
|
(void) tabexpand(buf);
|
|
|
|
if (*buf && *buf != ' ') {
|
|
/* found outdented header; insert a separator since we'll
|
|
have skipped corresponding blank line inside the file */
|
|
putstr(win, 0, "");
|
|
prolog = FALSE;
|
|
}
|
|
/* skip blank lines and prolog (progame name plus version) */
|
|
if (prolog || !*buf)
|
|
continue;
|
|
|
|
if (index(buf, ':'))
|
|
insert_rtoption(buf);
|
|
|
|
if (*buf)
|
|
putstr(win, 0, buf);
|
|
}
|
|
if (use_dlb)
|
|
(void) dlb_fclose(f);
|
|
display_nhwindow(win, FALSE);
|
|
destroy_nhwindow(win);
|
|
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[];
|
|
|
|
/*
|
|
* makedefs should put the first token into dat/options; we'll substitute
|
|
* the second value for it. The token must contain at least one colon
|
|
* so that we can spot it, and should not contain spaces so that makedefs
|
|
* won't split it across lines. Ideally the length should be close to
|
|
* that of the substituted value since we don't do phrase-splitting/line-
|
|
* wrapping when displaying it.
|
|
*/
|
|
static struct rt_opt {
|
|
const char *token, *value;
|
|
} rt_opts[] = {
|
|
{ ":PATMATCH:", regex_id },
|
|
{ ":LUAVERSION:", (const char *) g.lua_ver },
|
|
{ ":LUACOPYRIGHT:", (const char *) g.lua_copyright },
|
|
};
|
|
|
|
/*
|
|
* 3.6.0
|
|
* Some optional stuff is no longer available to makedefs because
|
|
* it depends which of several object files got linked into the
|
|
* game image, so we insert those options here.
|
|
*/
|
|
static void
|
|
insert_rtoption(buf)
|
|
char *buf;
|
|
{
|
|
int i;
|
|
|
|
if (!g.lua_ver[0])
|
|
get_lua_version();
|
|
|
|
for (i = 0; i < SIZE(rt_opts); ++i) {
|
|
if (strstri(buf, rt_opts[i].token) && *rt_opts[i].value) {
|
|
(void) strsubst(buf, rt_opts[i].token, rt_opts[i].value);
|
|
}
|
|
/* we don't break out of the loop after a match; there might be
|
|
other matches on the same line */
|
|
}
|
|
}
|
|
|
|
#ifdef MICRO
|
|
boolean
|
|
comp_times(filetime)
|
|
long filetime;
|
|
{
|
|
/* BUILD_TIME is constant but might have L suffix rather than UL;
|
|
'filetime' is historically signed but ought to have been unsigned */
|
|
return (boolean) ((unsigned long) filetime < (unsigned long) BUILD_TIME);
|
|
}
|
|
#endif
|
|
|
|
boolean
|
|
check_version(version_data, filename, complain, utdflags)
|
|
struct version_info *version_data;
|
|
const char *filename;
|
|
boolean complain;
|
|
unsigned long utdflags;
|
|
{
|
|
if (
|
|
#ifdef VERSION_COMPATIBILITY
|
|
version_data->incarnation < VERSION_COMPATIBILITY
|
|
|| version_data->incarnation > VERSION_NUMBER
|
|
#else
|
|
version_data->incarnation != VERSION_NUMBER
|
|
#endif
|
|
) {
|
|
if (complain)
|
|
pline("Version mismatch for file \"%s\".", filename);
|
|
return FALSE;
|
|
} else if (
|
|
#ifndef IGNORED_FEATURES
|
|
version_data->feature_set != VERSION_FEATURES
|
|
#else
|
|
(version_data->feature_set & ~IGNORED_FEATURES)
|
|
!= (VERSION_FEATURES & ~IGNORED_FEATURES)
|
|
#endif
|
|
|| ((utdflags & UTD_SKIP_SANITY1) == 0
|
|
&& version_data->entity_count != VERSION_SANITY1)
|
|
|| ((utdflags & UTD_CHECKSIZES) &&
|
|
(version_data->struct_sizes1 != VERSION_SANITY2))
|
|
|| ((utdflags & UTD_CHECKSIZES) &&
|
|
(version_data->struct_sizes2 != VERSION_SANITY3))) {
|
|
if (complain)
|
|
pline("Configuration incompatibility for file \"%s\".", filename);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/* this used to be based on file date and somewhat OS-dependant,
|
|
but now examines the initial part of the file's contents */
|
|
boolean
|
|
uptodate(nhfp, name, utdflags)
|
|
NHFILE *nhfp;
|
|
const char *name;
|
|
unsigned long utdflags;
|
|
{
|
|
int rlen = 0, cmc = 0, filecmc = 0;
|
|
struct version_info vers_info;
|
|
boolean verbose = name ? TRUE : FALSE;
|
|
char indicator;
|
|
|
|
if (nhfp->structlevel) {
|
|
rlen = read(nhfp->fd, (genericptr_t) &indicator, sizeof indicator);
|
|
rlen = read(nhfp->fd, (genericptr_t) &filecmc, sizeof filecmc);
|
|
if (rlen == 0)
|
|
return FALSE;
|
|
}
|
|
if (cmc != filecmc)
|
|
return FALSE;
|
|
|
|
rlen = read(nhfp->fd, (genericptr_t) &vers_info, sizeof vers_info);
|
|
minit(); /* ZEROCOMP */
|
|
if (rlen == 0) {
|
|
if (verbose) {
|
|
pline("File \"%s\" is empty?", name);
|
|
wait_synch();
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
if (!check_version(&vers_info, name, verbose, utdflags)) {
|
|
if (verbose)
|
|
wait_synch();
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
store_formatindicator(nhfp)
|
|
NHFILE *nhfp;
|
|
{
|
|
char indicate = 'u';
|
|
int cmc = 0;
|
|
|
|
if (nhfp->mode & WRITING) {
|
|
if (nhfp->structlevel) {
|
|
indicate = 'h'; /* historical */
|
|
bwrite(nhfp->fd, (genericptr_t) &indicate, sizeof indicate);
|
|
bwrite(nhfp->fd, (genericptr_t) &cmc, sizeof cmc);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
store_version(nhfp)
|
|
NHFILE *nhfp;
|
|
{
|
|
#if !defined(CROSSCOMPILE) || defined(CROSSCOMPILE_HOST)
|
|
static const struct version_info version_data = {
|
|
VERSION_NUMBER, VERSION_FEATURES,
|
|
VERSION_SANITY1, VERSION_SANITY2, VERSION_SANITY3
|
|
#else
|
|
struct version_info version_data = {
|
|
0UL,0UL,0UL,0UL,0Ul
|
|
#endif
|
|
};
|
|
|
|
#if defined(CROSSCOMPILE) && !defined(CROSSCOMPILE_HOST)
|
|
version_data.incarnation = VERSION_NUMBER; /* actual version number */
|
|
version_data.feature_set = VERSION_FEATURES; /* bitmask of config settings */
|
|
version_data.entity_count = VERSION_SANITY1; /* # of monsters and objects */
|
|
version_data.struct_sizes1 = VERSION_SANITY2; /* size of key structs */
|
|
version_data.struct_sizes2 = VERSION_SANITY3; /* size of more key structs */
|
|
#endif
|
|
if (nhfp->structlevel) {
|
|
bufoff(nhfp->fd);
|
|
/* bwrite() before bufon() uses plain write() */
|
|
store_formatindicator(nhfp);
|
|
bwrite(nhfp->fd,(genericptr_t) &version_data,
|
|
(unsigned) (sizeof version_data));
|
|
bufon(nhfp->fd);
|
|
}
|
|
return;
|
|
}
|
|
|
|
#ifdef AMIGA
|
|
const char amiga_version_string[] = AMIGA_VERSION_STRING;
|
|
#endif
|
|
|
|
unsigned long
|
|
get_feature_notice_ver(str)
|
|
char *str;
|
|
{
|
|
char buf[BUFSZ];
|
|
int ver_maj, ver_min, patch;
|
|
char *istr[3];
|
|
int j = 0;
|
|
|
|
if (!str)
|
|
return 0L;
|
|
str = strcpy(buf, str);
|
|
istr[j] = str;
|
|
while (*str) {
|
|
if (*str == '.') {
|
|
*str++ = '\0';
|
|
j++;
|
|
istr[j] = str;
|
|
if (j == 2)
|
|
break;
|
|
} else if (index("0123456789", *str) != 0) {
|
|
str++;
|
|
} else
|
|
return 0L;
|
|
}
|
|
if (j != 2)
|
|
return 0L;
|
|
ver_maj = atoi(istr[0]);
|
|
ver_min = atoi(istr[1]);
|
|
patch = atoi(istr[2]);
|
|
return FEATURE_NOTICE_VER(ver_maj, ver_min, patch);
|
|
/* macro from hack.h */
|
|
}
|
|
|
|
unsigned long
|
|
get_current_feature_ver()
|
|
{
|
|
return FEATURE_NOTICE_VER(VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL);
|
|
}
|
|
|
|
/*ARGUSED*/
|
|
const char *
|
|
copyright_banner_line(indx)
|
|
int indx;
|
|
{
|
|
#ifdef COPYRIGHT_BANNER_A
|
|
if (indx == 1)
|
|
return COPYRIGHT_BANNER_A;
|
|
#endif
|
|
#ifdef COPYRIGHT_BANNER_B
|
|
if (indx == 2)
|
|
return COPYRIGHT_BANNER_B;
|
|
#endif
|
|
#ifdef COPYRIGHT_BANNER_C
|
|
if (indx == 3)
|
|
return COPYRIGHT_BANNER_C;
|
|
#endif
|
|
#ifdef COPYRIGHT_BANNER_D
|
|
if (indx == 4)
|
|
return COPYRIGHT_BANNER_D;
|
|
#endif
|
|
return "";
|
|
}
|
|
|
|
/*version.c*/
|