From d430db0718871863338be262ceed70ad37d3864b Mon Sep 17 00:00:00 2001 From: "nethack.allison" Date: Wed, 19 Dec 2007 03:19:25 +0000 Subject: [PATCH] remove time_t from struct you (trunk only) There was an issue reported where save files between different versions of a manufacturer's compiler were incompatible because the time_t ubirthday field was changed from 32 bits to 64 bits. 32 bit time_t implementations will break at 19:14:07 on January 18, 2038. 64 bit time_t implementations will break at 23:59:59 on December 31, 3000. This removes the dependency on the size of time_t from the save file. The ubirthday field is no longer embedded in struct you. This also adds two general purpose routines to hacklib.c, one to convert a time value to a 14 character char representation and the other to convert that back to time_t. Those are used by the save/restore routines. This is a savefile breaking change, so editlevel in patchlevel.h was incremented. --- include/decl.h | 1 + include/extern.h | 2 ++ include/patchlevel.h | 2 +- include/you.h | 2 -- src/decl.c | 1 + src/hacklib.c | 78 ++++++++++++++++++++++++++++++++++++++++++ src/mkroom.c | 2 +- src/read.c | 2 +- src/restore.c | 4 +++ src/save.c | 1 + src/shk.c | 2 +- src/shknam.c | 2 +- src/topten.c | 2 +- src/u_init.c | 5 +-- sys/winnt/Makefile.msc | 6 ++-- 15 files changed, 99 insertions(+), 13 deletions(-) diff --git a/include/decl.h b/include/decl.h index 46c811f99..08a70015f 100644 --- a/include/decl.h +++ b/include/decl.h @@ -251,6 +251,7 @@ E NEARDATA anything zeroany; /* init'd and defined in decl.c */ #include "you.h" E NEARDATA struct you u; +E NEARDATA time_t ubirthday; #include "onames.h" #ifndef PM_H /* (pm.h has already been included via youprop.h) */ diff --git a/include/extern.h b/include/extern.h index 2ab35d42b..5ae8f2eda 100644 --- a/include/extern.h +++ b/include/extern.h @@ -850,6 +850,8 @@ E char *FDECL(yymmdd, (time_t)); #endif E long FDECL(yyyymmdd, (time_t)); E long FDECL(hhmmss, (time_t)); +E char *FDECL(yyyymmddhhmmss,(time_t)); +E time_t FDECL(time_from_yyyymmddhhmmss, (char *)); E int NDECL(phase_of_the_moon); E boolean NDECL(friday_13th); E int NDECL(night); diff --git a/include/patchlevel.h b/include/patchlevel.h index 4a5d84f3c..5489fb68c 100644 --- a/include/patchlevel.h +++ b/include/patchlevel.h @@ -13,7 +13,7 @@ * Incrementing EDITLEVEL can be used to force invalidation of old bones * and save files. */ -#define EDITLEVEL 39 +#define EDITLEVEL 40 #define COPYRIGHT_BANNER_A \ "NetHack, Copyright 1985-2007" diff --git a/include/you.h b/include/you.h index 8c141fc00..fce9ad53c 100644 --- a/include/you.h +++ b/include/you.h @@ -355,8 +355,6 @@ struct you { #endif int umortality; /* how many times you died */ int ugrave_arise; /* you die and become something aside from a ghost */ - time_t ubirthday; /* real world time when game began */ - int weapon_slots; /* unused skill slots */ int skills_advanced; /* # of advances made so far */ xchar skill_record[P_SKILL_LIMIT]; /* skill advancements */ diff --git a/src/decl.c b/src/decl.c index 266478686..859804f0e 100644 --- a/src/decl.c +++ b/src/decl.c @@ -137,6 +137,7 @@ NEARDATA struct sysflag sysflags = DUMMY; #endif NEARDATA struct instance_flags iflags = DUMMY; NEARDATA struct you u = DUMMY; +NEARDATA time_t ubirthday = DUMMY; NEARDATA struct obj *invent = (struct obj *)0, *uwep = (struct obj *)0, *uarm = (struct obj *)0, diff --git a/src/hacklib.c b/src/hacklib.c index 7a0128fc9..7aa41e154 100644 --- a/src/hacklib.c +++ b/src/hacklib.c @@ -45,6 +45,8 @@ NetHack, except that rounddiv may call panic(). char * yymmdd (time_t) long yyyymmdd (time_t) long hhmmss (time_t) + char * yyyymmddhhmmss (time_t) + time_t time_from_yyyymmddhhmmss (char *) int phase_of_the_moon (void) boolean friday_13th (void) int night (void) @@ -638,6 +640,82 @@ time_t date; return timenum; } +char * +yyyymmddhhmmss(date) +time_t date; +{ + long datenum; + static char datestr[15]; + struct tm *lt; + + if (date == 0) + lt = getlt(); + else +#if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || defined(BSD) + lt = localtime((long *)(&date)); +#else + lt = localtime(&date); +#endif + /* just in case somebody's localtime supplies (year % 100) + rather than the expected (year - 1900) */ + if (lt->tm_year < 70) + datenum = (long)lt->tm_year + 2000L; + else + datenum = (long)lt->tm_year + 1900L; + Sprintf(datestr, "%04d%02d%02d%02d%02d%02d", + datenum, lt->tm_mon + 1, lt->tm_mday, + lt->tm_hour, lt->tm_min, lt->tm_sec); + return(datestr); +} + +time_t +time_from_yyyymmddhhmmss(buf) +char *buf; +{ + int k; + struct tm t, *lt; + char *g, *p, y[5],mo[3],d[3],h[3],mi[3],s[3]; + if (buf && strlen(buf) == 14) { + g = buf; + p = y; /* year */ + for (k = 0; k < 4; ++k) + *p++ = *g++; + *p = '\0'; + p = mo; /* month */ + for (k = 0; k < 2; ++k) + *p++ = *g++; + *p = '\0'; + p = d; /* day */ + for (k = 0; k < 2; ++k) + *p++ = *g++; + *p = '\0'; + p = h; /* hour */ + for (k = 0; k < 2; ++k) + *p++ = *g++; + *p = '\0'; + p = mi; /* minutes */ + for (k = 0; k < 2; ++k) + *p++ = *g++; + *p = '\0'; + p = s; /* seconds */ + for (k = 0; k < 2; ++k) + *p++ = *g++; + *p = '\0'; + lt = getlt(); + if (lt) { + t = *lt; + t.tm_year = atoi(y) - 1900; + t.tm_mon = atoi(mo) - 1; + t.tm_mday = atoi(d); + t.tm_hour = atoi(h); + t.tm_min = atoi(mi); + t.tm_sec = atoi(s); + return mktime(&t); + } + } + return (time_t)0; +} + /* * moon period = 29.53058 days ~= 30, year = 365.2422 days * days moon phase advances on first day of year compared to preceding year diff --git a/src/mkroom.c b/src/mkroom.c index 8aee070a9..30f9a60e4 100644 --- a/src/mkroom.c +++ b/src/mkroom.c @@ -431,7 +431,7 @@ antholemon() int mtyp, indx, trycnt = 0; /* casts are for dealing with time_t */ - indx = (int)((long)u.ubirthday % 3L); + indx = (int)((long)ubirthday % 3L); indx += level_difficulty(); /* Same monsters within a level, different ones between levels */ do { diff --git a/src/read.c b/src/read.c index 9110448b0..9368389ae 100644 --- a/src/read.c +++ b/src/read.c @@ -104,7 +104,7 @@ doread() if (erosion) wipeout_text(buf, (int)(strlen(buf) * erosion / (2*MAX_ERODE)), - scroll->o_id ^ (unsigned)u.ubirthday); + scroll->o_id ^ (unsigned)ubirthday); pline("\"%s\"", buf); return 1; #endif /* TOURIST */ diff --git a/src/restore.c b/src/restore.c index f0470be57..c17b34cb7 100644 --- a/src/restore.c +++ b/src/restore.c @@ -522,6 +522,7 @@ unsigned int *stuckid, *steedid; /* STEED */ struct sysflag newgamesysflags; #endif struct obj *otmp, *tmp_bc; + char timebuf[15]; int uid; mread(fd, (genericptr_t) &uid, sizeof uid); @@ -565,6 +566,9 @@ unsigned int *stuckid, *steedid; /* STEED */ amii_setpens(amii_numcolors); /* use colors from save file */ #endif mread(fd, (genericptr_t) &u, sizeof(struct you)); + mread(fd, (genericptr_t) timebuf, 14); + ubirthday = time_from_yyyymmddhhmmss(timebuf); + set_uasmon(); #ifdef CLIPPING cliparound(u.ux, u.uy); diff --git a/src/save.c b/src/save.c index 3316db5ec..6d03ef372 100644 --- a/src/save.c +++ b/src/save.c @@ -310,6 +310,7 @@ register int fd, mode; if (u.ugold) (void)insert_gold_into_invent(FALSE); #endif bwrite(fd, (genericptr_t) &u, sizeof(struct you)); + bwrite(fd, yyyymmddhhmmss(ubirthday), 14); save_killers(fd, mode); /* must come before migrating_objs and migrating_mons are freed */ diff --git a/src/shk.c b/src/shk.c index cd09c59d5..39f05a2f6 100644 --- a/src/shk.c +++ b/src/shk.c @@ -1847,7 +1847,7 @@ register struct monst *shkp; /* if angry, impose a surcharge */ /* get a value that's 'random' from game to game, but the same within the same game */ boolean pseudorand = - (((int)u.ubirthday % obj->otyp) >= obj->otyp/2); + (((int)ubirthday % obj->otyp) >= obj->otyp/2); /* all gems are priced high - real or not */ switch(obj->otyp - LAST_GEM) { diff --git a/src/shknam.c b/src/shknam.c index d6981dc07..333e1a0af 100644 --- a/src/shknam.c +++ b/src/shknam.c @@ -412,7 +412,7 @@ const char * const *nlp; and restore support which would be necessary for randomization; try not to make too many assumptions about time_t's internals; use ledger_no rather than depth to keep mine town distinct. */ - int nseed = (int)((long)u.ubirthday / 257L); + int nseed = (int)((long)ubirthday / 257L); name_wanted = ledger_no(&u.uz) + (nseed % 13) - (nseed % 5); if (name_wanted < 0) name_wanted += (13 + 5); diff --git a/src/topten.c b/src/topten.c index eb1f6538c..6ecd8cc42 100644 --- a/src/topten.c +++ b/src/topten.c @@ -362,7 +362,7 @@ int how; (void) strncat(t0->death, killer.name, DTHSZ); break; } - t0->birthdate = yyyymmdd(u.ubirthday); + t0->birthdate = yyyymmdd(ubirthday); t0->deathdate = yyyymmdd((time_t)0L); t0->tt_next = 0; #ifdef UPDATE_RECORD_IN_PLACE diff --git a/src/u_init.c b/src/u_init.c index 4c0724e1c..4d66d9ab6 100644 --- a/src/u_init.c +++ b/src/u_init.c @@ -524,6 +524,7 @@ u_init() * necessary when aborting from a failed restore */ (void) memset((genericptr_t)&u, 0, sizeof(u)); u.ustuck = (struct monst *)0; + (void) memset((genericptr_t)&ubirthday, 0, sizeof(ubirthday)); #if 0 /* documentation of more zero values as desirable */ u.usick_cause[0] = 0; @@ -578,9 +579,9 @@ u_init() u.ulycn = NON_PM; #if defined(BSD) && !defined(POSIX_TYPES) - (void) time((long *)&u.ubirthday); + (void) time((long *)&ubirthday); #else - (void) time(&u.ubirthday); + (void) time(&ubirthday); #endif /* diff --git a/sys/winnt/Makefile.msc b/sys/winnt/Makefile.msc index 7e04f929f..cfd672c67 100644 --- a/sys/winnt/Makefile.msc +++ b/sys/winnt/Makefile.msc @@ -218,7 +218,7 @@ cdebug = -Zi -Od # Util builds #========================================== -cflagsUtil = $(cdebug) $(cflags) /D_USE_32BIT_TIME_T $(INCLDIR) \ +cflagsUtil = $(cdebug) $(cflags) $(INCLDIR) \ $(WINPFLAG) $(DLBFLG) lflagsUtil = $(ldebug) $(lflags) $(conlibs) @@ -232,13 +232,13 @@ LIBS= user32.lib winmm.lib $(ZLIB) !IF ("$(GRAPHICAL)"=="Y") -cflagsGame = $(cdebug) $(cflags) /D_USE_32BIT_TIME_T $(guiflags) $(INCLDIR) \ +cflagsGame = $(cdebug) $(cflags) $(guiflags) $(INCLDIR) \ $(WINPFLAG) $(DLBFLG) $(GAMEPDBFILE) $(GAMEMAPFILE) lflagsGame = $(ldebug) $(lflags) $(guilibs) !ELSE -cflagsGame = $(cdebug) $(cflags) /D_USE_32BIT_TIME_T $(conflags) $(INCLDIR) \ +cflagsGame = $(cdebug) $(cflags) $(conflags) $(INCLDIR) \ $(WINPFLAG) $(DLBFLG) $(GAMEPDBFILE) $(GAMEMAPFILE) lflagsGame = $(ldebug) $(lflags) $(conlibs)