/* NetHack 3.7 date.c $NHDT-Date: 1655402414 2022/06/16 18:00:14 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.3 $ */ /* Copyright (c) Michael Allison, 2021. */ /* NetHack may be freely redistributed. See license for details. */ #include "config.h" /* these are in extern.h but we don't include hack.h */ void populate_nomakedefs(struct version_info *); void free_nomakedefs(void); #define Snprintf(str, size, ...) \ nh_snprintf(__func__, __LINE__, str, size, __VA_ARGS__) extern void nh_snprintf(const char *func, int line, char *str, size_t size, const char *fmt, ...); extern unsigned long md_ignored_features(void); extern char *mdlib_version_string(char *, const char *); extern char *version_id_string(char *, size_t, const char *); extern char *bannerc_string(char *, size_t, const char *); extern int case_insensitive_comp(const char *, const char *); /* nomakedefs_populated: flag for whether 'nomakedefs' should be freed */ static int nomakedefs_populated = 0; struct nomakedefs_s nomakedefs = { /* 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.", (const char *) 0, /* git_sha */ (const char *) 0, /* git_branch */ "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, }; #if defined(__DATE__) && defined(__TIME__) #define extract_field(t,s,n,z) \ do { \ for (i = 0; i < n; ++i) \ t[i] = s[i + z]; \ t[i] = '\0'; \ } while (0) void populate_nomakedefs(struct version_info *version) { int i; char tmpbuf1[BUFSZ], tmpbuf2[BUFSZ], *strp; const char *mth[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; struct tm t = {0}; time_t timeresult; /* * In a cross-compiled environment, you can't execute * the target binaries during the build, so we can't * use makedefs to write the values of the build * date and time to a file for retrieval. Not for * information meaningful to the target execution * environment. * * How can we capture the build date/time of the target * binaries in such a situation? We need to rely on the * cross-compiler itself to do it for us during the * cross-compile. * * To that end, we are going to make use of the * following pre-defined preprocessor macros for this: * gcc, msvc, clang __DATE__ "Feb 12 1996" * gcc, msvc, clang __TIME__ "23:59:01" * */ Snprintf(tmpbuf1, sizeof tmpbuf1, "%s %s", __DATE__, __TIME__); /* "Feb 12 1996 23:59:01" 01234567890123456789 */ if ((int) strlen(tmpbuf1) == 20) { extract_field(tmpbuf2, tmpbuf1, 4, 7); /* year */ t.tm_year = atoi(tmpbuf2) - 1900; extract_field(tmpbuf2, tmpbuf1, 3, 0); /* mon */ for (i = 0; i < SIZE(mth); ++i) if (!case_insensitive_comp(tmpbuf2, mth[i])) { t.tm_mon = i; break; } extract_field(tmpbuf2, tmpbuf1, 2, 4); /* mday */ strp = tmpbuf2; if (*strp == ' ') strp++; t.tm_mday = atoi(strp); extract_field(tmpbuf2, tmpbuf1, 2, 12); /* hour */ t.tm_hour = atoi(tmpbuf2); extract_field(tmpbuf2, tmpbuf1, 2, 15); /* min */ t.tm_min = atoi(tmpbuf2); extract_field(tmpbuf2, tmpbuf1, 2, 18); /* sec */ t.tm_sec = atoi(tmpbuf2); timeresult = mktime(&t); nomakedefs.build_time = (unsigned long) timeresult; nomakedefs.build_date = dupstr(tmpbuf1); } nomakedefs.version_number = version->incarnation; nomakedefs.version_features = version->feature_set; nomakedefs.ignored_features = md_ignored_features(); nomakedefs.version_sanity1 = version->entity_count; nomakedefs.version_sanity2 = version->struct_sizes1; nomakedefs.version_sanity3 = version->struct_sizes2; nomakedefs.version_string = dupstr(mdlib_version_string(tmpbuf2, ".")); nomakedefs.version_id = dupstr( version_id_string(tmpbuf2, sizeof tmpbuf2, nomakedefs.build_date)); nomakedefs.copyright_banner_c = dupstr( bannerc_string(tmpbuf2, sizeof tmpbuf2, nomakedefs.build_date)); #ifdef NETHACK_GIT_SHA nomakedefs.git_sha = dupstr(NETHACK_GIT_SHA); #endif #ifdef NETHACK_GIT_BRANCH nomakedefs.git_branch = dupstr(NETHACK_GIT_BRANCH); #endif nomakedefs_populated = 1; return; } void free_nomakedefs(void) { /* can't just free non-Null values because they're initialized at compile-time with static strings and won't have dynamic values unless populate_nomakedefs() has been called */ if (!nomakedefs_populated) return; if (nomakedefs.build_date) free((genericptr_t) nomakedefs.build_date), nomakedefs.build_date = 0; if (nomakedefs.version_string) free((genericptr_t) nomakedefs.version_string), nomakedefs.version_string = 0; if (nomakedefs.version_id) free((genericptr_t) nomakedefs.version_id), nomakedefs.version_id = 0; if (nomakedefs.copyright_banner_c) free((genericptr_t) nomakedefs.copyright_banner_c), nomakedefs.copyright_banner_c = 0; #ifdef NETHACK_GIT_SHA if (nomakedefs.git_sha) free((genericptr_t) nomakedefs.git_sha), nomakedefs.git_sha = 0; #endif #ifdef NETHACK_GIT_BRANCH if (nomakedefs.git_branch) free((genericptr_t) nomakedefs.git_branch), nomakedefs.git_branch = 0; #endif /* values are Null now; dynamic vs static doesn't really matter anymore */ nomakedefs_populated = 0; return; } #endif /* __DATE__ && __TIME__ */ /*date.c*/