1 /* NetHack 3.6 version.c $NHDT-Date: 1552353060 2019/03/12 01:11:00 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.52 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Michael Allison, 2018. */
4 /* NetHack may be freely redistributed. See license for details. */
5
6 #include "hack.h"
7 #include "dlb.h"
8 #include "date.h"
9 /*
10 * All the references to the contents of patchlevel.h have been moved
11 * into makedefs....
12 */
13 #ifdef SHORT_FILENAMES
14 #include "patchlev.h"
15 #else
16 #include "patchlevel.h"
17 #endif
18
19 #if defined(NETHACK_GIT_SHA)
20 const char *NetHack_git_sha = NETHACK_GIT_SHA;
21 #endif
22 #if defined(NETHACK_GIT_BRANCH)
23 const char *NetHack_git_branch = NETHACK_GIT_BRANCH;
24 #endif
25
26 STATIC_DCL void FDECL(insert_rtoption, (char *));
27
28 /* fill buffer with short version (so caller can avoid including date.h) */
29 char *
version_string(buf)30 version_string(buf)
31 char *buf;
32 {
33 return strcpy(buf, VERSION_STRING);
34 }
35
36 /* fill and return the given buffer with the long nethack version string */
37 char *
getversionstring(buf)38 getversionstring(buf)
39 char *buf;
40 {
41 Strcpy(buf, VERSION_ID);
42
43 #if defined(RUNTIME_PORT_ID) \
44 || defined(NETHACK_GIT_SHA) || defined(NETHACK_GIT_BRANCH)
45 {
46 int c = 0;
47 #if defined(RUNTIME_PORT_ID)
48 char tmpbuf[BUFSZ], *tmp;
49 #endif
50 char *p = eos(buf);
51 boolean dotoff = (p > buf && p[-1] == '.');
52
53 if (dotoff)
54 --p;
55 Strcpy(p, " (");
56 #if defined(RUNTIME_PORT_ID)
57 tmp = get_port_id(tmpbuf);
58 if (tmp)
59 Sprintf(eos(buf), "%s%s", c++ ? "," : "", tmp);
60 #endif
61 #if defined(NETHACK_GIT_SHA)
62 if (NetHack_git_sha)
63 Sprintf(eos(buf), "%s%s", c++ ? "," : "", NetHack_git_sha);
64 #endif
65 #if defined(NETHACK_GIT_BRANCH)
66 #if (NH_DEVEL_STATUS != NH_STATUS_RELEASED)
67 if (NetHack_git_branch)
68 Sprintf(eos(buf), "%sbranch:%s",
69 c++ ? "," : "", NetHack_git_branch);
70 #endif
71 #endif
72 if (c)
73 Strcat(buf, ")");
74 else /* if nothing has been added, strip " (" back off */
75 *p = '\0';
76 if (dotoff)
77 Strcat(buf, ".");
78 }
79 #endif /* RUNTIME_PORT_ID || NETHACK_GIT_SHA || NETHACK_GIT_BRANCH */
80
81 return buf;
82 }
83
84 /* the 'v' command */
85 int
doversion()86 doversion()
87 {
88 char buf[BUFSZ];
89
90 pline("%s", getversionstring(buf));
91 return 0;
92 }
93
94 /* the '#version' command; also a choice for '?' */
95 int
doextversion()96 doextversion()
97 {
98 dlb *f;
99 char buf[BUFSZ], *p = 0;
100 winid win = create_nhwindow(NHW_TEXT);
101
102 /* instead of using ``display_file(OPTIONS_USED,TRUE)'' we handle
103 the file manually so we can include dynamic version info */
104
105 (void) getversionstring(buf);
106 /* if extra text (git info) is present, put it on separate line */
107 if (strlen(buf) >= COLNO)
108 p = rindex(buf, '(');
109 if (p && p > buf && p[-1] == ' ')
110 p[-1] = '\0';
111 else
112 p = 0;
113 putstr(win, 0, buf);
114 if (p) {
115 *--p = ' ';
116 putstr(win, 0, p);
117 }
118
119 f = dlb_fopen(OPTIONS_USED, "r");
120 if (!f) {
121 putstr(win, 0, "");
122 Sprintf(buf, "[Configuration '%s' not available?]", OPTIONS_USED);
123 putstr(win, 0, buf);
124 } else {
125 /*
126 * already inserted above:
127 * + outdented program name and version plus build date and time
128 * dat/options; display contents with lines prefixed by '-' deleted:
129 * - blank-line
130 * - indented program name and version
131 * blank-line
132 * outdented feature header
133 * - blank-line
134 * indented feature list
135 * spread over multiple lines
136 * blank-line
137 * outdented windowing header
138 * - blank-line
139 * indented windowing choices with
140 * optional second line for default
141 * - blank-line
142 * - EOF
143 */
144 boolean prolog = TRUE; /* to skip indented program name */
145
146 while (dlb_fgets(buf, BUFSZ, f)) {
147 (void) strip_newline(buf);
148 if (index(buf, '\t') != 0)
149 (void) tabexpand(buf);
150
151 if (*buf && *buf != ' ') {
152 /* found outdented header; insert a separator since we'll
153 have skipped corresponding blank line inside the file */
154 putstr(win, 0, "");
155 prolog = FALSE;
156 }
157 /* skip blank lines and prolog (progame name plus version) */
158 if (prolog || !*buf)
159 continue;
160
161 if (index(buf, ':'))
162 insert_rtoption(buf);
163
164 if (*buf)
165 putstr(win, 0, buf);
166 }
167 (void) dlb_fclose(f);
168 display_nhwindow(win, FALSE);
169 destroy_nhwindow(win);
170 }
171 return 0;
172 }
173
early_version_info(pastebuf)174 void early_version_info(pastebuf)
175 boolean pastebuf;
176 {
177 char buf[BUFSZ], buf2[BUFSZ];
178 char *tmp = getversionstring(buf);
179
180 /* this is early enough that we have to do
181 our own line-splitting */
182 if (tmp) {
183 tmp = strstri(buf," (");
184 if (tmp) *tmp++ = '\0';
185 }
186
187 Sprintf(buf2, "%s\n", buf);
188 if (tmp) Sprintf(eos(buf2), "%s\n", tmp);
189 raw_printf("%s", buf2);
190
191 if (pastebuf) {
192 #ifdef RUNTIME_PASTEBUF_SUPPORT
193 /*
194 * Call a platform/port-specific routine to insert the
195 * version information into a paste buffer. Useful for
196 * easy inclusion in bug reports.
197 */
198 port_insert_pastebuf(buf2);
199 #else
200 raw_printf("%s", "Paste buffer copy is not available.\n");
201 #endif
202 }
203 }
204
205 extern const char regex_id[];
206
207 /*
208 * makedefs should put the first token into dat/options; we'll substitute
209 * the second value for it. The token must contain at least one colon
210 * so that we can spot it, and should not contain spaces so that makedefs
211 * won't split it across lines. Ideally the length should be close to
212 * that of the substituted value since we don't do phrase-splitting/line-
213 * wrapping when displaying it.
214 */
215 static struct rt_opt {
216 const char *token, *value;
217 } rt_opts[] = {
218 { ":PATMATCH:", regex_id },
219 };
220
221 /*
222 * 3.6.0
223 * Some optional stuff is no longer available to makedefs because
224 * it depends which of several object files got linked into the
225 * game image, so we insert those options here.
226 */
227 STATIC_OVL void
insert_rtoption(buf)228 insert_rtoption(buf)
229 char *buf;
230 {
231 int i;
232
233 for (i = 0; i < SIZE(rt_opts); ++i) {
234 if (strstri(buf, rt_opts[i].token))
235 (void) strsubst(buf, rt_opts[i].token, rt_opts[i].value);
236 /* we don't break out of the loop after a match; there might be
237 other matches on the same line */
238 }
239 }
240
241 #ifdef MICRO
242 boolean
comp_times(filetime)243 comp_times(filetime)
244 long filetime;
245 {
246 /* BUILD_TIME is constant but might have L suffix rather than UL;
247 'filetime' is historically signed but ought to have been unsigned */
248 return (boolean) ((unsigned long) filetime < (unsigned long) BUILD_TIME);
249 }
250 #endif
251
252 boolean
check_version(version_data,filename,complain)253 check_version(version_data, filename, complain)
254 struct version_info *version_data;
255 const char *filename;
256 boolean complain;
257 {
258 if (
259 #ifdef VERSION_COMPATIBILITY
260 version_data->incarnation < VERSION_COMPATIBILITY
261 || version_data->incarnation > VERSION_NUMBER
262 #else
263 version_data->incarnation != VERSION_NUMBER
264 #endif
265 ) {
266 if (complain)
267 pline("Version mismatch for file \"%s\".", filename);
268 return FALSE;
269 } else if (
270 #ifndef IGNORED_FEATURES
271 version_data->feature_set != VERSION_FEATURES
272 #else
273 (version_data->feature_set & ~IGNORED_FEATURES)
274 != (VERSION_FEATURES & ~IGNORED_FEATURES)
275 #endif
276 || version_data->entity_count != VERSION_SANITY1
277 || version_data->struct_sizes1 != VERSION_SANITY2
278 || version_data->struct_sizes2 != VERSION_SANITY3) {
279 if (complain)
280 pline("Configuration incompatibility for file \"%s\".", filename);
281 return FALSE;
282 }
283 return TRUE;
284 }
285
286 /* this used to be based on file date and somewhat OS-dependant,
287 but now examines the initial part of the file's contents */
288 boolean
uptodate(fd,name)289 uptodate(fd, name)
290 int fd;
291 const char *name;
292 {
293 int rlen;
294 struct version_info vers_info;
295 boolean verbose = name ? TRUE : FALSE;
296
297 rlen = read(fd, (genericptr_t) &vers_info, sizeof vers_info);
298 minit(); /* ZEROCOMP */
299 if (rlen == 0) {
300 if (verbose) {
301 pline("File \"%s\" is empty?", name);
302 wait_synch();
303 }
304 return FALSE;
305 }
306 if (!check_version(&vers_info, name, verbose)) {
307 if (verbose)
308 wait_synch();
309 return FALSE;
310 }
311 return TRUE;
312 }
313
314 void
store_version(fd)315 store_version(fd)
316 int fd;
317 {
318 static const struct version_info version_data = {
319 VERSION_NUMBER, VERSION_FEATURES,
320 VERSION_SANITY1, VERSION_SANITY2, VERSION_SANITY3
321 };
322
323 bufoff(fd);
324 /* bwrite() before bufon() uses plain write() */
325 bwrite(fd, (genericptr_t) &version_data,
326 (unsigned) (sizeof version_data));
327 bufon(fd);
328 return;
329 }
330
331 #ifdef AMIGA
332 const char amiga_version_string[] = AMIGA_VERSION_STRING;
333 #endif
334
335 unsigned long
get_feature_notice_ver(str)336 get_feature_notice_ver(str)
337 char *str;
338 {
339 char buf[BUFSZ];
340 int ver_maj, ver_min, patch;
341 char *istr[3];
342 int j = 0;
343
344 if (!str)
345 return 0L;
346 str = strcpy(buf, str);
347 istr[j] = str;
348 while (*str) {
349 if (*str == '.') {
350 *str++ = '\0';
351 j++;
352 istr[j] = str;
353 if (j == 2)
354 break;
355 } else if (index("0123456789", *str) != 0) {
356 str++;
357 } else
358 return 0L;
359 }
360 if (j != 2)
361 return 0L;
362 ver_maj = atoi(istr[0]);
363 ver_min = atoi(istr[1]);
364 patch = atoi(istr[2]);
365 return FEATURE_NOTICE_VER(ver_maj, ver_min, patch);
366 /* macro from hack.h */
367 }
368
369 unsigned long
get_current_feature_ver()370 get_current_feature_ver()
371 {
372 return FEATURE_NOTICE_VER(VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL);
373 }
374
375 /*ARGUSED*/
376 const char *
copyright_banner_line(indx)377 copyright_banner_line(indx)
378 int indx;
379 {
380 #ifdef COPYRIGHT_BANNER_A
381 if (indx == 1)
382 return COPYRIGHT_BANNER_A;
383 #endif
384 #ifdef COPYRIGHT_BANNER_B
385 if (indx == 2)
386 return COPYRIGHT_BANNER_B;
387 #endif
388 #ifdef COPYRIGHT_BANNER_C
389 if (indx == 3)
390 return COPYRIGHT_BANNER_C;
391 #endif
392 #ifdef COPYRIGHT_BANNER_D
393 if (indx == 4)
394 return COPYRIGHT_BANNER_D;
395 #endif
396 return "";
397 }
398
399 /*version.c*/
400