OSDN Git Service

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