1 /* NetHack 3.7 mdlib.c $NHDT-Date: 1608933420 2020/12/25 21:57:00 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.17 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /*-Copyright (c) Kenneth Lorber, Kensington, Maryland, 2015. */
4 /* Copyright (c) M. Stephenson, 1990, 1991. */
5 /* Copyright (c) Dean Luick, 1990. */
6 /* NetHack may be freely redistributed. See license for details. */
7
8 /*
9 * This can be linked into a binary to provide the functionality
10 * via the contained functions, or it can be #included directly
11 * into util/makedefs.c to provide it there.
12 */
13
14 #ifndef MAKEDEFS_C
15 #define MDLIB_C
16 #include "config.h"
17 #ifdef MONITOR_HEAP
18 #undef free /* makedefs, mdlib don't use the alloc and free in src/alloc.c */
19 #endif
20 #include "permonst.h"
21 #include "objclass.h"
22 #include "monsym.h"
23 #include "artilist.h"
24 #include "dungeon.h"
25 #include "obj.h"
26 #include "monst.h"
27 #include "you.h"
28 #include "context.h"
29 #include "flag.h"
30 #include "dlb.h"
31 #include <ctype.h>
32 /* version information */
33 #ifdef SHORT_FILENAMES
34 #include "patchlev.h"
35 #else
36 #include "patchlevel.h"
37 #endif
38 #define Fprintf (void) fprintf
39 #define Fclose (void) fclose
40 #define Unlink (void) unlink
41 #if !defined(AMIGA) || defined(AZTEC_C)
42 #define rewind(fp) fseek((fp), 0L, SEEK_SET) /* guarantee a return value */
43 #endif /* AMIGA || AZTEC_C */
44 #else
45 #ifndef GLOBAL_H
46 #include "global.h"
47 #endif
48 #endif /* !MAKEDEFS_C */
49
50 /* shorten up some lines */
51 #if defined(CROSSCOMPILE_TARGET) || defined(OPTIONS_AT_RUNTIME)
52 #define FOR_RUNTIME
53 #endif
54
55 #if defined(MAKEDEFS_C) || defined(FOR_RUNTIME)
56 /* REPRODUCIBLE_BUILD will change this to TRUE */
57 static boolean date_via_env = FALSE;
58
59 static char *version_string(char *, const char *);
60 static char *version_id_string(char *, const char *);
61 static char *bannerc_string(char *, const char *);
62
63 static void make_version(void);
64 static char *eos(char *);
65 #if 0
66 static char *mdlib_strsubst(char *, const char *, const char *);
67 #endif
68
69 #ifndef HAS_NO_MKSTEMP
70 #ifdef _MSC_VER
71 static int mkstemp(char *);
72 #endif
73 #endif
74 #endif /* MAKEDEFS_C || FOR_RUNTIME */
75
76 #if defined(MAKEDEFS_C) || defined(FOR_RUNTIME) || defined(WIN32) \
77 || (defined(CROSSCOMPILE_TARGET) && defined(__DATE__) && defined(__TIME__))
78 static int case_insensitive_comp(const char *, const char *);
79 #endif
80
81 #if !defined(MAKEDEFS_C) && defined(WIN32)
82 extern int GUILaunched;
83 #endif
84
85 /* these two are in extern.h but we don't include hack.h */
86 void runtime_info_init(void);
87 const char *do_runtime_info(int *);
88
89 void build_options(void);
90 static int count_and_validate_winopts(void);
91 static void opt_out_words(char *, int *);
92 static void build_savebones_compat_string(void);
93 static int idxopttext, done_runtime_opt_init_once = 0;
94 #define MAXOPT 40
95 #if !defined(MAKEDEFS_C) && defined(CROSSCOMPILE_TARGET) \
96 && defined(__DATE__) && defined(__TIME__)
97 static char rttimebuf[MAXOPT];
98 #endif
99 static char *opttext[120] = { 0 };
100 char optbuf[BUFSZ];
101 static struct version_info version;
102 static const char opt_indent[] = " ";
103
104 struct win_info {
105 const char *id, /* DEFAULT_WINDOW_SYS string */
106 *name; /* description, often same as id */
107 boolean valid;
108 };
109
110 static struct win_info window_opts[] = {
111 #ifdef TTY_GRAPHICS
112 { "tty",
113 /* testing 'USE_TILES' here would bring confusion because it could
114 apply to another interface such as X11, so check MSDOS explicitly
115 instead; even checking TTY_TILES_ESCCODES would probably be
116 confusing to most users (and it will already be listed separately
117 in the compiled options section so users aware of it can find it) */
118 #ifdef MSDOS
119 "traditional text with optional 'tiles' graphics",
120 #else
121 /* assume that one or more of IBMgraphics, DECgraphics, or MACgraphics
122 can be enabled; we can't tell from here whether that is accurate */
123 "traditional text with optional line-drawing",
124 #endif
125 TRUE
126 },
127 #endif /*TTY_GRAPHICS */
128 #ifdef CURSES_GRAPHICS
129 { "curses", "terminal-based graphics", TRUE },
130 #endif
131 #ifdef X11_GRAPHICS
132 { "X11", "X11", TRUE },
133 #endif
134 #ifdef QT_GRAPHICS /* too vague; there are multiple incompatible versions */
135 { "Qt", "Qt", TRUE },
136 #endif
137 #ifdef MSWIN_GRAPHICS /* win32 */
138 { "mswin", "Windows GUI", TRUE },
139 #endif
140 #ifdef SHIM_GRAPHICS
141 { "shim", "NetHack Library Windowing Shim", TRUE },
142 #endif
143
144 #if 0 /* remainder have been retired */
145 #ifdef GNOME_GRAPHICS /* unmaintained/defunct */
146 { "Gnome", "Gnome", TRUE },
147 #endif
148 #ifdef MAC /* defunct OS 9 interface */
149 { "mac", "Mac", TRUE },
150 #endif
151 #ifdef AMIGA_INTUITION /* unmaintained/defunct */
152 { "amii", "Amiga Intuition", TRUE },
153 #endif
154 #ifdef GEM_GRAPHICS /* defunct Atari interface */
155 { "Gem", "Gem", TRUE },
156 #endif
157 #ifdef BEOS_GRAPHICS /* unmaintained/defunct */
158 { "BeOS", "BeOS InterfaceKit", TRUE },
159 #endif
160 #endif /* 0 => retired */
161 { 0, 0, FALSE }
162 };
163
164 /*
165 * Use this to explicitly mask out features during version checks.
166 *
167 * ZEROCOMP, RLECOMP, and ZLIB_COMP describe compression features
168 * that the port/plaform which wrote the savefile was capable of
169 * dealing with. Don't reject a savefile just because the port
170 * reading the savefile doesn't match on all/some of them.
171 * The actual compression features used to produce the savefile are
172 * recorded in the savefile_info structure immediately following the
173 * version_info, and that is what needs to be checked against the
174 * feature set of the port that is reading the savefile back in.
175 * That check is done in src/restore.c now.
176 *
177 */
178 #ifndef MD_IGNORED_FEATURES
179 #define MD_IGNORED_FEATURES \
180 (0L | (1L << 19) /* SCORE_ON_BOTL */ \
181 | (1L << 27) /* ZEROCOMP */ \
182 | (1L << 28) /* RLECOMP */ \
183 )
184 #endif /* MD_IGNORED_FEATUES */
185
186 static void
make_version(void)187 make_version(void)
188 {
189 register int i;
190
191 /*
192 * integer version number
193 */
194 version.incarnation = ((unsigned long) VERSION_MAJOR << 24)
195 | ((unsigned long) VERSION_MINOR << 16)
196 | ((unsigned long) PATCHLEVEL << 8)
197 | ((unsigned long) EDITLEVEL);
198 /*
199 * encoded feature list
200 * Note: if any of these magic numbers are changed or reassigned,
201 * EDITLEVEL in patchlevel.h should be incremented at the same time.
202 * The actual values have no special meaning, and the category
203 * groupings are just for convenience.
204 */
205 version.feature_set = (unsigned long) (0L
206 /* levels and/or topology (0..4) */
207 /* monsters (5..9) */
208 #ifdef MAIL_STRUCTURES
209 | (1L << 6)
210 #endif
211 /* objects (10..14) */
212 /* flag bits and/or other global variables (15..26) */
213 #ifdef TEXTCOLOR
214 | (1L << 17)
215 #endif
216 #ifdef INSURANCE
217 | (1L << 18)
218 #endif
219 #ifdef SCORE_ON_BOTL
220 | (1L << 19)
221 #endif
222 /* data format (27..31)
223 * External compression methods such as COMPRESS and ZLIB_COMP
224 * do not affect the contents and are thus excluded from here */
225 #ifdef ZEROCOMP
226 | (1L << 27)
227 #endif
228 #ifdef RLECOMP
229 | (1L << 28)
230 #endif
231 );
232 /*
233 * Value used for object & monster sanity check.
234 * (NROFARTIFACTS<<24) | (NUM_OBJECTS<<12) | (NUMMONS<<0)
235 */
236 for (i = 1; artifact_names[i]; i++)
237 continue;
238 version.entity_count = (unsigned long) (i - 1);
239 for (i = 1; objects[i].oc_class != ILLOBJ_CLASS; i++)
240 continue;
241 version.entity_count = (version.entity_count << 12) | (unsigned long) i;
242 for (i = 0; mons[i].mlet; i++)
243 continue;
244 version.entity_count = (version.entity_count << 12) | (unsigned long) i;
245 /*
246 * Value used for compiler (word size/field alignment/padding) check.
247 */
248 version.struct_sizes1 =
249 (((unsigned long) sizeof(struct context_info) << 24)
250 | ((unsigned long) sizeof(struct obj) << 17)
251 | ((unsigned long) sizeof(struct monst) << 10)
252 | ((unsigned long) sizeof(struct you)));
253 version.struct_sizes2 = (((unsigned long) sizeof(struct flag) << 10));
254 /* free bits in here */
255 return;
256 }
257
258 #if defined(MAKEDEFS_C) || defined(FOR_RUNTIME)
259
260 static char *
version_string(char * outbuf,const char * delim)261 version_string(char *outbuf, const char *delim)
262 {
263 Sprintf(outbuf, "%d%s%d", VERSION_MAJOR, delim, VERSION_MINOR);
264 #if (NH_DEVEL_STATUS != NH_STATUS_RELEASED)
265 Sprintf(eos(outbuf), "-%d", EDITLEVEL);
266 #endif
267 return outbuf;
268 }
269
270 static char *
version_id_string(char * outbuf,const char * build_date)271 version_id_string(char *outbuf, const char *build_date)
272 {
273 char subbuf[64], versbuf[64];
274 char statusbuf[64];
275
276 #if (NH_DEVEL_STATUS != NH_STATUS_RELEASED)
277 #if (NH_DEVEL_STATUS == NH_STATUS_BETA)
278 Strcpy(statusbuf, " Beta");
279 #else
280 #if (NH_DEVEL_STATUS == NH_STATUS_WIP)
281 Strcpy(statusbuf, " Work-in-progress");
282 #else
283 Strcpy(statusbuf, " post-release");
284 #endif
285 #endif
286 #else
287 statusbuf[0] = '\0';
288 #endif
289 subbuf[0] = '\0';
290 #ifdef PORT_SUB_ID
291 subbuf[0] = ' ';
292 Strcpy(&subbuf[1], PORT_SUB_ID);
293 #endif
294
295 Sprintf(outbuf, "%s xNetHack%s Version %s%s - last %s %s.", PORT_ID,
296 subbuf, version_string(versbuf, "."), statusbuf,
297 date_via_env ? "revision" : "build", build_date);
298 return outbuf;
299 }
300
301 /* still within #if MAKDEFS_C || FOR_RUNTIME */
302
303 static char *
bannerc_string(char * outbuf,const char * build_date)304 bannerc_string(char *outbuf, const char *build_date)
305 {
306 char subbuf[64], versbuf[64];
307
308 subbuf[0] = '\0';
309 #ifdef PORT_SUB_ID
310 subbuf[0] = ' ';
311 Strcpy(&subbuf[1], PORT_SUB_ID);
312 #endif
313 #if (NH_DEVEL_STATUS != NH_STATUS_RELEASED)
314 #if (NH_DEVEL_STATUS == NH_STATUS_BETA)
315 Strcat(subbuf, " Beta");
316 #else
317 Strcat(subbuf, " Work-in-progress");
318 #endif
319 #endif
320
321 Sprintf(outbuf, " Version %s %s%s, %s %s.",
322 version_string(versbuf, "."), PORT_ID, subbuf,
323 date_via_env ? "revised" : "built", &build_date[4]);
324 #if 0
325 Sprintf(outbuf, "%s NetHack%s %s Copyright 1985-%s (built %s)",
326 PORT_ID, subbuf, version_string(versbuf,"."), RELEASE_YEAR,
327 &build_date[4]);
328 #endif
329 return outbuf;
330 }
331
332 #ifndef HAS_NO_MKSTEMP
333 #ifdef _MSC_VER
334 int
mkstemp(char * template)335 mkstemp(char *template)
336 {
337 int err;
338
339 err = _mktemp_s(template, strlen(template) + 1);
340 if( err != 0 )
341 return -1;
342 return _open(template,
343 _O_RDWR | _O_BINARY | _O_TEMPORARY | _O_CREAT,
344 _S_IREAD | _S_IWRITE);
345 }
346 #endif /* _MSC_VER */
347 #endif /* HAS_NO_MKSTEMP */
348 #endif /* MAKEDEFS_C || FOR_RUNTIME */
349
350 #if defined(MAKEDEFS_C) || defined(FOR_RUNTIME) || defined(WIN32) \
351 || (defined(CROSSCOMPILE_TARGET) && defined(__DATE__) && defined(__TIME__))
352 static int
case_insensitive_comp(const char * s1,const char * s2)353 case_insensitive_comp(const char *s1, const char *s2)
354 {
355 uchar u1, u2;
356
357 for (;; s1++, s2++) {
358 u1 = (uchar) *s1;
359 if (isupper(u1))
360 u1 = tolower(u1);
361 u2 = (uchar) *s2;
362 if (isupper(u2))
363 u2 = tolower(u2);
364 if (u1 == '\0' || u1 != u2)
365 break;
366 }
367 return u1 - u2;
368 }
369 #endif
370
371 static char *
eos(char * str)372 eos(char *str)
373 {
374 while (*str)
375 str++;
376 return str;
377 }
378
379 #if 0
380 static char *
381 mdlib_strsubst(char *bp, const char *orig, const char *replacement)
382 {
383 char *found, buf[BUFSZ];
384
385 if (bp) {
386 /* [this could be replaced by strNsubst(bp, orig, replacement, 1)] */
387 found = strstr(bp, orig);
388 if (found) {
389 Strcpy(buf, found + strlen(orig));
390 Strcpy(found, replacement);
391 Strcat(bp, buf);
392 }
393 }
394 return bp;
395 }
396 #endif
397
398 static char save_bones_compat_buf[BUFSZ];
399
400 static void
build_savebones_compat_string(void)401 build_savebones_compat_string(void)
402 {
403 #ifdef VERSION_COMPATIBILITY
404 unsigned long uver = VERSION_COMPATIBILITY,
405 cver = (((unsigned long) VERSION_MAJOR << 24)
406 | ((unsigned long) VERSION_MINOR << 16)
407 | ((unsigned long) PATCHLEVEL << 8));
408 #endif
409
410 Strcpy(save_bones_compat_buf,
411 "save and bones files accepted from version");
412 #ifdef VERSION_COMPATIBILITY
413 if (uver != cver)
414 Sprintf(eos(save_bones_compat_buf), "s %lu.%lu.%lu through %d.%d.%d",
415 ((uver >> 24) & 0x0ffUL),
416 ((uver >> 16) & 0x0ffUL),
417 ((uver >> 8) & 0x0ffUL),
418 VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL);
419 else
420 #endif
421 Sprintf(eos(save_bones_compat_buf), " %d.%d.%d only",
422 VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL);
423 }
424
425 static const char *build_opts[] = {
426 #ifdef AMIGA_WBENCH
427 "Amiga WorkBench support",
428 #endif
429 #ifdef ANSI_DEFAULT
430 "ANSI default terminal",
431 #endif
432 #ifdef TEXTCOLOR
433 "color",
434 #endif
435 #ifdef TTY_GRAPHICS
436 #ifdef TTY_TILES_ESCCODES
437 "console escape codes for tile hinting",
438 #endif
439 #endif
440 #ifdef COM_COMPL
441 "command line completion",
442 #endif
443 #ifdef LIFE
444 "Conway's Game of Life",
445 #endif
446 #ifdef COMPRESS
447 "data file compression",
448 #endif
449 #ifdef ZLIB_COMP
450 "ZLIB data file compression",
451 #endif
452 #ifdef DLB
453 #ifndef VERSION_IN_DLB_FILENAME
454 "data librarian",
455 #else
456 "data librarian with a version-dependent name",
457 #endif
458 #endif
459 #ifdef DUMPLOG
460 "end-of-game dumplogs",
461 #endif
462 #ifdef HOLD_LOCKFILE_OPEN
463 "exclusive lock on level 0 file",
464 #endif
465 #if defined(MSGHANDLER) && (defined(POSIX_TYPES) || defined(__GNUC__))
466 "external program as a message handler",
467 #endif
468 #if defined(HANGUPHANDLING) && !defined(NO_SIGNAL)
469 #ifdef SAFERHANGUP
470 "deferred handling of hangup signal",
471 #else
472 "immediate handling of hangup signal",
473 #endif
474 #endif
475 #ifdef INSURANCE
476 "insurance files for recovering from crashes",
477 #endif
478 #ifdef LOGFILE
479 "log file",
480 #endif
481 #ifdef XLOGFILE
482 "extended log file",
483 #endif
484 #ifdef PANICLOG
485 "errors and warnings log file",
486 #endif
487 #ifdef MAIL
488 "mail daemon",
489 #endif
490 #if defined(GNUDOS) || defined(__DJGPP__)
491 "MSDOS protected mode",
492 #endif
493 #ifdef NEWS
494 "news file",
495 #endif
496 #ifdef OVERLAY
497 #ifdef MOVERLAY
498 "MOVE overlays",
499 #else
500 #ifdef VROOMM
501 "VROOMM overlays",
502 #else
503 "overlays",
504 #endif
505 #endif
506 #endif
507 /* pattern matching method will be substituted by nethack at run time */
508 "pattern matching via :PATMATCH:",
509 #ifdef USE_ISAAC64
510 "pseudo random numbers generated by ISAAC64",
511 #ifdef DEV_RANDOM
512 #ifdef NHSTDC
513 /* include which specific one */
514 "strong PRNG seed available from " DEV_RANDOM,
515 #else
516 "strong PRNG seed available from DEV_RANDOM",
517 #endif
518 #else
519 #ifdef WIN32
520 "strong PRNG seed available from CNG BCryptGenRandom()",
521 #endif
522 #endif /* DEV_RANDOM */
523 #else /* ISAAC64 */
524 #ifdef RANDOM
525 "pseudo random numbers generated by random()",
526 #else
527 "pseudo random numbers generated by C rand()",
528 #endif
529 #endif /* ISAAC64 */
530 #ifdef SELECTSAVED
531 "restore saved games via menu",
532 #endif
533 #ifdef SCORE_ON_BOTL
534 "score on status line",
535 #endif
536 #ifdef CLIPPING
537 "screen clipping",
538 #endif
539 #ifdef NO_TERMS
540 #ifdef MAC
541 "screen control via mactty",
542 #endif
543 #ifdef SCREEN_BIOS
544 "screen control via BIOS",
545 #endif
546 #ifdef SCREEN_DJGPPFAST
547 "screen control via DJGPP fast",
548 #endif
549 #ifdef SCREEN_VGA
550 "screen control via VGA graphics",
551 #endif
552 #ifdef WIN32CON
553 "screen control via WIN32 console I/O",
554 #endif
555 #endif /* NO_TERMS */
556 #ifdef SHELL
557 "shell command",
558 #endif
559 "traditional status display",
560 #ifdef STATUS_HILITES
561 "status via windowport with highlighting",
562 #else
563 "status via windowport without highlighting",
564 #endif
565 #ifdef SUSPEND
566 "suspend command",
567 #endif
568 #ifdef TTY_GRAPHICS
569 #ifdef TERMINFO
570 "terminal info library",
571 #else
572 #if defined(TERMLIB) || (!defined(MICRO) && !defined(WIN32))
573 "terminal capability library",
574 #endif
575 #endif
576 #endif /*TTY_GRAPHICS*/
577 #ifdef USE_XPM
578 "tiles file in XPM format",
579 #endif
580 #ifdef GRAPHIC_TOMBSTONE
581 "graphical RIP screen",
582 #endif
583 #ifdef TIMED_DELAY
584 "timed wait for display effects",
585 #endif
586 #ifdef USER_SOUNDS
587 "user sounds",
588 #endif
589 #ifdef PREFIXES_IN_USE
590 "variable playground",
591 #endif
592 #ifdef VISION_TABLES
593 "vision tables",
594 #endif
595 #ifdef ZEROCOMP
596 "zero-compressed save files",
597 #endif
598 #ifdef RLECOMP
599 "run-length compression of map in save files",
600 #endif
601 #ifdef SYSCF
602 "system configuration at run-time",
603 #endif
604 save_bones_compat_buf,
605 "and basic NetHack features"
606 };
607
608 int
count_and_validate_winopts(void)609 count_and_validate_winopts(void)
610 {
611 int i, cnt = 0;
612
613 /* window_opts has a fencepost entry at the end */
614 for (i = 0; i < SIZE(window_opts) - 1; i++) {
615 #if !defined(MAKEDEFS_C) && defined(FOR_RUNTIME)
616 #ifdef WIN32
617 window_opts[i].valid = FALSE;
618 if ((GUILaunched
619 && case_insensitive_comp(window_opts[i].id, "mswin") != 0)
620 || (!GUILaunched
621 && case_insensitive_comp(window_opts[i].id, "mswin") == 0))
622 continue;
623 #endif
624 #endif /* !MAKEDEFS_C && FOR_RUNTIME */
625 ++cnt;
626 window_opts[i].valid = TRUE;
627 }
628 return cnt;
629 }
630
631 static void
opt_out_words(char * str,int * length_p)632 opt_out_words(char *str, /* input, but modified during processing */
633 int *length_p) /* in/out */
634 {
635 char *word;
636
637 while (*str) {
638 word = index(str, ' ');
639 #if 0
640 /* treat " (" as unbreakable space */
641 if (word && *(word + 1) == '(')
642 word = index(word + 1, ' ');
643 #endif
644 if (word)
645 *word = '\0';
646 if (*length_p + (int) strlen(str) > COLNO - 5) {
647 opttext[idxopttext] = strdup(optbuf);
648 if (idxopttext < (MAXOPT - 1))
649 idxopttext++;
650 Sprintf(optbuf, "%s", opt_indent),
651 *length_p = (int) strlen(opt_indent);
652 } else {
653 Sprintf(eos(optbuf), " "), (*length_p)++;
654 }
655 Sprintf(eos(optbuf), "%s", str), *length_p += (int) strlen(str);
656 str += strlen(str) + (word ? 1 : 0);
657 }
658 }
659
660 void
build_options(void)661 build_options(void)
662 {
663 char buf[BUFSZ];
664 int i, length, winsyscnt, cnt = 0;
665 const char *defwinsys = DEFAULT_WINDOW_SYS;
666
667 #if !defined (MAKEDEFS_C) && defined(FOR_RUNTIME)
668 #ifdef WIN32
669 defwinsys = GUILaunched ? "mswin" : "tty";
670 #endif
671 #endif
672 build_savebones_compat_string();
673 opttext[idxopttext] = strdup(optbuf);
674 if (idxopttext < (MAXOPT - 1))
675 idxopttext++;
676 #if (NH_DEVEL_STATUS != NH_STATUS_RELEASED)
677 #if (NH_DEVEL_STATUS == NH_STATUS_BETA)
678 #define STATUS_ARG " [beta]"
679 #else
680 #define STATUS_ARG " [work-in-progress]"
681 #endif
682 #else
683 #define STATUS_ARG ""
684 #endif /* NH_DEVEL_STATUS == NH_STATUS_RELEASED */
685 Sprintf(optbuf, "%sNetHack version %d.%d%s\n",
686 opt_indent, VERSION_MAJOR, VERSION_MINOR, STATUS_ARG);
687 opttext[idxopttext] = strdup(optbuf);
688 if (idxopttext < (MAXOPT - 1))
689 idxopttext++;
690 Sprintf(optbuf, "Options compiled into this edition:");
691 opttext[idxopttext] = strdup(optbuf);
692 if (idxopttext < (MAXOPT - 1))
693 idxopttext++;
694 optbuf[0] = '\0';
695 length = COLNO + 1; /* force 1st item onto new line */
696 for (i = 0; i < SIZE(build_opts); i++) {
697 #if !defined(MAKEDEFS_C) && defined(FOR_RUNTIME)
698 #ifdef WIN32
699 /* ignore the console entry if GUI version */
700 if (GUILaunched
701 && !strcmp("screen control via WIN32 console I/O", build_opts[i]))
702 continue;
703 #endif
704 #endif /* !MAKEDEFS_C && FOR_RUNTIME */
705 Strcat(strcpy(buf, build_opts[i]),
706 (i < SIZE(build_opts) - 1) ? "," : ".");
707 opt_out_words(buf, &length);
708 }
709 opttext[idxopttext] = strdup(optbuf);
710 if (idxopttext < (MAXOPT - 1))
711 idxopttext++;
712 optbuf[0] = '\0';
713 winsyscnt = count_and_validate_winopts();
714 opttext[idxopttext] = strdup(optbuf);
715 if (idxopttext < (MAXOPT - 1))
716 idxopttext++;
717 Sprintf(optbuf, "Supported windowing system%s:",
718 (winsyscnt > 1) ? "s" : "");
719 opttext[idxopttext] = strdup(optbuf);
720 if (idxopttext < (MAXOPT - 1))
721 idxopttext++;
722 optbuf[0] = '\0';
723 length = COLNO + 1; /* force 1st item onto new line */
724
725 for (i = 0; i < SIZE(window_opts) - 1; i++) {
726 if (!window_opts[i].valid)
727 continue;
728 Sprintf(buf, "\"%s\"", window_opts[i].id);
729 if (strcmp(window_opts[i].name, window_opts[i].id))
730 Sprintf(eos(buf), " (%s)", window_opts[i].name);
731 /*
732 * 1 : foo.
733 * 2 : foo and bar,
734 * 3+: for, bar, and quux,
735 *
736 * 2+ will be followed by " with a default of..."
737 */
738 Strcat(buf, (winsyscnt == 1) ? "." /* no 'default' */
739 : (winsyscnt == 2 && cnt == 0) ? " and"
740 : (cnt == winsyscnt - 2) ? ", and"
741 : ",");
742 opt_out_words(buf, &length);
743 cnt++;
744 }
745 if (cnt > 1) {
746 /* loop ended with a comma; opt_out_words() will insert a space */
747 Sprintf(buf, "with a default of \"%s\".", defwinsys);
748 opt_out_words(buf, &length);
749 }
750
751 opttext[idxopttext] = strdup(optbuf);
752 if (idxopttext < (MAXOPT - 1))
753 idxopttext++;
754 optbuf[0] = '\0';
755
756 #if defined(MAKEDEFS_C) || defined(FOR_RUNTIME)
757 {
758 static const char *lua_info[] = {
759 "", "NetHack 3.7.* uses the 'Lua' interpreter to process some data:", "",
760 " :LUACOPYRIGHT:", "",
761 /* 1 2 3 4 5 6 7
762 1234567890123456789012345678901234567890123456789012345678901234567890123456
763 */
764 " \"Permission is hereby granted, free of charge, to any person obtaining",
765 " a copy of this software and associated documentation files (the ",
766 " \"Software\"), to deal in the Software without restriction including",
767 " without limitation the rights to use, copy, modify, merge, publish,",
768 " distribute, sublicense, and/or sell copies of the Software, and to ",
769 " permit persons to whom the Software is furnished to do so, subject to",
770 " the following conditions:",
771 " The above copyright notice and this permission notice shall be",
772 " included in all copies or substantial portions of the Software.\"",
773 (const char *) 0
774 };
775
776 /* add lua copyright notice;
777 ":TAG:" substitutions are deferred to caller */
778 for (i = 0; lua_info[i]; ++i) {
779 opttext[idxopttext] = strdup(lua_info[i]);
780 if (idxopttext < (MAXOPT - 1))
781 idxopttext++;
782 }
783 }
784 #endif /* MAKEDEFS_C || FOR_RUNTIME */
785
786 /* end with a blank line */
787 opttext[idxopttext] = strdup("");
788 if (idxopttext < (MAXOPT - 1))
789 idxopttext++;
790 return;
791 }
792
793 #if defined(__DATE__) && defined(__TIME__)
794 #define extract_field(t,s,n,z) \
795 do { \
796 for (i = 0; i < n; ++i) \
797 t[i] = s[i + z]; \
798 t[i] = '\0'; \
799 } while (0)
800 #endif
801
802 void
runtime_info_init(void)803 runtime_info_init(void)
804 {
805 #if !defined(MAKEDEFS_C) && defined(CROSSCOMPILE_TARGET) \
806 && defined(__DATE__) && defined(__TIME__)
807 int i;
808 char tmpbuf[BUFSZ], *strp;
809 const char *mth[] = {
810 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
811 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
812 struct tm t = {0};
813 time_t timeresult;
814 #endif
815
816 if (!done_runtime_opt_init_once) {
817 done_runtime_opt_init_once = 1;
818 build_savebones_compat_string();
819 /* construct the current version number */
820 make_version();
821 #if !defined(MAKEDEFS_C) && defined(CROSSCOMPILE_TARGET)
822 #if defined(__DATE__) && defined(__TIME__)
823 /*
824 * In a cross-compiled environment, you can't execute
825 * the target binaries during the build, so we can't
826 * use makedefs to write the values of the build
827 * date and time to a file for retrieval. Not for
828 * information meaningful to the target execution
829 * environment.
830 *
831 * How can we capture the build date/time of the target
832 * binaries in such a situation? We need to rely on the
833 * cross-compiler itself to do it for us during the
834 * cross-compile.
835 *
836 * To that end, we are going to make use of the
837 * following pre-defined preprocessor macros for this:
838 * gcc, msvc, clang __DATE__ "Feb 12 1996"
839 * gcc, msvc, clang __TIME__ "23:59:01"
840 *
841 */
842 if (sizeof __DATE__ + sizeof __TIME__ + sizeof "123" <
843 sizeof rttimebuf)
844 Sprintf(rttimebuf, "%s %s", __DATE__, __TIME__);
845 /* "Feb 12 1996 23:59:01"
846 01234567890123456789 */
847 if ((int) strlen(rttimebuf) == 20) {
848 extract_field(tmpbuf, rttimebuf, 4, 7); /* year */
849 t.tm_year = atoi(tmpbuf) - 1900;
850 extract_field(tmpbuf, rttimebuf, 3, 0); /* mon */
851 for (i = 0; i < SIZE(mth); ++i)
852 if (!case_insensitive_comp(tmpbuf, mth[i])) {
853 t.tm_mon = i;
854 break;
855 }
856 extract_field(tmpbuf, rttimebuf, 2, 4); /* mday */
857 strp = tmpbuf;
858 if (*strp == ' ')
859 strp++;
860 t.tm_mday = atoi(strp);
861 extract_field(tmpbuf, rttimebuf, 2, 12); /* hour */
862 t.tm_hour = atoi(tmpbuf);
863 extract_field(tmpbuf, rttimebuf, 2, 15); /* min */
864 t.tm_min = atoi(tmpbuf);
865 extract_field(tmpbuf, rttimebuf, 2, 18); /* sec */
866 t.tm_sec = atoi(tmpbuf);
867 timeresult = mktime(&t);
868 BUILD_TIME = (unsigned long) timeresult;
869 BUILD_DATE = rttimebuf;
870 }
871 #endif /* __DATE__ && __TIME__ */
872 VERSION_NUMBER = version.incarnation;
873 VERSION_FEATURES = version.feature_set;
874 #ifdef MD_IGNORED_FEATURES
875 IGNORED_FEATURES = MD_IGNORED_FEATURES;
876 #endif
877 VERSION_SANITY1 = version.entity_count;
878 VERSION_SANITY2 = version.struct_sizes1;
879 VERSION_SANITY3 = version.struct_sizes2;
880 VERSION_STRING = strdup(version_string(tmpbuf, "."));
881 VERSION_ID = strdup(version_id_string(tmpbuf, BUILD_DATE));
882 COPYRIGHT_BANNER_C = strdup(bannerc_string(tmpbuf, BUILD_DATE));
883 #ifdef NETHACK_HOST_GIT_SHA
884 NETHACK_GIT_SHA = strdup(NETHACK_HOST_GIT_SHA);
885 #endif
886 #ifdef NETHACK_HOST_GIT_BRANCH
887 NETHACK_GIT_BRANCH = strdup(NETHACK_HOST_GIT_BRANCH);
888 #endif
889 #endif /* !MAKEDEFS_C && CROSSCOMPILE_TARGET */
890 idxopttext = 0;
891 build_options();
892 }
893 }
894
895 const char *
do_runtime_info(int * rtcontext)896 do_runtime_info(int *rtcontext)
897 {
898 const char *retval = (const char *) 0;
899
900 if (!done_runtime_opt_init_once)
901 runtime_info_init();
902 if (idxopttext && rtcontext)
903 if (*rtcontext >= 0 && *rtcontext < (MAXOPT - 1)) {
904 retval = opttext[*rtcontext];
905 *rtcontext += 1;
906 }
907 return retval;
908 }
909
910 /*mdlib.c*/
911