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.
This commit is contained in:
nethack.allison
2007-12-19 03:19:25 +00:00
parent faa3543063
commit d430db0718
15 changed files with 99 additions and 13 deletions

View File

@@ -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) */

View File

@@ -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);

View File

@@ -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"

View File

@@ -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 */

View File

@@ -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,

View File

@@ -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

View File

@@ -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 {

View File

@@ -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 */

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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

View File

@@ -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
/*

View File

@@ -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)