From f4a6da2e52046a07657388f71edba24ef047a8eb Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 25 May 2025 15:03:13 -0400 Subject: [PATCH] save/restore changes - part 2 This is the second of a series of changes related to save/restore. No EDITLEVEL bump has been included, because although the code is changed extensively by this, the content of the savefiles have not been changed. Push the use of the structlevel bwrite() and mread() function use out of the core and into sfstruct.c. This is groundwork for upcoming changes. In the core, replace the bwrite() and mread() calls with the use of type-specific savefile output (Sfo) and savefile input (Sfi) macros. The macros are defined in a new header file savefile.h, which also contains the prototypes for the sfo_* and sfi_* functions that the macros ultimately expand to. The functions themselves are in src/sfbase.c. On C99, each Sfo or Sfi macro expansion refers directly to the corresponding type-specific sfo_* or sfi_* function. If C23 or later is is use, the majority (all but 3 types) of the macros refer to a single _Generic output routine sfo(nhfp, dt, tag), and a single _Generic input routine sfi(nhfp, dt, tag), which handles the dispatch of the type-specific underlying functions. This was somewhat experimental, but turned out to be practical because the compiler would gripe if the type for a variable was not included in the _Generic when passed as an argument, so it could be fixed. This alters the savefile verication process by having a common set return values for the related functions such as uptodate(), check_version(), etc. The new return values return more information about savefile incompatibilities, beyond failure/sucess. The additional information will be useful for an upcoming addition. The expanded return values are: SF_UPTODATE (0) everything matched and looks good SF_OUTDATED (1) savefile is outdated SF_CRITICAL_BYTE_COUNT_MISMATCH (2) critical size count mismatch SF_DM_IL32LLP64_ON_ILP32LL64 (3) Windows x64 savefile on x86 SF_DM_I32LP64_ON_ILP32LL64 (4) Unix 64 savefile on x86 SF_DM_ILP32LL64_ON_I32LP64 (5) x86 savefile on Unix 64 SF_DM_ILP32LL64_ON_IL32LLP64 (6) x86 savefile on Windows x64 SF_DM_I32LP64_ON_IL32LLP64 (7) Unix 64 savefile on Windows x64 SF_DM_IL32LLP64_ON_I32LP64 (8) Windows x64 savefile on Unix 64 SF_DM_MISMATCH (9) some other mismatch The callers in the core have been adjusted to deal with the expanded return values. Other miscellaneous inclusions: - go.oracle_loc -> svo.oracle_loc. - add a bit (1UL << 30) to called SFCTOOL_BIT as groundwork for changes to follow. --- .gitignore | 1 + doc/Guidebook.mn | 14 - doc/Guidebook.tex | 16 - include/config.h | 2 +- include/decl.h | 6 +- include/extern.h | 9 +- include/global.h | 1 + include/hack.h | 59 ++- include/hacklib.h | 2 + include/savefile.h | 605 +++++++++++++++++++++++ include/sfprocs.h | 199 ++++++++ src/artifact.c | 31 +- src/bones.c | 41 +- src/cfgfiles.c | 6 +- src/decl.c | 4 +- src/dungeon.c | 175 +++---- src/end.c | 14 +- src/engrave.c | 51 +- src/files.c | 310 +++++++++--- src/hacklib.c | 49 ++ src/light.c | 24 +- src/mdlib.c | 37 +- src/mkmaze.c | 36 +- src/mkroom.c | 18 +- src/muse.c | 2 +- src/nhlua.c | 19 +- src/o_init.c | 47 +- src/options.c | 17 +- src/region.c | 175 +++---- src/restore.c | 388 ++++++--------- src/rumors.c | 37 +- src/save.c | 365 +++++--------- src/sfbase.c | 209 ++++++++ src/sfstruct.c | 398 ++++++++++++++- src/sys.c | 3 +- src/timeout.c | 47 +- src/track.c | 27 +- src/version.c | 192 ++++--- src/worm.c | 39 +- sys/share/pcmain.c | 5 +- sys/unix/Makefile.src | 25 +- sys/unix/Makefile.utl | 2 + sys/vms/Makefile.src | 21 +- sys/windows/Makefile.nmake | 67 ++- sys/windows/vs/NetHack/NetHack.vcxproj | 5 +- sys/windows/vs/NetHackW/NetHackW.vcxproj | 5 +- sys/windows/windmain.c | 3 + sys/windows/windsys.c | 14 - util/.gitignore | 1 + util/recover.c | 15 +- 50 files changed, 2551 insertions(+), 1287 deletions(-) create mode 100644 include/savefile.h create mode 100644 include/sfprocs.h create mode 100644 src/sfbase.c diff --git a/.gitignore b/.gitignore index f7849967c..f5a18b7e3 100644 --- a/.gitignore +++ b/.gitignore @@ -56,6 +56,7 @@ Makefile.gcc-orig *.lastcodeanalysissucceeded # VS 2017 caches data into the hidden directory .vs .vs +win/win32/vs/obj/* # Win32-specific ignores end .DS_Store # ms-dos diff --git a/doc/Guidebook.mn b/doc/Guidebook.mn index e852ff559..dae3b6713 100644 --- a/doc/Guidebook.mn +++ b/doc/Guidebook.mn @@ -6118,20 +6118,6 @@ the message as the only parameter. MAXPLAYERS\ =\ Limit the maximum number of games that can be running at the same time. .lp -SAVEFORMAT\ =\ A list of up to two save file formats separated by space. -The first format in the list will written as well as read. The second format -will be read only if no save file in the first format exists. -Valid choices are \(lqhistorical\(rq for binary writing of entire structs, -\(lqlendian\(rq for binary writing of each field in little-endian order, -\(lqascii\(rq for writing the save file content in ascii text. -.lp -BONESFORMAT\ =\ A list of up to two bones file formats separated by space. -The first format in the list will written as well as read. The second format -will be read only if no bones files in the first format exist. -Valid choices are \(lqhistorical\(rq for binary writing of entire structs, -\(lqlendian\(rq for binary writing of each field in little-endian order, -\(lqascii\(rq for writing the bones file content in ascii text. -.lp SUPPORT\ =\ A string explaining how to get local support (no default value). .lp RECOVER\ =\ A string explaining how to recover a game on this system diff --git a/doc/Guidebook.tex b/doc/Guidebook.tex index f590cefa3..a54d02b68 100644 --- a/doc/Guidebook.tex +++ b/doc/Guidebook.tex @@ -6768,22 +6768,6 @@ the message as the only parameter. \item[\ib{MAXPLAYERS}] Limit the maximum number of games that can be running at the same time. %.lp -\item[\ib{SAVEFORMAT}] -A list of up to two save file formats separated by space. -The first format in the list will written as well as read. The second format -will be read only if no save file in the first format exists. -Valid choices are ``{\tt historical}'' for binary writing of entire structs, -``{\tt lendian}'' for binary writing of each field in little-endian order, -``{\tt ascii}'' for writing the save file content in ascii text. -%.lp -\item[\ib{BONESFORMAT}] -A list of up to two bones file formats separated by space. -The first format in the list will written as well as read. The second -format will be read only if no bones files in the first format exist. -Valid choices are ``{\tt historical}'' for binary writing of entire structs, -``{\tt lendian}'' for binary writing of each field in little-endian order, -``{\tt ascii}'' for writing the bones file content in ascii text. -%.lp \item[\ib{SUPPORT}] A string explaining how to get local support (no default value). %.lp diff --git a/include/config.h b/include/config.h index 14bfdc2e8..f14273810 100644 --- a/include/config.h +++ b/include/config.h @@ -259,7 +259,7 @@ # ifdef CRASHREPORT # undef CRASHREPORT # endif -# ifdef MSDOS +# if defined(MSDOS) || defined(NOPANICTRACE) # undef PANICTRACE # endif #endif diff --git a/include/decl.h b/include/decl.h index db9042445..54cf2f390 100644 --- a/include/decl.h +++ b/include/decl.h @@ -296,6 +296,9 @@ struct instance_globals_c { short corpsenm_digested; /* monster type being digested, set by gulpum */ /* zap.c */ + /* new */ + boolean converted_savefile_loaded; + boolean havestate; }; @@ -735,7 +738,6 @@ struct instance_globals_o { /* rumors.c */ int oracle_flg; /* -1=>don't use, 0=>need init, 1=>init done */ - unsigned long *oracle_loc; /* uhitm.c */ boolean override_confirmation; /* Used to flag attacks caused by @@ -1169,6 +1171,8 @@ struct instance_globals_saved_n { struct instance_globals_saved_o { /* rumors.c */ unsigned oracle_cnt; /* oracles are handled differently from rumors... */ + unsigned long *oracle_loc; + /* other */ long omoves; /* level timestamp */ }; diff --git a/include/extern.h b/include/extern.h index 63c6800fc..42e47a3d4 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1969,6 +1969,7 @@ extern int dosuspend(void); extern void nt_regularize(char *); extern int(*nt_kbhit)(void); extern void Delay(int); +extern boolean contains_directory(const char *); # ifdef CRASHREPORT struct CRctxt; extern struct CRctxt *ctxp; @@ -1976,7 +1977,6 @@ extern int win32_cr_helper(char, struct CRctxt *, void *, int); extern int win32_cr_gettrace(int, char *, int); extern int *win32_cr_shellexecute(const char *); # endif -extern boolean contains_directory(const char *); #endif /* WIN32 */ #endif /* MICRO || WIN32 */ @@ -2675,7 +2675,6 @@ extern void get_plname_from_file(NHFILE *, char *, boolean) NONNULLARG12; extern int restore_menu(winid); #endif extern boolean lookup_id_mapping(unsigned, unsigned *) NONNULLARG2; -extern int validate(NHFILE *, const char *, boolean) NONNULLARG1; /* extern void reset_restpref(void); */ /* extern void set_restpref(const char *); */ /* extern void set_savepref(const char *); */ @@ -3496,8 +3495,7 @@ extern boolean comp_times(long); #endif extern boolean check_version(struct version_info *, const char *, boolean, unsigned long) NONNULLARG1; -extern boolean uptodate(NHFILE *, const char *, unsigned long) NONNULLARG1; -extern void store_formatindicator(NHFILE *) NONNULLARG1; +extern int uptodate(NHFILE *, const char *, unsigned long) NONNULLARG1; extern void store_version(NHFILE *) NONNULLARG1; extern unsigned long get_feature_notice_ver(char *) NO_NNARGS; extern unsigned long get_current_feature_ver(void); @@ -3505,8 +3503,9 @@ extern const char *copyright_banner_line(int) NONNULL; extern void early_version_info(boolean); extern void dump_version_info(void); extern void store_critical_bytes(NHFILE *) NONNULLARG1; -extern int compare_critical_bytes(NHFILE *); +extern int compare_critical_bytes(NHFILE *, int *, unsigned long) NONNULLARG1; extern int get_critical_size_count(void); +extern int validate(NHFILE *, const char *, boolean) NONNULLARG1; /* ### video.c ### */ diff --git a/include/global.h b/include/global.h index a38c7722b..727929d09 100644 --- a/include/global.h +++ b/include/global.h @@ -569,4 +569,5 @@ typedef enum NHL_pcall_action { NHLpa_impossible } NHL_pcall_action; +#define SFCTOOL_BIT (1UL << 30) /* needed for upcoming savefile handling */ #endif /* GLOBAL_H */ diff --git a/include/hack.h b/include/hack.h index bf50ff3d9..9960d223e 100644 --- a/include/hack.h +++ b/include/hack.h @@ -766,13 +766,6 @@ struct role_filter { }; #define NUM_RACES (5) -enum saveformats { - invalid = 0, - historical = 1, /* entire struct, binary, as-is */ - lendian = 2, /* each field, binary, little-endian */ - ascii = 3 /* each field, ascii text (just proof of concept) */ -}; - struct selectionvar { int wid, hei; boolean bounds_dirty; @@ -899,6 +892,19 @@ typedef struct { #define UTD_SKIP_SANITY1 0x04 #define UTD_SKIP_SAVEFILEINFO 0x08 #define UTD_WITHOUT_WAITSYNCH_PERFILE 0x10 +#define UTD_QUIETLY 0x20 + +/* Values for savefile status */ +#define SF_UPTODATE 0 +#define SF_OUTDATED 1 +#define SF_CRITICAL_BYTE_COUNT_MISMATCH 2 +#define SF_DM_IL32LLP64_ON_ILP32LL64 3 /* Wind x64 savefile on x86 */ +#define SF_DM_I32LP64_ON_ILP32LL64 4 /* Unix 64 savefile on x86 */ +#define SF_DM_ILP32LL64_ON_I32LP64 5 /* x86 savefile on Unix 64 */ +#define SF_DM_ILP32LL64_ON_IL32LLP64 6 /* x86 savefile on Wind x64 */ +#define SF_DM_I32LP64_ON_IL32LLP64 7 /* Unix 64 savefile on Wind x64 */ +#define SF_DM_IL32LLP64_ON_I32LP64 8 /* Wind x64 savefile on Unix 64 */ +#define SF_DM_MISMATCH 9 /* generic savefile byte mismatch */ #define ENTITIES 2 struct valuable_data { @@ -940,28 +946,43 @@ struct xlock_s { boolean magic_key; }; +#define MAX_BMASK 4 + /* NetHack ftypes */ #define NHF_LEVELFILE 1 #define NHF_SAVEFILE 2 #define NHF_BONESFILE 3 /* modes */ -#define READING 0x0 -#define COUNTING 0x1 -#define WRITING 0x2 -#define FREEING 0x4 -#define MAX_BMASK 4 +#define READING 0x0 +#define COUNTING 0x1 +#define WRITING 0x2 +#define FREEING 0x4 +#define CONVERTING 0x08 +#define UNCONVERTING 0x10 +#if 0 /* operations of the various saveXXXchn & co. routines */ #define perform_bwrite(nhfp) ((nhfp)->mode & (COUNTING | WRITING)) #define release_data(nhfp) ((nhfp)->mode & FREEING) +#endif + +/* operations of the various saveXXXchn & co. routines */ +#define update_file(nhfp) ((nhfp)->mode & (COUNTING | WRITING)) +#define release_data(nhfp) ((nhfp)->mode & FREEING) + +enum saveformats { + invalid = 0, + historical = 1, /* entire struct, binary, as-is */ + cnvascii = 2, /* each field, ascii text */ + NUM_SAVEFORMATS +}; /* Content types for fieldlevel files */ struct fieldlevel_content { boolean deflt; /* individual fields */ boolean binary; /* binary rather than text */ - boolean json; /* JSON */ }; -typedef struct { +struct nh_file { int fd; /* for traditional structlevel binary writes */ int mode; /* holds READING, WRITING, or FREEING modes */ int ftype; /* NHF_LEVELFILE, NHF_SAVEFILE, or NHF_BONESFILE */ @@ -978,7 +999,10 @@ typedef struct { FILE *fplog; /* file pointer logfile */ FILE *fpdebug; /* file pointer debug info */ struct fieldlevel_content style; -} NHFILE; + struct nh_file *nhfpconvert; +}; + +typedef struct nh_file NHFILE; /* Monster name articles */ #define ARTICLE_NONE 0 @@ -1534,8 +1558,13 @@ typedef uint32_t mmflags_nht; /* makemon MM_ flags */ #include "nhlua.h" #endif +#if !defined(RECOVER_C) + #include "extern.h" +#include "savefile.h" #include "decl.h" +#endif /* RECOVER_C */ + #endif /* HACK_H */ diff --git a/include/hacklib.h b/include/hacklib.h index 2912035a4..96b6bdf39 100644 --- a/include/hacklib.h +++ b/include/hacklib.h @@ -79,6 +79,8 @@ extern unsigned Strlen_(const char *, const char *, int) NONNULLPTRS; #endif extern int unicodeval_to_utf8str(int, uint8 *, size_t); extern boolean copy_bytes(int, int); +extern const char *datamodel(void); +extern const char *what_datamodel_is_this(int, int, int, int, int); #endif /* HACKLIB_H */ diff --git a/include/savefile.h b/include/savefile.h new file mode 100644 index 000000000..28cd24b23 --- /dev/null +++ b/include/savefile.h @@ -0,0 +1,605 @@ +/* NetHack 3.7 savefile.h $NHDT-Date: 1738638877 2025/02/03 19:14:37 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1476 $ */ +/* Copyright (c) Michael Allison, 2025. */ +/* NetHack may be freely redistributed. See license for details. */ + +#ifndef SAVEFILE_H +#define SAVEFILE_H + +/* #define SAVEFILE_DEBUGGING */ + +extern void sf_init(void); +/* sfbase.c output functions */ +extern void sfo_aligntyp(NHFILE *, aligntyp *, const char *); +extern void sfo_any(NHFILE *, anything *, const char *); +extern void sfo_boolean(NHFILE *, boolean *, const char *); +extern void sfo_char(NHFILE *, char *, const char *, int); +extern void sfo_genericptr(NHFILE *, genericptr_t *, const char *); +extern void sfo_int16(NHFILE *, int16 *, const char *); +extern void sfo_int32(NHFILE *, int32 *, const char *); +extern void sfo_int64(NHFILE *, int64 *, const char *); +extern void sfo_uchar(NHFILE *, uchar *, const char *); +extern void sfo_uint16(NHFILE *, uint16 *, const char *); +extern void sfo_uint32(NHFILE *, uint32 *, const char *); +extern void sfo_uint64(NHFILE *, uint64 *, const char *); +extern void sfo_size_t(NHFILE *, size_t *, const char *); +extern void sfo_time_t(NHFILE *, time_t *, const char *); + +extern void sfo_arti_info(NHFILE *nhfp, + struct arti_info *d_arti_info, + const char *myname); +extern void sfo_dgn_topology(NHFILE *nhfp, + struct dgn_topology *d_dgn_topology, + const char *myname); +extern void sfo_dungeon(NHFILE *nhfp, struct dungeon *d_dungeon, + const char *myname); +extern void sfo_branch(NHFILE *nhfp, struct branch *d_branch, + const char *myname); +extern void sfo_linfo(NHFILE *nhfp, struct linfo *d_linfo, + const char *myname); +extern void sfo_nhcoord(NHFILE *nhfp, struct nhcoord *d_nhcoord, + const char *myname); +extern void sfo_d_level(NHFILE *nhfp, struct d_level *d_d_level, + const char *myname); +extern void sfo_mapseen_feat(NHFILE *nhfp, + struct mapseen_feat *d_mapseen_feat, + const char *myname); +extern void sfo_mapseen_flags(NHFILE *nhfp, + struct mapseen_flags *d_mapseen_flags, + const char *myname); +extern void sfo_mapseen_rooms(NHFILE *nhfp, + struct mapseen_rooms *d_mapseen_rooms, + const char *myname); +extern void sfo_kinfo(NHFILE *nhfp, + struct kinfo *d_kinfo, + const char *myname); +extern void sfo_engr(NHFILE *, struct engr *, const char *); +extern void sfo_ls_t(NHFILE *, struct ls_t *, const char *); +extern void sfo_bubble(NHFILE *, struct bubble *, const char *); +extern void sfo_mkroom(NHFILE *, struct mkroom *, const char *); +extern void sfo_objclass(NHFILE *, struct objclass *, const char *); +extern void sfo_nhrect(NHFILE *, struct nhrect *, const char *); +extern void sfo_fe(NHFILE *, struct fe *, const char *); +extern void sfo_version_info(NHFILE *, struct version_info *, + const char *); +extern void sfo_context_info(NHFILE *, struct context_info *, + const char *); +extern void sfo_flag(NHFILE *, struct flag *, const char *); +extern void sfo_you(NHFILE *, struct you *, const char *); +extern void sfo_mvitals(NHFILE *, struct mvitals *, const char *); +extern void sfo_q_score(NHFILE *, struct q_score *, const char *); +extern void sfo_spell(NHFILE *, struct spell *, const char *); +extern void sfo_dest_area(NHFILE *, struct dest_area *, const char *); +extern void sfo_levelflags(NHFILE *, struct levelflags *, const char *); +extern void sfo_rm(NHFILE *, struct rm *, const char *); +extern void sfo_cemetery(NHFILE *, struct cemetery *, const char *); +extern void sfo_damage(NHFILE *, struct damage *, const char *); +extern void sfo_stairway(NHFILE *, struct stairway *, const char *); +extern void sfo_obj(NHFILE *, struct obj *, const char *); +extern void sfo_monst(NHFILE *, struct monst *, const char *); +extern void sfo_ebones(NHFILE *, struct ebones *, const char *); +extern void sfo_edog(NHFILE *, struct edog *, const char *); +extern void sfo_egd(NHFILE *, struct egd *, const char *); +extern void sfo_emin(NHFILE *, struct emin *, const char *); +extern void sfo_engr(NHFILE *, struct engr *, const char *); +extern void sfo_epri(NHFILE *, struct epri *, const char *); +extern void sfo_eshk(NHFILE *, struct eshk *, const char *); +extern void sfo_trap(NHFILE *, struct trap *, const char *); +extern void sfo_gamelog_line(NHFILE *, struct gamelog_line *, const char *); +extern void sfo_fruit(NHFILE *, struct fruit *, const char *); +extern void sfo_s_level(NHFILE *, struct s_level *, const char *); +extern void sfo_xint8(NHFILE *, xint8 *, const char *); +extern void sfo_xint16(NHFILE *, xint16 *, const char *); +extern void sfo_schar(NHFILE *, schar *, const char *); +extern void sfo_short(NHFILE *, short *, const char *); +extern void sfo_ushort(NHFILE *, ushort *, const char *); +extern void sfo_int(NHFILE *, int *, const char *); +extern void sfo_unsigned(NHFILE *, unsigned *, const char *); +extern void sfo_long(NHFILE *, long *, const char *); +extern void sfo_ulong(NHFILE *, ulong *, const char *); +/* sfbase.c input functions */ +extern void sfi_addinfo(NHFILE *, const char *, const char *); +extern void sfi_aligntyp(NHFILE *, aligntyp *, const char *); +extern void sfi_any(NHFILE *, anything *, const char *); +extern void sfi_boolean(NHFILE *, boolean *, const char *); +extern void sfi_genericptr(NHFILE *, genericptr_t *, const char *); +extern void sfi_char(NHFILE *, char *, const char *, int); +extern void sfi_int16(NHFILE *, int16 *, const char *); +extern void sfi_int32(NHFILE *, int32 *, const char *); +extern void sfi_int64(NHFILE *, int64 *, const char *); +extern void sfi_uchar(NHFILE *, uchar *, const char *); +extern void sfi_uint16(NHFILE *, uint16 *, const char *); +extern void sfi_uint32(NHFILE *, uint32 *, const char *); +extern void sfi_uint64(NHFILE *, uint64 *, const char *); +extern void sfi_size_t(NHFILE *, size_t *, const char *); +extern void sfi_time_t(NHFILE *, time_t *, const char *); +extern void sfi_arti_info(NHFILE *nhfp, + struct arti_info *d_arti_info, + const char *myname); +extern void sfi_dungeon(NHFILE *nhfp, struct dungeon *d_dungeon, + const char *myname); +extern void sfi_dgn_topology(NHFILE *nhfp, + struct dgn_topology *d_dgn_topology, + const char *myname); +extern void sfi_branch(NHFILE *nhfp, struct branch *d_branch, + const char *myname); +extern void sfi_linfo(NHFILE *nhfp, struct linfo *d_linfo, + const char *myname); +extern void sfi_nhcoord(NHFILE *nhfp, struct nhcoord *d_nhcoord, + const char *myname); +extern void sfi_d_level(NHFILE *nhfp, struct d_level *d_d_level, + const char *myname); +extern void sfi_mapseen_feat(NHFILE *nhfp, + struct mapseen_feat *d_mapseen_feat, + const char *myname); +extern void sfi_mapseen_flags(NHFILE *nhfp, + struct mapseen_flags *d_mapseen_flags, + const char *myname); +extern void sfi_mapseen_rooms(NHFILE *nhfp, + struct mapseen_rooms *d_mapseen_rooms, + const char *myname); +extern void sfi_kinfo(NHFILE *nhfp, + struct kinfo *d_kinfo, + const char *myname); +extern void sfi_engr(NHFILE *, struct engr *, const char *); +extern void sfi_ls_t(NHFILE *, struct ls_t *, const char *); +extern void sfi_bubble(NHFILE *, struct bubble *, const char *); +extern void sfi_mkroom(NHFILE *, struct mkroom *, const char *); +extern void sfi_objclass(NHFILE *, struct objclass *, const char *); +extern void sfi_nhrect(NHFILE *, struct nhrect *, const char *); +extern void sfi_fe(NHFILE *, struct fe *, const char *); +extern void sfi_version_info(NHFILE *, struct version_info *, + const char *); +extern void sfi_context_info(NHFILE *, struct context_info *, + const char *); +extern void sfi_flag(NHFILE *, struct flag *, const char *); +extern void sfi_you(NHFILE *, struct you *, const char *); +extern void sfi_mvitals(NHFILE *, struct mvitals *, const char *); +extern void sfi_q_score(NHFILE *, struct q_score *, const char *); +extern void sfi_spell(NHFILE *, struct spell *, const char *); +extern void sfi_dest_area(NHFILE *, struct dest_area *, const char *); +extern void sfi_levelflags(NHFILE *, struct levelflags *, const char *); +extern void sfi_rm(NHFILE *, struct rm *, const char *); +extern void sfi_cemetery(NHFILE *, struct cemetery *, const char *); +extern void sfi_damage(NHFILE *, struct damage *, const char *); +extern void sfi_stairway(NHFILE *, struct stairway *, const char *); +extern void sfi_obj(NHFILE *, struct obj *, const char *); +extern void sfi_monst(NHFILE *, struct monst *, const char *); +extern void sfi_ebones(NHFILE *, struct ebones *, const char *); +extern void sfi_edog(NHFILE *, struct edog *, const char *); +extern void sfi_egd(NHFILE *, struct egd *, const char *); +extern void sfi_emin(NHFILE *, struct emin *, const char *); +extern void sfi_engr(NHFILE *, struct engr *, const char *); +extern void sfi_epri(NHFILE *, struct epri *, const char *); +extern void sfi_eshk(NHFILE *, struct eshk *, const char *); +extern void sfi_trap(NHFILE *, struct trap *, const char *); +extern void sfi_fruit(NHFILE *, struct fruit *, const char *); +extern void sfi_gamelog_line(NHFILE *, struct gamelog_line *, const char *); +extern void sfi_s_level(NHFILE *, struct s_level *, const char *); +extern void sfi_xint8(NHFILE *, xint8 *, const char *); +extern void sfi_xint16(NHFILE *, xint16 *, const char *); +extern void sfi_schar(NHFILE *, schar *, const char *); +extern void sfi_short(NHFILE *, short *, const char *); +extern void sfi_ushort(NHFILE *, ushort *, const char *); +extern void sfi_int(NHFILE *, int *, const char *); +extern void sfi_unsigned(NHFILE *, unsigned *, const char *); +extern void sfi_long(NHFILE *, long *, const char *); +extern void sfi_ulong(NHFILE *, ulong *, const char *); +#if NH_C < 202300L +#define Sfo_aligntyp(a,b,c) sfo_aligntyp(a, b, c) +#define Sfo_any(a,b,c) sfo_any(a, b, c) +#define Sfo_genericptr(a,b,c) sfo_genericptr(a, b, c) +#define Sfo_coordxy(a,b,c) sfo_int16(a, b, c) +#define Sfo_char(a,b,c,d) sfo_char(a, b, c, d) +#define Sfo_int16(a,b,c) sfo_int16(a, b, c) +#define Sfo_int32(a,b,c) sfo_int32(a, b, c) +#define Sfo_int64(a,b,c) sfo_int64(a, b, c) +#define Sfo_uchar(a,b,c) sfo_uchar(a, b, c) +#define Sfo_uint16(a,b,c) sfo_uint16(a, b, c) +#define Sfo_uint32(a,b,c) sfo_uint32(a, b, c) +#define Sfo_uint64(a,b,c) sfo_uint64(a, b, c) +#define Sfo_size_t(a,b,c) sfo_size_t(a, b, c) +#define Sfo_time_t(a,b,c) sfo_time_t(a, b, c) + +#define Sfo_arti_info(a,b,c) sfo_arti_info(a, b, c) +#define Sfo_dgn_topology(a,b,c) sfo_dgn_topology(a, b, c) +#define Sfo_dungeon(a,b,c) sfo_dungeon(a, b, c) +#define Sfo_branch(a,b,c) sfo_branch(a, b, c) +#define Sfo_linfo(a,b,c) sfo_linfo(a, b, c) +#define Sfo_nhcoord(a,b,c) sfo_nhcoord(a, b, c) +#define Sfo_d_level(a,b,c) sfo_d_level(a, b, c) +#define Sfo_mapseen_feat(a,b,c) sfo_mapseen_feat(a, b, c) +#define Sfo_mapseen_flags(a,b,c) sfo_mapseen_flags(a, b, c) +#define Sfo_mapseen_rooms(a,b,c) sfo_mapseen_rooms(a, b, c) +#define Sfo_kinfo(a,b,c) sfo_kinfo(a, b, c) +#define Sfo_engr(a,b,c) sfo_engr(a, b, c) +#define Sfo_ls_t(a,b,c) sfo_ls_t(a, b, c) +#define Sfo_bubble(a,b,c) sfo_bubble(a, b, c) +#define Sfo_mkroom(a,b,c) sfo_mkroom(a, b, c) +#define Sfo_objclass(a,b,c) sfo_objclass(a, b, c) +#define Sfo_nhrect(a,b,c) sfo_nhrect(a, b, c) +#define Sfo_fe(a,b,c) sfo_fe(a, b, c) +#define Sfo_version_info(a,b,c) sfo_version_info(a, b, c) +#define Sfo_context_info(a,b,c) sfo_context_info(a, b, c) +#define Sfo_flag(a,b,c) sfo_flag(a, b, c) +#define Sfo_you(a,b,c) sfo_you(a, b, c) +#define Sfo_mvitals(a,b,c) sfo_mvitals(a, b, c) +#define Sfo_q_score(a,b,c) sfo_q_score(a, b, c) +#define Sfo_spell(a,b,c) sfo_spell(a, b, c) +#define Sfo_dest_area(a,b,c) sfo_dest_area(a, b, c) +#define Sfo_levelflags(a,b,c) sfo_levelflags(a, b, c) +#define Sfo_rm(a,b,c) sfo_rm(a, b, c) +#define Sfo_cemetery(a,b,c) sfo_cemetery(a, b, c) +#define Sfo_damage(a,b,c) sfo_damage(a, b, c) +#define Sfo_stairway(a,b,c) sfo_stairway(a, b, c) +#define Sfo_obj(a,b,c) sfo_obj(a, b, c) +#define Sfo_monst(a,b,c) sfo_monst(a, b, c) +#define Sfo_ebones(a,b,c) sfo_ebones(a, b, c) +#define Sfo_edog(a,b,c) sfo_edog(a, b, c) +#define Sfo_egd(a,b,c) sfo_egd(a, b, c) +#define Sfo_emin(a,b,c) sfo_emin(a, b, c) +#define Sfo_engr(a,b,c) sfo_engr(a, b, c) +#define Sfo_epri(a,b,c) sfo_epri(a, b, c) +#define Sfo_eshk(a,b,c) sfo_eshk(a, b, c) +#define Sfo_trap(a,b,c) sfo_trap(a, b, c) +#define Sfo_gamelog_line(a,b,c) sfo_gamelog_line(a, b, c) +#define Sfo_fruit(a,b,c) sfo_fruit(a, b, c) +#define Sfo_s_level(a,b,c) sfo_s_level(a, b, c) +#define Sfo_schar(a,b,c) sfo_schar(a, b, c); +#define Sfo_short(a, b, c) sfo_short(a, b, c) +#define Sfo_ushort(a, b, c) sfo_ushort(a, b, c) +#define Sfo_int(a, b, c) sfo_int(a, b, c) +#define Sfo_unsigned(a, b, c) sfo_unsigned(a, b, c) +#define Sfo_long(a,b,c) sfo_long(a, b, c); +#define Sfo_ulong(a,b,c) sfo_ulong(a, b, c); +#define Sfo_boolean(a,b,c) sfo_boolean(a, b, c); +#define Sfo_xint8(a, b, c) sfo_xint8(a, b, c); +#define Sfo_xint16(a, b, c) sfo_xint16(a, b, c) +/* sfbase.c input functions */ +#define Sfi_addinfo(a,b,c) sfi_addinfo(a, b, c) +#define Sfi_aligntyp(a,b,c) sfi_aligntyp(a, b, c) +#define Sfi_any(a,b,c) sfi_any(a, b, c) +#define Sfi_genericptr(a,b,c) sfi_genericptr(a, b, c) +#define Sfi_coordxy(a,b,c) sfi_int16(a, b, c) +#define Sfi_char(a,b,c,d) sfi_char(a, b, c, d) +#define Sfi_int16(a,b,c) sfi_int16(a, b, c) +#define Sfi_int32(a,b,c) sfi_int32(a, b, c) +#define Sfi_int64(a,b,c) sfi_int64(a, b, c) +#define Sfi_uchar(a,b,c) sfi_uchar(a, b, c) +#define Sfi_uint16(a,b,c) sfi_uint16(a, b, c) +#define Sfi_uint32(a,b,c) sfi_uint32(a, b, c) +#define Sfi_uint64(a,b,c) sfi_uint64(a, b, c) +#define Sfi_size_t(a,b,c) sfi_size_t(a, b, c) +#define Sfi_time_t(a,b,c) sfi_time_t(a, b, c) +#define Sfi_arti_info(a,b,c) sfi_arti_info(a, b, c) +#define Sfi_dungeon(a,b,c) sfi_dungeon(a, b, c) +#define Sfi_dgn_topology(a,b,c) sfi_dgn_topology(a, b, c) +#define Sfi_branch(a,b,c) sfi_branch(a, b, c) +#define Sfi_linfo(a,b,c) sfi_linfo(a, b, c) +#define Sfi_nhcoord(a,b,c) sfi_nhcoord(a, b, c) +#define Sfi_d_level(a,b,c) sfi_d_level(a, b, c) +#define Sfi_mapseen_feat(a,b,c) sfi_mapseen_feat(a, b, c) +#define Sfi_mapseen_flags(a,b,c) sfi_mapseen_flags(a, b, c) +#define Sfi_mapseen_rooms(a,b,c) sfi_mapseen_rooms(a, b, c) +#define Sfi_kinfo(a,b,c) sfi_kinfo(a, b, c) +#define Sfi_engr(a,b,c) sfi_engr(a, b, c) +#define Sfi_ls_t(a,b,c) sfi_ls_t(a, b, c) +#define Sfi_bubble(a,b,c) sfi_bubble(a, b, c) +#define Sfi_mkroom(a,b,c) sfi_mkroom(a, b, c) +#define Sfi_objclass(a,b,c) sfi_objclass(a, b, c) +#define Sfi_nhrect(a,b,c) sfi_nhrect(a, b, c) +#define Sfi_fe(a,b,c) sfi_fe(a, b, c) +#define Sfi_version_info(a,b,c) sfi_version_info(a, b, c) +#define Sfi_context_info(a,b,c) sfi_context_info(a, b, c) +#define Sfi_flag(a,b,c) sfi_flag(a, b, c) +#define Sfi_you(a,b,c) sfi_you(a, b, c) +#define Sfi_mvitals(a,b,c) sfi_mvitals(a, b, c) +#define Sfi_q_score(a,b,c) sfi_q_score(a, b, c) +#define Sfi_spell(a,b,c) sfi_spell(a, b, c) +#define Sfi_dest_area(a,b,c) sfi_dest_area(a, b, c) +#define Sfi_levelflags(a,b,c) sfi_levelflags(a, b, c) +#define Sfi_rm(a,b,c) sfi_rm(a, b, c) +#define Sfi_cemetery(a,b,c) sfi_cemetery(a, b, c) +#define Sfi_damage(a,b,c) sfi_damage(a, b, c) +#define Sfi_stairway(a,b,c) sfi_stairway(a, b, c) +#define Sfi_obj(a,b,c) sfi_obj(a, b, c) +#define Sfi_monst(a,b,c) sfi_monst(a, b, c) +#define Sfi_ebones(a,b,c) sfi_ebones(a, b, c) +#define Sfi_edog(a,b,c) sfi_edog(a, b, c) +#define Sfi_egd(a,b,c) sfi_egd(a, b, c) +#define Sfi_emin(a,b,c) sfi_emin(a, b, c) +#define Sfi_engr(a,b,c) sfi_engr(a, b, c) +#define Sfi_epri(a,b,c) sfi_epri(a, b, c) +#define Sfi_eshk(a,b,c) sfi_eshk(a, b, c) +#define Sfi_trap(a,b,c) sfi_trap(a, b, c) +#define Sfi_fruit(a,b,c) sfi_fruit(a, b, c) +#define Sfi_gamelog_line(a,b,c) sfi_gamelog_line(a, b, c) +#define Sfi_s_level(a,b,c) sfi_s_level(a, b, c) +#define Sfi_schar(a,b,c) sfi_schar(a, b, c); +#define Sfi_short(a, b, c) sfi_short(a, b, c) +#define Sfi_ushort(a, b, c) sfi_ushort(a, b, c) +#define Sfi_int(a, b, c) sfi_int(a, b, c); +#define Sfi_unsigned(a, b, c) sfi_unsigned(a, b, c); +#define Sfi_long(a,b,c) sfi_long(a, b, c); +#define Sfi_ulong(a,b,c) sfi_ulong(a, b, c); +#define Sfi_boolean(a,b,c) sfi_boolean(a, b, c); +#define Sfi_xint8(a, b, c) sfi_xint8(a, b, c); +#define Sfi_xint16(a, b, c) sfi_xint16(a, b, c); +#else + +#define sfo(nhfp, dt, tag) \ + _Generic( (dt), \ + anything * : sfo_any, \ + int16_t * : sfo_int16, \ + int32_t * : sfo_int32, \ + int64_t * : sfo_int64, \ + uchar * : sfo_uchar, \ + uint16_t * : sfo_uint16, \ + uint32_t * : sfo_uint32, \ + uint64_t * : sfo_uint64, \ + long * : sfo_long, \ + unsigned long * : sfo_ulong, \ + xint8 * : sfo_xint8, \ + struct arti_info * : sfo_arti_info, \ + struct nhrect * : sfo_nhrect, \ + struct branch * : sfo_branch, \ + struct bubble * : sfo_bubble, \ + struct cemetery * : sfo_cemetery, \ + struct context_info * : sfo_context_info, \ + coord * : sfo_nhcoord, \ + struct damage * : sfo_damage, \ + struct dgn_topology * : sfo_dgn_topology, \ + dungeon * : sfo_dungeon, \ + d_level * : sfo_d_level, \ + struct levelflags * : sfo_levelflags, \ + light_source * : sfo_ls_t, \ + struct dest_area * : sfo_dest_area, \ + struct ebones * : sfo_ebones, \ + struct edog * : sfo_edog, \ + struct egd * : sfo_egd, \ + struct emin * : sfo_emin, \ + struct engr * : sfo_engr, \ + struct epri * : sfo_epri, \ + struct eshk * : sfo_eshk, \ + struct fe * : sfo_fe, \ + struct flag * : sfo_flag, \ + struct fruit * : sfo_fruit, \ + struct gamelog_line * : sfo_gamelog_line, \ + struct kinfo * : sfo_kinfo, \ + struct linfo * : sfo_linfo, \ + struct mapseen_feat * : sfo_mapseen_feat, \ + struct mapseen_flags *: sfo_mapseen_flags, \ + struct mapseen_rooms *: sfo_mapseen_rooms, \ + struct mkroom * : sfo_mkroom, \ + struct monst * : sfo_monst, \ + struct mvitals * : sfo_mvitals, \ + struct obj * : sfo_obj, \ + struct objclass * : sfo_objclass, \ + struct q_score * : sfo_q_score, \ + struct rm * : sfo_rm, \ + struct spell * : sfo_spell, \ + struct stairway * : sfo_stairway, \ + struct s_level * : sfo_s_level, \ + struct trap * : sfo_trap, \ + struct version_info * : sfo_version_info, \ + struct you * : sfo_you \ + ) (nhfp, dt, tag) + +/* struct container * : sfo_container, */ +/* struct mapseen * : sfo_mapseen, */ +/* struct mextra * : sfo_mextra, */ +/* struct oextra * : sfo_oextra, */ +/* struct permonst * : sfo_permonst, */ + +#define sfi(nhfp, dt, tag) \ + _Generic( (dt), \ + anything * : sfi_any, \ + int16_t * : sfi_int16, \ + int32_t * : sfi_int32, \ + int64_t * : sfi_int64, \ + uchar * : sfi_uchar, \ + uint16_t * : sfi_uint16, \ + uint32_t * : sfi_uint32, \ + uint64_t * : sfi_uint64, \ + long * : sfi_long, \ + unsigned long * : sfi_ulong, \ + xint8 * : sfi_xint8, \ + struct arti_info * : sfi_arti_info, \ + struct nhrect * : sfi_nhrect, \ + struct branch * : sfi_branch, \ + struct bubble * : sfi_bubble, \ + struct cemetery * : sfi_cemetery, \ + struct context_info * : sfi_context_info, \ + coord * : sfi_nhcoord, \ + struct damage * : sfi_damage, \ + struct dgn_topology * : sfi_dgn_topology, \ + dungeon * : sfi_dungeon, \ + d_level * : sfi_d_level, \ + struct levelflags * : sfi_levelflags, \ + light_source * : sfi_ls_t, \ + struct dest_area * : sfi_dest_area, \ + struct ebones * : sfi_ebones, \ + struct edog * : sfi_edog, \ + struct egd * : sfi_egd, \ + struct emin * : sfi_emin, \ + struct engr * : sfi_engr, \ + struct epri * : sfi_epri, \ + struct eshk * : sfi_eshk, \ + struct fe * : sfi_fe, \ + struct flag * : sfi_flag, \ + struct fruit * : sfi_fruit, \ + struct gamelog_line * : sfi_gamelog_line, \ + struct kinfo * : sfi_kinfo, \ + struct linfo * : sfi_linfo, \ + struct mapseen_feat * : sfi_mapseen_feat, \ + struct mapseen_flags *: sfi_mapseen_flags, \ + struct mapseen_rooms *: sfi_mapseen_rooms, \ + struct mkroom * : sfi_mkroom, \ + struct monst * : sfi_monst, \ + struct mvitals * : sfi_mvitals, \ + struct obj * : sfi_obj, \ + struct objclass * : sfi_objclass, \ + struct q_score * : sfi_q_score, \ + struct rm * : sfi_rm, \ + struct spell * : sfi_spell, \ + struct stairway * : sfi_stairway, \ + struct s_level * : sfi_s_level, \ + struct trap * : sfi_trap, \ + struct version_info * : sfi_version_info, \ + struct you * : sfi_you \ + ) (nhfp, dt, tag) + +/* char * : sfo_char, */ +/* char * : sfi_char, */ +/* struct container * : sfi_container, */ +/* struct mapseen * : sfi_mapseen, */ +/* struct mextra * : sfi_mextra, */ +/* struct oextra * : sfi_oextra, */ +/* struct permonst * : sfi_permonst, */ + +#define Sfo_any(a,b,c) sfo(a, b, c) +#define Sfo_aligntyp(a,b,c) sfo(a, b, c) +#define Sfo_genericptr(a,b,c) sfo(a, b, c) +#define Sfo_coordxy(a,b,c) sfo(a, b, c) +#define Sfo_int16(a,b,c) sfo(a, b, c) +#define Sfo_int32(a,b,c) sfo(a, b, c) +#define Sfo_int64(a,b,c) sfo(a, b, c) +#define Sfo_uchar(a,b,c) sfo(a, b, c) +#define Sfo_unsigned(a,b,c) sfo(a, b, c) +#define Sfo_uchar(a,b,c) sfo(a, b, c) +#define Sfo_uint16(a,b,c) sfo(a, b, c) +#define Sfo_uint32(a,b,c) sfo(a, b, c) +#define Sfo_uint64(a,b,c) sfo(a, b, c) +#define Sfo_size_t(a,b,c) sfo(a, b, c) +#define Sfo_time_t(a,b,c) sfo(a, b, c) + +#define Sfo_arti_info(a,b,c) sfo(a, b, c) +#define Sfo_dgn_topology(a,b,c) sfo(a, b, c) +#define Sfo_dungeon(a,b,c) sfo(a, b, c) +#define Sfo_branch(a,b,c) sfo(a, b, c) +#define Sfo_linfo(a,b,c) sfo(a, b, c) +#define Sfo_nhcoord(a,b,c) sfo(a, b, c) +#define Sfo_d_level(a,b,c) sfo(a, b, c) +#define Sfo_mapseen_feat(a,b,c) sfo(a, b, c) +#define Sfo_mapseen_flags(a,b,c) sfo(a, b, c) +#define Sfo_mapseen_rooms(a,b,c) sfo(a, b, c) +#define Sfo_kinfo(a,b,c) sfo(a, b, c) +#define Sfo_engr(a,b,c) sfo(a, b, c) +#define Sfo_ls_t(a,b,c) sfo(a, b, c) +#define Sfo_bubble(a,b,c) sfo(a, b, c) +#define Sfo_mkroom(a,b,c) sfo(a, b, c) +#define Sfo_objclass(a,b,c) sfo(a, b, c) +#define Sfo_nhrect(a,b,c) sfo(a, b, c) +#define Sfo_fe(a,b,c) sfo(a, b, c) +#define Sfo_version_info(a,b,c) sfo(a, b, c) +#define Sfo_context_info(a,b,c) sfo(a, b, c) +#define Sfo_flag(a,b,c) sfo(a, b, c) +#define Sfo_you(a,b,c) sfo(a, b, c) +#define Sfo_mvitals(a,b,c) sfo(a, b, c) +#define Sfo_q_score(a,b,c) sfo(a, b, c) +#define Sfo_spell(a,b,c) sfo(a, b, c) +#define Sfo_dest_area(a,b,c) sfo(a, b, c) +#define Sfo_levelflags(a,b,c) sfo(a, b, c) +#define Sfo_rm(a,b,c) sfo(a, b, c) +#define Sfo_cemetery(a,b,c) sfo(a, b, c) +#define Sfo_damage(a,b,c) sfo(a, b, c) +#define Sfo_stairway(a,b,c) sfo(a, b, c) +#define Sfo_obj(a,b,c) sfo(a, b, c) +#define Sfo_monst(a,b,c) sfo(a, b, c) +#define Sfo_ebones(a,b,c) sfo(a, b, c) +#define Sfo_edog(a,b,c) sfo(a, b, c) +#define Sfo_egd(a,b,c) sfo(a, b, c) +#define Sfo_emin(a,b,c) sfo(a, b, c) +#define Sfo_engr(a,b,c) sfo(a, b, c) +#define Sfo_epri(a,b,c) sfo(a, b, c) +#define Sfo_eshk(a,b,c) sfo(a, b, c) +#define Sfo_trap(a,b,c) sfo(a, b, c) +#define Sfo_gamelog_line(a,b,c) sfo(a, b, c) +#define Sfo_fruit(a,b,c) sfo(a, b, c) +#define Sfo_s_level(a,b,c) sfo(a, b, c) +#define Sfo_short(a, b, c) sfo(a, b, c) +#define Sfo_ushort(a, b, c) sfo(a, b, c) +#define Sfo_int(a, b, c) sfo(a, b, c) +#define Sfo_unsigned(a, b, c) sfo(a, b, c) +#define Sfo_long(a,b,c) sfo(a, b, c) +#define Sfo_ulong(a,b,c) sfo(a, b, c) +#define Sfo_xint8(a, b, c) sfo(a, b, c) +#define Sfo_xint16(a, b, c) sfo(a, b, c) +/* not in _Generic */ +#define Sfo_char(a,b,c,d) sfo_char(a, b, c, d) +#define Sfo_boolean(a,b,c) sfo_boolean(a, b, c) +#define Sfo_schar(a,b,c) sfo_schar(a, b, c) +/* sfbase.c input functions */ +#define Sfi_addinfo(a,b,c) sfi(a, b, c) +#define Sfi_aligntyp(a,b,c) sfi(a, b, c) +#define Sfi_any(a,b,c) sfi(a, b, c) +#define Sfi_genericptr(a,b,c) sfi(a, b, c) +#define Sfi_coordxy(a,b,c) sfi(a, b, c) +#define Sfi_int16(a,b,c) sfi(a, b, c) +#define Sfi_int32(a,b,c) sfi(a, b, c) +#define Sfi_int64(a,b,c) sfi(a, b, c) +#define Sfi_uchar(a,b,c) sfi(a, b, c) +#define Sfi_uint16(a,b,c) sfi(a, b, c) +#define Sfi_uint32(a,b,c) sfi(a, b, c) +#define Sfi_uint64(a,b,c) sfi(a, b, c) +#define Sfi_size_t(a,b,c) sfi(a, b, c) +#define Sfi_time_t(a,b,c) sfi(a, b, c) +#define Sfi_arti_info(a,b,c) sfi(a, b, c) +#define Sfi_dungeon(a,b,c) sfi(a, b, c) +#define Sfi_dgn_topology(a,b,c) sfi(a, b, c) +#define Sfi_branch(a,b,c) sfi(a, b, c) +#define Sfi_linfo(a,b,c) sfi(a, b, c) +#define Sfi_nhcoord(a,b,c) sfi(a, b, c) +#define Sfi_d_level(a,b,c) sfi(a, b, c) +#define Sfi_mapseen_feat(a,b,c) sfi(a, b, c) +#define Sfi_mapseen_flags(a,b,c) sfi(a, b, c) +#define Sfi_mapseen_rooms(a,b,c) sfi(a, b, c) +#define Sfi_kinfo(a,b,c) sfi(a, b, c) +#define Sfi_engr(a,b,c) sfi(a, b, c) +#define Sfi_ls_t(a,b,c) sfi(a, b, c) +#define Sfi_bubble(a,b,c) sfi(a, b, c) +#define Sfi_mkroom(a,b,c) sfi(a, b, c) +#define Sfi_objclass(a,b,c) sfi(a, b, c) +#define Sfi_nhrect(a,b,c) sfi(a, b, c) +#define Sfi_fe(a,b,c) sfi(a, b, c) +#define Sfi_version_info(a,b,c) sfi(a, b, c) +#define Sfi_context_info(a,b,c) sfi(a, b, c) +#define Sfi_flag(a,b,c) sfi(a, b, c) +#define Sfi_you(a,b,c) sfi(a, b, c) +#define Sfi_mvitals(a,b,c) sfi(a, b, c) +#define Sfi_q_score(a,b,c) sfi(a, b, c) +#define Sfi_spell(a,b,c) sfi(a, b, c) +#define Sfi_dest_area(a,b,c) sfi(a, b, c) +#define Sfi_levelflags(a,b,c) sfi(a, b, c) +#define Sfi_rm(a,b,c) sfi(a, b, c) +#define Sfi_cemetery(a,b,c) sfi(a, b, c) +#define Sfi_damage(a,b,c) sfi(a, b, c) +#define Sfi_stairway(a,b,c) sfi(a, b, c) +#define Sfi_obj(a,b,c) sfi(a, b, c) +#define Sfi_monst(a,b,c) sfi(a, b, c) +#define Sfi_ebones(a,b,c) sfi(a, b, c) +#define Sfi_edog(a,b,c) sfi(a, b, c) +#define Sfi_egd(a,b,c) sfi(a, b, c) +#define Sfi_emin(a,b,c) sfi(a, b, c) +#define Sfi_engr(a,b,c) sfi(a, b, c) +#define Sfi_epri(a,b,c) sfi(a, b, c) +#define Sfi_eshk(a,b,c) sfi(a, b, c) +#define Sfi_trap(a,b,c) sfi(a, b, c) +#define Sfi_fruit(a,b,c) sfi(a, b, c) +#define Sfi_gamelog_line(a,b,c) sfi(a, b, c) +#define Sfi_s_level(a,b,c) sfi(a, b, c) +#define Sfi_short(a, b, c) sfi(a, b, c) +#define Sfi_ushort(a, b, c) sfi(a, b, c) +#define Sfi_int(a,b,c) sfi(a, b, c) +#define Sfi_unsigned(a, b, c) sfi(a, b, c) +#define Sfi_long(a,b,c) sfi(a, b, c) +#define Sfi_ulong(a,b,c) sfi(a, b, c) +#define Sfi_xint8(a, b, c) sfi(a, b, c) +#define Sfi_xint16(a, b, c) sfi(a, b, c) +/* not in _Generic */ +#define Sfi_char(a,b,c,d) sfi_char(a, b, c, d) +#define Sfi_boolean(a,b,c) sfi_boolean(a, b, c) +#define Sfi_schar(a,b,c) sfi_schar(a, b, c) +#endif + +#endif /* SAVEFILE_H */ + diff --git a/include/sfprocs.h b/include/sfprocs.h new file mode 100644 index 000000000..661d1a40a --- /dev/null +++ b/include/sfprocs.h @@ -0,0 +1,199 @@ +/* NetHack 3.6 sfprocs.h Tue Nov 6 19:38:48 2018 */ +/* Copyright (c) NetHack Development Team 2025. */ +/* NetHack may be freely redistributed. See license for details. */ + +#ifndef SFPROCS_H +#define SFPROCS_H + +#define NHTYPE_SIMPLE 1 +#define NHTYPE_COMPLEX 2 + +#define SF_PROTO(dtyp) \ + extern void sfo_##dtyp(NHFILE *, dtyp *, const char *); \ + extern void sfi_##dtyp(NHFILE *, dtyp *, const char *); \ + extern void sfo_x_##dtyp(NHFILE *, dtyp *, const char *); \ + extern void sfi_x_##dtyp(NHFILE *, dtyp *, const char *) +#define SF_PROTO_C(keyw, dtyp) \ + extern void sfo_##dtyp(NHFILE *, keyw dtyp *, const char *); \ + extern void sfi_##dtyp(NHFILE *, keyw dtyp *, const char *); \ + extern void sfo_x_##dtyp(NHFILE *, keyw dtyp *, const char *); \ + extern void sfi_x_##dtyp(NHFILE *, keyw dtyp *, const char *) +#define SF_PROTO_X(xxx, dtyp) \ + extern void sfo_##dtyp(NHFILE *, xxx *, const char *, int bfsz); \ + extern void sfi_##dtyp(NHFILE *, xxx *, const char *, int bfsz); \ + extern void sfo_x_##dtyp(NHFILE *, xxx *, const char *, int bfsz); \ + extern void sfi_x_##dtyp(NHFILE *, xxx *, const char *, int bfsz) + +SF_PROTO_C(struct, arti_info); +SF_PROTO_C(struct, nhrect); +SF_PROTO_C(struct, branch); +SF_PROTO_C(struct, bubble); +SF_PROTO_C(struct, cemetery); +SF_PROTO_C(struct, context_info); +SF_PROTO_C(struct, nhcoord); +SF_PROTO_C(struct, damage); +SF_PROTO_C(struct, dest_area); +SF_PROTO_C(struct, dgn_topology); +SF_PROTO_C(struct, dungeon); +SF_PROTO_C(struct, d_level); +SF_PROTO_C(struct, ebones); +SF_PROTO_C(struct, edog); +SF_PROTO_C(struct, egd); +SF_PROTO_C(struct, emin); +SF_PROTO_C(struct, engr); +SF_PROTO_C(struct, epri); +SF_PROTO_C(struct, eshk); +SF_PROTO_C(struct, fe); +SF_PROTO_C(struct, flag); +SF_PROTO_C(struct, fruit); +SF_PROTO_C(struct, gamelog_line); +SF_PROTO_C(struct, kinfo); +SF_PROTO_C(struct, levelflags); +SF_PROTO_C(struct, ls_t); +SF_PROTO_C(struct, linfo); +SF_PROTO_C(struct, mapseen_feat); +SF_PROTO_C(struct, mapseen_flags); +SF_PROTO_C(struct, mapseen_rooms); +SF_PROTO_C(struct, mkroom); +SF_PROTO_C(struct, monst); +SF_PROTO_C(struct, mvitals); +SF_PROTO_C(struct, obj); +SF_PROTO_C(struct, objclass); +SF_PROTO_C(struct, q_score); +SF_PROTO_C(struct, rm); +SF_PROTO_C(struct, spell); +SF_PROTO_C(struct, stairway); +SF_PROTO_C(struct, s_level); +SF_PROTO_C(struct, trap); +SF_PROTO_C(struct, version_info); +SF_PROTO_C(struct, you); +SF_PROTO_C(union, any); +SF_PROTO(int16); +SF_PROTO(int32); +SF_PROTO(int64); +SF_PROTO(uchar); +SF_PROTO(uint16); +SF_PROTO(uint32); +SF_PROTO(uint64); +SF_PROTO(long); +SF_PROTO(ulong); +SF_PROTO(xint8); +SF_PROTO(boolean); +SF_PROTO(schar); +SF_PROTO(aligntyp); +SF_PROTO(genericptr); +SF_PROTO(size_t); +SF_PROTO(time_t); +SF_PROTO(int); +SF_PROTO(unsigned); +SF_PROTO(coordxy); +SF_PROTO(short); +SF_PROTO(xint16); +SF_PROTO(ushort); +SF_PROTO_X(uint8_t, bitfield); +SF_PROTO_X(char, char); + +#undef SF_PROTO +#undef SF_PROTO_C +#undef SF_PROTO_X + +#define SF_ENTRY(dtyp) \ + void (*sf_##dtyp)(NHFILE *, dtyp *, const char *) +#define SF_ENTRY_C(keyw, dtyp) \ + void (*sf_##dtyp)(NHFILE *, keyw dtyp *, const char *) +#define SF_ENTRY_X(xxx, dtyp) \ + void (*sf_##dtyp)(NHFILE *, xxx *, const char *, int bfsz) + +struct sf_procs { + SF_ENTRY_C(struct, arti_info); + SF_ENTRY_C(struct, nhrect); + SF_ENTRY_C(struct, branch); + SF_ENTRY_C(struct, bubble); + SF_ENTRY_C(struct, cemetery); + SF_ENTRY_C(struct, context_info); + SF_ENTRY_C(struct, nhcoord); + SF_ENTRY_C(struct, damage); + SF_ENTRY_C(struct, dest_area); + SF_ENTRY_C(struct, dgn_topology); + SF_ENTRY_C(struct, dungeon); + SF_ENTRY_C(struct, d_level); + SF_ENTRY_C(struct, ebones); + SF_ENTRY_C(struct, edog); + SF_ENTRY_C(struct, egd); + SF_ENTRY_C(struct, emin); + SF_ENTRY_C(struct, engr); + SF_ENTRY_C(struct, epri); + SF_ENTRY_C(struct, eshk); + SF_ENTRY_C(struct, fe); + SF_ENTRY_C(struct, flag); + SF_ENTRY_C(struct, fruit); + SF_ENTRY_C(struct, gamelog_line); + SF_ENTRY_C(struct, kinfo); + SF_ENTRY_C(struct, levelflags); + SF_ENTRY_C(struct, ls_t); + SF_ENTRY_C(struct, linfo); + SF_ENTRY_C(struct, mapseen_feat); + SF_ENTRY_C(struct, mapseen_flags); + SF_ENTRY_C(struct, mapseen_rooms); + SF_ENTRY_C(struct, mkroom); + SF_ENTRY_C(struct, monst); + SF_ENTRY_C(struct, mvitals); + SF_ENTRY_C(struct, obj); + SF_ENTRY_C(struct, objclass); + SF_ENTRY_C(struct, q_score); + SF_ENTRY_C(struct, rm); + SF_ENTRY_C(struct, spell); + SF_ENTRY_C(struct, stairway); + SF_ENTRY_C(struct, s_level); + SF_ENTRY_C(struct, trap); + SF_ENTRY_C(struct, version_info); + SF_ENTRY_C(struct, you); + SF_ENTRY_C(union, any); + + SF_ENTRY(aligntyp); + SF_ENTRY(boolean); + SF_ENTRY(coordxy); + SF_ENTRY(genericptr); + SF_ENTRY(int); + SF_ENTRY(int16); + SF_ENTRY(int32); + SF_ENTRY(int64); + SF_ENTRY(long); + SF_ENTRY(schar); + SF_ENTRY(short); + SF_ENTRY(size_t); + SF_ENTRY(time_t); + SF_ENTRY(uchar); + SF_ENTRY(uint16); + SF_ENTRY(uint32); + SF_ENTRY(uint64); + SF_ENTRY(ulong); + SF_ENTRY(unsigned); + SF_ENTRY(ushort); + SF_ENTRY(xint16); + SF_ENTRY(xint8); + SF_ENTRY_X(char, char); + SF_ENTRY_X(uint8_t, bitfield); +}; + +#undef SF_ENTRY +#undef SF_ENTRY_C +#undef SF_ENTRY_X + +struct sf_structlevel_procs { + const char *ext; + struct sf_procs fn; /* called for structlevel (historical) */ +}; +struct sf_fieldlevel_procs { + const char *ext; + struct sf_procs fn_x; /* called for fieldlevel */ +}; +extern struct sf_structlevel_procs sfoprocs[NUM_SAVEFORMATS], sfiprocs[NUM_SAVEFORMATS]; +extern struct sf_fieldlevel_procs sfoflprocs[NUM_SAVEFORMATS], sfiflprocs[NUM_SAVEFORMATS]; +extern struct sf_structlevel_procs historical_sfo_procs; +extern struct sf_structlevel_procs historical_sfi_procs; +extern struct sf_fieldlevel_procs cnv_sfo_procs; +extern struct sf_fieldlevel_procs cnv_sfi_procs; + +#endif /* SFPROCS_H */ + diff --git a/src/artifact.c b/src/artifact.c index cd0c37bdd..ddd254285 100644 --- a/src/artifact.c +++ b/src/artifact.c @@ -71,6 +71,7 @@ static xint16 artidisco[NROFARTIFACTS]; * bulk re-init if game restart ever gets implemented. They are saved * and restored but that is done through this file so they can be local. */ + static const struct arti_info zero_artiexist = {0}; /* all bits zero */ staticfn void hack_artifacts(void); @@ -113,16 +114,11 @@ save_artifacts(NHFILE *nhfp) { int i; - for (i = 0; i < (NROFARTIFACTS + 1); ++i) { - if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) &artiexist[i], - sizeof (struct arti_info)); - } - for (i = 0; i < (NROFARTIFACTS); ++i) { - if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) &artidisco[i], - sizeof (xint16)); - } + for (i = 0; i < (NROFARTIFACTS + 1); ++i) + Sfo_arti_info(nhfp, &artiexist[i], "artiexist"); + + for (i = 0; i < NROFARTIFACTS; ++i) + Sfo_xint16(nhfp, &artidisco[i], "artidisco"); } void @@ -130,16 +126,10 @@ restore_artifacts(NHFILE *nhfp) { int i; - for (i = 0; i < (NROFARTIFACTS + 1); ++i) { - if (nhfp->structlevel) - mread(nhfp->fd, (genericptr_t) &artiexist[i], - sizeof (struct arti_info)); - } - for (i = 0; i < (NROFARTIFACTS); ++i) { - if (nhfp->structlevel) - mread(nhfp->fd, (genericptr_t) &artidisco[i], - sizeof (xint16)); - } + for (i = 0; i < (NROFARTIFACTS + 1); ++i) + Sfi_arti_info(nhfp, &artiexist[i], "artiexist"); + for (i = 0; i < NROFARTIFACTS; ++i) + Sfi_short(nhfp, &artidisco[i], "artidisco"); hack_artifacts(); /* redo non-saved special cases */ } @@ -2799,4 +2789,5 @@ permapoisoned(struct obj *obj) { return (obj && is_art(obj, ART_GRIMTOOTH)); } + /*artifact.c*/ diff --git a/src/bones.c b/src/bones.c index f165e71ea..31185dd28 100644 --- a/src/bones.c +++ b/src/bones.c @@ -610,13 +610,10 @@ savebones(int how, time_t when, struct obj *corpse) nhfp->mode = WRITING; store_version(nhfp); - /* if a bones pool digit is in use, it precedes the bonesid - string and isn't recorded in the file */ - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &c, sizeof c); - bwrite(nhfp->fd, (genericptr_t) bonesid, (unsigned) c); /* DD.nn */ - } + string and isn't recorded in the file */ + Sfo_char(nhfp, &c, "bones_count", 1); + Sfo_char(nhfp, bonesid, "bonesid", (int) c); /* DD.nnn */ savefruitchn(nhfp); update_mlstmv(); /* update monsters for eventual restoration */ savelev(nhfp, ledger_no(&u.uz)); @@ -655,7 +652,7 @@ getbones(void) return 0; } - if (validate(nhfp, gb.bones, FALSE) != 0) { + if (validate(nhfp, gb.bones, FALSE) != SF_UPTODATE) { if (!wizard) pline("Discarding unusable bones; no need to panic..."); ok = FALSE; @@ -668,26 +665,18 @@ getbones(void) return 0; } } - /* if a bones pool digit is in use, it precedes the bonesid - string and wasn't recorded in the file */ - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &c, - sizeof c); /* length including terminating '\0' */ - } - if ((unsigned) c <= sizeof oldbonesid) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) oldbonesid, - (unsigned) c); /* DD.nn or Qrrr.n for role rrr */ + Sfi_char(nhfp, &c, "bones_count", 1); /* length incl. '\0' */ + if ((unsigned) c <= sizeof oldbonesid) { + Sfi_char(nhfp, oldbonesid, "bonesid", (int) c); + } else { + if (wizard) + debugpline2("Abandoning bones , %u > %u.", + (unsigned) c, (unsigned) sizeof oldbonesid); + close_nhfile(nhfp); + compress_bonesfile(); + /* ToDo: maybe unlink these problematic bones? */ + return 0; } - } else { - if (wizard) - debugpline2("Abandoning bones , %u > %u.", (unsigned) c, - (unsigned) sizeof oldbonesid); - close_nhfile(nhfp); - compress_bonesfile(); - /* ToDo: maybe unlink these problematic bones? */ - return 0; - } if (strcmp(bonesid, oldbonesid) != 0) { char errbuf[BUFSZ]; diff --git a/src/cfgfiles.c b/src/cfgfiles.c index 3e1197a4e..52f45a7a4 100644 --- a/src/cfgfiles.c +++ b/src/cfgfiles.c @@ -1133,7 +1133,6 @@ cnf_line_PORTABLE_DEVICE_PATHS(char *bufp) #endif return TRUE; } - #endif /* SYSCF */ staticfn boolean @@ -1863,9 +1862,9 @@ vconfig_error_add(const char *str, va_list the_args) staticfn void parseformat(int *arr, char *str) { - const char *legal[] = { "historical", "lendian", "ascii" }; + const char *legal[] = { "historical", "cnv" }; int i, kwi = 0, words = 0; - char *p = str, *keywords[2]; + char *p = str, *keywords[2] = { NULL }; while (*p) { while (*p && isspace((uchar) *p)) { @@ -1937,3 +1936,4 @@ assure_syscf_file(void) /* ---------- END CONFIG FILE HANDLING ----------- */ /*cfgfiles.c*/ + diff --git a/src/decl.c b/src/decl.c index e4dc3c6e8..3430cd3a5 100644 --- a/src/decl.c +++ b/src/decl.c @@ -282,6 +282,7 @@ static const struct instance_globals_c g_init_c = { UNDEFINED_PTR, /* coder */ /* uhitm.c */ NON_PM, /* corpsenm_digested */ + FALSE, /* converted_savefile_loaded */ TRUE, /* havestate*/ }; @@ -602,7 +603,6 @@ static const struct instance_globals_o g_init_o = { UNDEFINED_PTR, /* oldfruit */ /* rumors.c */ 0, /* oracle_flag */ - UNDEFINED_PTR, /* oracle_loc */ /* uhitm.c */ FALSE, /* override_confirmation */ /* zap.c */ @@ -930,6 +930,8 @@ static const struct instance_globals_saved_n init_svn = { static const struct instance_globals_saved_o init_svo = { /* rumors.c */ 0U, /* oracle_cnt */ + UNDEFINED_PTR, /* oracle_loc */ + /* other */ 0L /* omoves */ }; diff --git a/src/dungeon.c b/src/dungeon.c index 9a43ed7ac..cbc2abd8f 100644 --- a/src/dungeon.c +++ b/src/dungeon.c @@ -32,6 +32,8 @@ struct lchoice { char menuletter; }; +static mapseen *load_mapseen(NHFILE *); + #if 0 staticfn void Fread(genericptr_t, int, int, dlb *); #endif @@ -152,49 +154,31 @@ save_dungeon( mapseen *curr_ms, *next_ms; if (perform_write) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svn.n_dgns, sizeof svn.n_dgns); - } + Sfo_int(nhfp, &svn.n_dgns, "dungeon_count"); for (i = 0; i < svn.n_dgns; ++i) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svd.dungeons[i], - sizeof (dungeon)); - } - } - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svd.dungeon_topology, - sizeof svd.dungeon_topology); - bwrite(nhfp->fd, (genericptr_t) svt.tune, sizeof tune); + Sfo_dungeon(nhfp, &svd.dungeons[i], "dungeon"); } + Sfo_dgn_topology(nhfp, &svd.dungeon_topology, "svd.dungeon_topology"); + Sfo_char(nhfp, svt.tune, "tune", (int) sizeof tune); for (count = 0, curr = svb.branches; curr; curr = curr->next) count++; - if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) &count, sizeof count); + Sfo_int(nhfp, &count, "branch_count"); for (curr = svb.branches; curr; curr = curr->next) { - if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) curr, sizeof *curr); + Sfo_branch(nhfp, curr, "branch"); } count = maxledgerno(); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &count, sizeof count); - } + Sfo_int(nhfp, &count, "level_info_count"); for (i = 0; i < count; ++i) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svl.level_info[i], - sizeof (struct linfo)); - } - } - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svi.inv_pos, sizeof svi.inv_pos); + Sfo_linfo(nhfp, &svl.level_info[i], "svl.level_info"); } + Sfo_nhcoord(nhfp, &svi.inv_pos, "svi.inv_pos"); + for (count = 0, curr_ms = svm.mapseenchn; curr_ms; curr_ms = curr_ms->next) count++; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &count, sizeof count); - } + Sfo_int(nhfp, &count, "mapseen_count"); for (curr_ms = svm.mapseenchn; curr_ms; curr_ms = curr_ms->next) { save_mapseen(nhfp, curr_ms); @@ -224,35 +208,24 @@ void restore_dungeon(NHFILE *nhfp) { branch *curr, *last; - int count = 0, i; + int count = 0; + int i; mapseen *curr_ms, *last_ms; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &svn.n_dgns, sizeof svn.n_dgns); - } + Sfi_int(nhfp, &svn.n_dgns, "dungeon_count"); for (i = 0; i < svn.n_dgns; ++i) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &svd.dungeons[i], sizeof(dungeon)); - } - } - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &svd.dungeon_topology, - sizeof svd.dungeon_topology); - } - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) svt.tune, sizeof tune); + Sfi_dungeon(nhfp, &svd.dungeons[i], "dungeon"); } + Sfi_dgn_topology(nhfp, &svd.dungeon_topology, "svd.dungeon_topology"); + Sfi_char(nhfp, svt.tune, "tune", (int) sizeof tune); + last = svb.branches = (branch *) 0; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &count, sizeof count); - } + Sfi_int(nhfp, &count, "branch_count"); for (i = 0; i < count; i++) { curr = (branch *) alloc(sizeof *curr); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) curr, sizeof *curr); - } + Sfi_branch(nhfp, curr, "branch"); curr->next = (branch *) 0; if (last) last->next = curr; @@ -261,23 +234,19 @@ restore_dungeon(NHFILE *nhfp) last = curr; } - if (nhfp->structlevel) - mread(nhfp->fd, (genericptr_t) &count, sizeof count); + Sfi_int(nhfp, &count, "level_info_count"); if (count >= MAXLINFO) panic("level information count larger (%d) than allocated size", count); for (i = 0; i < count; ++i) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &svl.level_info[i], - sizeof (struct linfo)); - } - } - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &svi.inv_pos, sizeof svi.inv_pos); - mread(nhfp->fd, (genericptr_t) &count, sizeof count); + Sfi_linfo(nhfp, &svl.level_info[i], "svl.level_info"); } + Sfi_nhcoord(nhfp, &svi.inv_pos, "svi.inv_pos"); + + Sfi_int(nhfp, &count, "mapseen_count"); + last_ms = (mapseen *) 0; for (i = 0; i < count; i++) { curr_ms = load_mapseen(nhfp); @@ -2592,19 +2561,14 @@ save_exclusions(NHFILE *nhfp) for (nez = 0, ez = sve.exclusion_zones; ez; ez = ez->next, ++nez) ; - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) - bwrite(nhfp->fd, (genericptr_t) &nez, sizeof nez); - + if (update_file(nhfp)) { + Sfo_int(nhfp, &nez, "exclusion-count"); for (ez = sve.exclusion_zones; ez; ez = ez->next) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &ez->zonetype, - sizeof ez->zonetype); - bwrite(nhfp->fd, (genericptr_t) &ez->lx, sizeof ez->lx); - bwrite(nhfp->fd, (genericptr_t) &ez->ly, sizeof ez->ly); - bwrite(nhfp->fd, (genericptr_t) &ez->hx, sizeof ez->hx); - bwrite(nhfp->fd, (genericptr_t) &ez->hy, sizeof ez->hy); - } + Sfo_xint16(nhfp, &ez->zonetype, "exclusion-zonetype"); + Sfo_coordxy(nhfp, &ez->lx, "exclusion-lx"); + Sfo_coordxy(nhfp, &ez->ly, "exclusion-ly"); + Sfo_coordxy(nhfp, &ez->hx, "exclusion-hx"); + Sfo_coordxy(nhfp, &ez->hy, "exclusion-hy"); } } } @@ -2615,20 +2579,15 @@ load_exclusions(NHFILE *nhfp) struct exclusion_zone *ez; int nez = 0; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &nez, sizeof nez); - } + Sfi_int(nhfp, &nez, "exclusion_count"); while (nez-- > 0) { ez = (struct exclusion_zone *) alloc(sizeof *ez); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &ez->zonetype, - sizeof ez->zonetype); - mread(nhfp->fd, (genericptr_t) &ez->lx, sizeof ez->lx); - mread(nhfp->fd, (genericptr_t) &ez->ly, sizeof ez->ly); - mread(nhfp->fd, (genericptr_t) &ez->hx, sizeof ez->hx); - mread(nhfp->fd, (genericptr_t) &ez->hy, sizeof ez->hy); - } + Sfi_xint16(nhfp, &ez->zonetype, "exclusion-zonetype"); + Sfi_coordxy(nhfp, &ez->lx, "exclusion-lx"); + Sfi_coordxy(nhfp, &ez->ly, "exclusion-ly"); + Sfi_coordxy(nhfp, &ez->hx, "exclusion-hx"); + Sfi_coordxy(nhfp, &ez->hy, "exclusion-hy"); ez->next = sve.exclusion_zones; sve.exclusion_zones = ez; } @@ -2699,27 +2658,18 @@ save_mapseen(NHFILE *nhfp, mapseen *mptr) for (brindx = 0, curr = svb.branches; curr; curr = curr->next, ++brindx) if (curr == mptr->br) break; - - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &brindx, sizeof brindx); - bwrite(nhfp->fd, (genericptr_t) &mptr->lev, sizeof mptr->lev); - bwrite(nhfp->fd, (genericptr_t) &mptr->feat, sizeof mptr->feat); - bwrite(nhfp->fd, (genericptr_t) &mptr->flags, sizeof mptr->flags); - bwrite(nhfp->fd, (genericptr_t) &mptr->custom_lth, - sizeof mptr->custom_lth); - } + Sfo_int(nhfp, &brindx, "mapseen-branch_index"); + Sfo_d_level(nhfp, &mptr->lev, "mapseen-d_level"); + Sfo_mapseen_feat(nhfp, &mptr->feat, "mapseen-feat"); + Sfo_mapseen_flags(nhfp, &mptr->flags, "mapseen-flags"); + Sfo_unsigned(nhfp, &mptr->custom_lth, "mapseen-custom_lth"); if (mptr->custom_lth) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) mptr->custom, - mptr->custom_lth); - } + Sfo_char(nhfp, mptr->custom, "mapseen-custom", + (int) mptr->custom_lth); } for (i = 0; i < ((MAXNROFROOMS + 1) * 2); ++i) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &mptr->msrooms[i], - sizeof (struct mapseen_rooms)); - } + Sfo_mapseen_rooms(nhfp, &mptr->msrooms[i], "mapseen-msrooms"); } savecemetery(nhfp, &mptr->final_resting_place); } @@ -2733,38 +2683,28 @@ load_mapseen(NHFILE *nhfp) load = (mapseen *) alloc(sizeof *load); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &branchnum, sizeof branchnum); - } + Sfi_int(nhfp, &branchnum, "mapseen-branch_index"); for (brindx = 0, curr = svb.branches; curr; curr = curr->next, ++brindx) if (brindx == branchnum) break; load->br = curr; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &load->lev, sizeof load->lev); - mread(nhfp->fd, (genericptr_t) &load->feat, sizeof load->feat); - mread(nhfp->fd, (genericptr_t) &load->flags, sizeof load->flags); - mread(nhfp->fd, (genericptr_t) &load->custom_lth, - sizeof load->custom_lth); - } + Sfi_d_level(nhfp, &load->lev, "mapseen-d_level"); + Sfi_mapseen_feat(nhfp, &load->feat, "mapseen-feat"); + Sfi_mapseen_flags(nhfp, &load->flags, "mapseen-flags"); + Sfi_unsigned(nhfp, &load->custom_lth, "mapseen-custom_lth"); if (load->custom_lth) { /* length doesn't include terminator (which isn't saved & restored) */ load->custom = (char *) alloc(load->custom_lth + 1); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) load->custom, - load->custom_lth); - } + Sfi_char(nhfp, load->custom, "mapseen-custom", + (int) load->custom_lth); load->custom[load->custom_lth] = '\0'; } else { load->custom = 0; } for (i = 0; i < ((MAXNROFROOMS + 1) * 2); ++i) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &load->msrooms[i], - sizeof (struct mapseen_rooms)); - } + Sfi_mapseen_rooms(nhfp, &load->msrooms[i], "mapseen-msrooms"); } restcemetery(nhfp, &load->final_resting_place); return load; @@ -3742,7 +3682,6 @@ print_mapseen( } } } - #undef OF_INTEREST #undef ADDNTOBUF #undef ADDTOBUF diff --git a/src/end.c b/src/end.c index 57b189d12..e17c17517 100644 --- a/src/end.c +++ b/src/end.c @@ -1754,11 +1754,9 @@ save_killers(NHFILE *nhfp) { struct kinfo *kptr; - if (perform_bwrite(nhfp)) { + if (update_file(nhfp)) { for (kptr = &svk.killer; kptr; kptr = kptr->next) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) kptr, sizeof (struct kinfo)); - } + Sfo_kinfo(nhfp, kptr, "kinfo"); } } if (release_data(nhfp)) { @@ -1776,9 +1774,7 @@ restore_killers(NHFILE *nhfp) struct kinfo *kptr; for (kptr = &svk.killer; kptr != (struct kinfo *) 0; kptr = kptr->next) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) kptr, sizeof (struct kinfo)); - } + Sfi_kinfo(nhfp, kptr, "kinfo"); if (kptr->next) { kptr->next = (struct kinfo *) alloc(sizeof (struct kinfo)); } @@ -1933,12 +1929,12 @@ NH_abort(char *why USED_FOR_CRASHREPORT) panictrace_setsignals(FALSE); #endif #endif /* PANICTRACE */ -#ifdef WIN32 +#if defined(WIN32) win32_abort(); #else abort(); #endif } -#undef USED_FOR_CRASHREPORT +#undef USED_FOR_CRASHREPORT /*end.c*/ diff --git a/src/engrave.c b/src/engrave.c index 2a300cfac..00602e0fc 100644 --- a/src/engrave.c +++ b/src/engrave.c @@ -1515,27 +1515,29 @@ void save_engravings(NHFILE *nhfp) { struct engr *ep, *ep2; - unsigned no_more_engr = 0; + unsigned no_more_engr = 0, engr_alloc; + unsigned szeach; for (ep = head_engr; ep; ep = ep2) { ep2 = ep->nxt_engr; if (ep->engr_alloc - && ep->engr_txt[actual_text][0] && perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &(ep->engr_alloc), - sizeof ep->engr_alloc); - bwrite(nhfp->fd, (genericptr_t) ep, - sizeof (struct engr) + ep->engr_alloc); - } + && ep->engr_txt[actual_text][0] && update_file(nhfp)) { + engr_alloc = (unsigned) ep->engr_alloc; + szeach = ep->engr_szeach; + Sfo_unsigned(nhfp, &engr_alloc, "engraving-engr_alloc"); + Sfo_engr(nhfp, ep, "engraving"); + ep->engr_txt[actual_text] = (char *)(ep + 1); + ep->engr_txt[remembered_text] = ep->engr_txt[actual_text] + szeach; + ep->engr_txt[pristine_text] = ep->engr_txt[remembered_text] + szeach; + Sfo_char(nhfp, ep->engr_txt[actual_text], "engraving-actual_text", szeach); + Sfo_char(nhfp, ep->engr_txt[remembered_text], "engraving-remembered_text", szeach); + Sfo_char(nhfp, ep->engr_txt[pristine_text], "engraving-pristine_text", szeach); } if (release_data(nhfp)) dealloc_engr(ep); } - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &no_more_engr, - sizeof no_more_engr); - } + if (update_file(nhfp)) { + Sfo_unsigned(nhfp, &no_more_engr, "engraving-engr_alloc"); } if (release_data(nhfp)) head_engr = 0; @@ -1546,25 +1548,28 @@ rest_engravings(NHFILE *nhfp) { struct engr *ep; unsigned lth = 0; + unsigned szeach; head_engr = 0; while (1) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) <h, sizeof(unsigned)); - } + Sfi_unsigned(nhfp, <h, "engraving-engr_alloc"); if (lth == 0) return; ep = newengr(lth); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) ep, sizeof (struct engr) + lth); - } + Sfi_engr(nhfp, ep, "engraving"); + szeach = ep->engr_szeach; ep->nxt_engr = head_engr; head_engr = ep; ep->engr_txt[actual_text] = (char *) (ep + 1); /* Andreas Bormann */ - ep->engr_txt[remembered_text] = ep->engr_txt[actual_text] - + ep->engr_szeach; - ep->engr_txt[pristine_text] = ep->engr_txt[remembered_text] - + ep->engr_szeach; + ep->engr_txt[remembered_text] = ep->engr_txt[actual_text] + szeach; + ep->engr_txt[pristine_text] = ep->engr_txt[remembered_text] + szeach; + Sfi_char(nhfp, ep->engr_txt[actual_text], + "engraving-actual_text", (int) szeach); + Sfi_char(nhfp, ep->engr_txt[remembered_text], + "engraving-remembered_text", (int) szeach); + Sfi_char(nhfp, ep->engr_txt[pristine_text], + "engraving-pristine_text", (int) szeach); + while (ep->engr_txt[actual_text][0] == ' ') ep->engr_txt[actual_text]++; while (ep->engr_txt[remembered_text][0] == ' ') diff --git a/src/files.c b/src/files.c index 90ab61076..238d03662 100644 --- a/src/files.c +++ b/src/files.c @@ -5,6 +5,10 @@ #define NEED_VARARGS +#if defined(WIN32) +#include "win32api.h" +#endif + #include "hack.h" #include "dlb.h" @@ -77,6 +81,9 @@ static char fqn_filename_buffer[FQN_NUMBUF][FQN_MAX_FILENAME]; #if defined(WIN32) #include +#include +#define F_OK 0 +#define access _access #endif #ifdef AMIGA @@ -96,11 +103,15 @@ extern void amii_set_text_font(char *, int); #endif #define Close close #ifndef WIN_CE +#ifdef DeleteFile +#undef DeleteFile +#endif #define DeleteFile unlink #endif #ifdef WIN32 -/*from windmain.c */ +/*from windsys.c */ extern char *translate_path_variables(const char *, char *); +extern boolean get_user_home_folder(char *, size_t); #endif #endif @@ -116,6 +127,7 @@ extern char *translate_path_variables(const char *, char *); staticfn NHFILE *new_nhfile(void); staticfn void free_nhfile(NHFILE *); + #ifdef SELECTSAVED staticfn int QSORTCALLBACK strcmp_wrap(const void *, const void *); #endif @@ -130,10 +142,17 @@ staticfn void docompress_file(const char *, boolean); #if defined(ZLIB_COMP) staticfn boolean make_compressed_name(const char *, char *); #endif + +staticfn NHFILE *problematic_savefile(int, const char *); +staticfn NHFILE *viable_nhfile(NHFILE *); +#ifdef SELECTSAVED +staticfn int QSORTCALLBACK strcmp_wrap(const void *, const void *); +#endif +staticfn char *set_bonesfile_name(char *, d_level *); +staticfn char *set_bonestemp_name(void); #ifndef USE_FCNTL staticfn char *make_lockname(const char *, char *); #endif - staticfn FILE *fopen_wizkit_file(void); staticfn void wizkit_addinv(struct obj *); boolean proc_wizkit_line(char *buf); @@ -407,7 +426,7 @@ zero_nhfile(NHFILE *nhfp) { nhfp->fd = -1; nhfp->mode = COUNTING; - nhfp->structlevel = FALSE; + nhfp->structlevel = TRUE; nhfp->fieldlevel = FALSE; nhfp->addinfo = FALSE; nhfp->bendian = IS_BIGENDIAN(); @@ -417,6 +436,9 @@ zero_nhfile(NHFILE *nhfp) nhfp->count = 0; nhfp->eof = FALSE; nhfp->fnidx = 0; + nhfp->style.deflt = FALSE; + nhfp->style.binary = TRUE; + nhfp->nhfpconvert = 0; } staticfn NHFILE * @@ -442,6 +464,12 @@ close_nhfile(NHFILE *nhfp) { if (nhfp->structlevel && nhfp->fd != -1) (void) nhclose(nhfp->fd), nhfp->fd = -1; + if (nhfp->fplog) + (void) fprintf(nhfp->fplog, "# closing\n"); + if (nhfp->fplog) + (void) fclose(nhfp->fplog); + if (nhfp->fpdebug) + (void) fclose(nhfp->fpdebug); zero_nhfile(nhfp); free_nhfile(nhfp); } @@ -449,13 +477,11 @@ close_nhfile(NHFILE *nhfp) void rewind_nhfile(NHFILE *nhfp) { - if (nhfp->structlevel) { #ifdef BSD - (void) lseek(nhfp->fd, 0L, 0); + (void) lseek(nhfp->fd, 0L, 0); #else - (void) lseek(nhfp->fd, (off_t) 0, 0); + (void) lseek(nhfp->fd, (off_t) 0, 0); #endif - } } staticfn NHFILE * @@ -465,10 +491,25 @@ viable_nhfile(NHFILE *nhfp) the pointer to the nethack file descriptor */ if (nhfp) { /* check for no open file at all, - * not a structlevel legacy file + * not a structlevel legacy file, + * nor a fieldlevel file. */ - if (nhfp->structlevel && nhfp->fd < 0) { + if (((nhfp->fd == -1) && !nhfp->fpdef) + || (nhfp->structlevel && nhfp->fd < 0) + || (nhfp->fieldlevel && !nhfp->fpdef)) { /* not viable, start the cleanup */ + if (nhfp->fieldlevel) { + if (nhfp->fpdef) { + (void) fclose(nhfp->fpdef); + nhfp->fpdef = (FILE *) 0; + } + if (nhfp->fplog) { + (void) fprintf(nhfp->fplog, "# closing, not viable\n"); + (void) fclose(nhfp->fplog); + } + if (nhfp->fpdebug) + (void) fclose(nhfp->fpdebug); + } zero_nhfile(nhfp); free_nhfile(nhfp); nhfp = (NHFILE *) 0; @@ -477,6 +518,20 @@ viable_nhfile(NHFILE *nhfp) return nhfp; } +int +nhclose(int fd) +{ + int retval = 0; + + if (fd >= 0) { + if (close_check(fd)) + bclose(fd); + else + retval = close(fd); + } + return retval; +} + /* ---------- BEGIN LEVEL FILE HANDLING ----------- */ /* Construct a file name for a level-type file, which is of the form @@ -520,6 +575,7 @@ create_levelfile(int lev, char errbuf[]) nhfp->addinfo = FALSE; nhfp->style.deflt = FALSE; nhfp->style.binary = TRUE; + nhfp->fnidx = historical; nhfp->fd = -1; nhfp->fpdef = (FILE *) 0; #if defined(MICRO) || defined(WIN32) @@ -542,6 +598,9 @@ create_levelfile(int lev, char errbuf[]) Sprintf(errbuf, "Cannot create file \"%s\" for level %d (errno %d).", gl.lock, lev, errno); +#if defined(MSDOS) + setmode(nhfp->fd, O_BINARY); +#endif } nhfp = viable_nhfile(nhfp); return nhfp; @@ -566,6 +625,7 @@ open_levelfile(int lev, char errbuf[]) nhfp->style.deflt = FALSE; nhfp->style.binary = TRUE; nhfp->ftype = NHF_LEVELFILE; + nhfp->fnidx = historical; nhfp->fd = -1; nhfp->fpdef = (FILE *) 0; } @@ -583,6 +643,9 @@ open_levelfile(int lev, char errbuf[]) Sprintf(errbuf, "Cannot open file \"%s\" for level %d (errno %d).", gl.lock, lev, errno); +#if defined(MSDOS) + setmode(nhfp->fd, O_BINARY); +#endif } nhfp = viable_nhfile(nhfp); return nhfp; @@ -631,20 +694,6 @@ strcmp_wrap(const void *p, const void *q) } #endif -int -nhclose(int fd) -{ - int retval = 0; - - if (fd >= 0) { - if (close_check(fd)) - bclose(fd); - else - retval = close(fd); - } - return retval; -} - /* ---------- END LEVEL FILE HANDLING ----------- */ /* ---------- BEGIN BONES FILE HANDLING ----------- */ @@ -731,10 +780,23 @@ create_bonesfile(d_level *lev, char **bonesid, char errbuf[]) nhfp = new_nhfile(); if (nhfp) { - nhfp->structlevel = TRUE; - nhfp->fieldlevel = FALSE; nhfp->ftype = NHF_BONESFILE; nhfp->mode = WRITING; + nhfp->structlevel = TRUE; + nhfp->fieldlevel = FALSE; + nhfp->addinfo = TRUE; + nhfp->style.deflt = TRUE; + nhfp->style.binary = TRUE; + nhfp->fnidx = historical; + nhfp->fd = -1; + nhfp->fpdef = fopen(file, nhfp->style.binary ? WRBMODE : WRTMODE); + if (nhfp->fpdef) { +#ifdef SAVEFILE_DEBUGGING + nhfp->fpdebug = fopen("create_bonesfile-debug.log", "a"); +#endif + } else { + failed = errno; + } if (nhfp->structlevel) { #if defined(MICRO) || defined(WIN32) /* Use O_TRUNC to force the file to be shortened if it already @@ -751,6 +813,9 @@ create_bonesfile(d_level *lev, char **bonesid, char errbuf[]) #endif if (nhfp->fd < 0) failed = errno; +#if defined(MSDOS) + setmode(nhfp->fd, O_BINARY); +#endif } if (failed && errbuf) /* failure explanation */ Sprintf(errbuf, "Cannot create bones \"%s\", id %s (errno %d).", @@ -814,11 +879,25 @@ open_bonesfile(d_level *lev, char **bonesid) nhfp->fieldlevel = FALSE; nhfp->ftype = NHF_BONESFILE; nhfp->mode = READING; + nhfp->addinfo = TRUE; + nhfp->style.deflt = TRUE; + nhfp->style.binary = (sysopt.bonesformat[0] != cnvascii); + nhfp->fnidx = sysopt.bonesformat[0]; + nhfp->fd = -1; + nhfp->fpdef = fopen(fq_bones, nhfp->style.binary ? RDBMODE : RDTMODE); + if (nhfp->fpdef) { +#ifdef SAVEFILE_DEBUGGING + nhfp->fpdebug = fopen("open_bonesfile-debug.log", "a"); +#endif + } if (nhfp->structlevel) { #ifdef MAC nhfp->fd = macopen(fq_bones, O_RDONLY | O_BINARY, BONE_TYPE); #else nhfp->fd = open(fq_bones, O_RDONLY | O_BINARY, 0); +#endif +#if defined(MSDOS) + setmode(nhfp->fd, O_BINARY); #endif } } @@ -829,8 +908,11 @@ open_bonesfile(d_level *lev, char **bonesid) int delete_bonesfile(d_level *lev) { + int reslt; + (void) set_bonesfile_name(gb.bones, lev); - return !(unlink(fqname(gb.bones, BONESPREFIX, 0)) < 0); + reslt = unlink(fqname(gb.bones, BONESPREFIX, 0)); + return !(reslt < 0); } /* assume we're compressing the recently read or created bonesfile, so the @@ -929,9 +1011,6 @@ set_savefile_name(boolean regularize_it) if (strlen(SAVE_EXTENSION) > (0) && !overflow) { if (strlen(gs.SAVEF) + strlen(SAVE_EXTENSION) < (SAVESIZE - 1)) { Strcat(gs.SAVEF, SAVE_EXTENSION); -#ifdef MSDOS - sfindicator = ""; -#endif } else overflow = 3; } @@ -960,8 +1039,7 @@ set_savefile_name(boolean regularize_it) void save_savefile_name(NHFILE *nhfp) { - if (nhfp->structlevel) - (void) write(nhfp->fd, (genericptr_t) gs.SAVEF, sizeof(gs.SAVEF)); + Sfo_char(nhfp, gs.SAVEF, "savefile_name", sizeof(gs.SAVEF)); } #endif @@ -999,12 +1077,9 @@ create_savefile(void) fq_save = fqname(gs.SAVEF, SAVEPREFIX, 0); nhfp = new_nhfile(); if (nhfp) { - nhfp->structlevel = TRUE; - nhfp->fieldlevel = FALSE; nhfp->ftype = NHF_SAVEFILE; nhfp->mode = WRITING; if (program_state.in_self_recover || do_historical) { - do_historical = TRUE; /* force it */ nhUse(do_historical); nhfp->structlevel = TRUE; nhfp->fieldlevel = FALSE; @@ -1014,19 +1089,24 @@ create_savefile(void) nhfp->fnidx = historical; nhfp->fd = -1; nhfp->fpdef = (FILE *) 0; - } - if (nhfp->structlevel) { +#ifdef SAVEFILE_DEBUGGING + nhfp->fplog = fopen("create-savefile.log", "w"); +#endif + } #if defined(MICRO) || defined(WIN32) nhfp->fd = open(fq_save, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK); #else #ifdef MAC - nhfp->fd = maccreat(fq_save, SAVE_TYPE); + nhfp->fd = maccreat(fq_save, SAVE_TYPE); #else - nhfp->fd = creat(fq_save, FCMASK); + nhfp->fd = creat(fq_save, FCMASK); #endif #endif /* MICRO || WIN32 */ - } +#if defined(MSDOS) || defined(WIN32) + if (nhfp->fd >= 0) + (void) setmode(nhfp->fd, O_BINARY); +#endif } #if defined(VMS) && !defined(SECURE) /* @@ -1054,8 +1134,6 @@ open_savefile(void) fq_save = fqname(gs.SAVEF, SAVEPREFIX, 0); nhfp = new_nhfile(); if (nhfp) { - nhfp->structlevel = TRUE; - nhfp->fieldlevel = FALSE; nhfp->ftype = NHF_SAVEFILE; nhfp->mode = READING; if (program_state.in_self_recover || do_historical) { @@ -1069,14 +1147,19 @@ open_savefile(void) nhfp->fnidx = historical; nhfp->fd = -1; nhfp->fpdef = (FILE *) 0; - } - if (nhfp->structlevel) { -#ifdef MAC - nhfp->fd = macopen(fq_save, O_RDONLY | O_BINARY, SAVE_TYPE); -#else - nhfp->fd = open(fq_save, O_RDONLY | O_BINARY, 0); +#ifdef SAVEFILE_DEBUGGING + nhfp->fplog = fopen("open-savefile.log", "w"); +#endif + } +#ifdef MAC + nhfp->fd = macopen(fq_save, O_RDONLY | O_BINARY, SAVE_TYPE); +#else + nhfp->fd = open(fq_save, O_RDONLY | O_BINARY, 0); +#endif +#if defined(MSDOS) || defined(WIN32) + if (nhfp->fd >= 0) + (void) setmode(nhfp->fd, O_BINARY); #endif - } } nhfp = viable_nhfile(nhfp); return nhfp; @@ -1086,7 +1169,9 @@ open_savefile(void) int delete_savefile(void) { - (void) unlink(fqname(gs.SAVEF, SAVEPREFIX, 0)); + const char *sfname = fqname(gs.SAVEF, SAVEPREFIX, 0); + + (void) unlink(sfname); return 0; /* for restore_saved_game() (ex-xxxmain.c) test */ } @@ -1096,16 +1181,16 @@ restore_saved_game(void) { const char *fq_save; NHFILE *nhfp = (NHFILE *) 0; + int sfstatus = 0; set_savefile_name(TRUE); fq_save = fqname(gs.SAVEF, SAVEPREFIX, 0); nh_uncompress(fq_save); if ((nhfp = open_savefile()) != 0) { - if (validate(nhfp, fq_save, FALSE) != 0) { + if ((sfstatus = validate(nhfp, fq_save, FALSE)) != SF_UPTODATE) { close_nhfile(nhfp); - nhfp = (NHFILE *) 0; - (void) delete_savefile(); + nhfp = problematic_savefile(sfstatus, fq_save); } } return nhfp; @@ -1165,6 +1250,7 @@ plname_from_file( NHFILE *nhfp; unsigned ln; char *result = 0; + int sfstatus = 0; Strcpy(gs.SAVEF, filename); #ifdef COMPRESS_EXTENSION @@ -1179,7 +1265,8 @@ plname_from_file( #endif nh_uncompress(gs.SAVEF); if ((nhfp = open_savefile()) != 0) { - if (validate(nhfp, filename, without_wait_synch_per_file) == 0) { + if ((sfstatus = validate(nhfp, filename, + without_wait_synch_per_file)) == SF_UPTODATE) { /* room for "name+role+race+gend+algn X" where the space before X is actually NUL and X is playmode: one of '-', 'X', or 'D' */ ln = (unsigned) PL_NSIZ_PLUS; @@ -1403,7 +1490,6 @@ docompress_file(const char *filename, boolean uncomp) #ifdef TTY_GRAPHICS boolean istty = WINDOWPORT(tty); #endif - #ifdef COMPRESS_EXTENSION xtra = COMPRESS_EXTENSION; #else @@ -1752,6 +1838,60 @@ docompress_file(const char *filename, boolean uncomp) /* ---------- END FILE COMPRESSION HANDLING ----------- */ + +/* ---------- BEGIN PROBLEMATIC SAVEFILE HANDLING ----------- */ + +static struct sfstatus_to_msg { + int sfstatus; + const char *msg; +} sf2msg[] = { + { SF_UPTODATE, "everything matches" }, + { SF_OUTDATED, "outdated savefile" }, + { SF_CRITICAL_BYTE_COUNT_MISMATCH, + "savefile critical byte-count mismatch" }, + { SF_DM_IL32LLP64_ON_ILP32LL64, "Windows x64 savefile on x86" }, + { SF_DM_I32LP64_ON_ILP32LL64, "Unix 64 savefile on x86" }, + { SF_DM_ILP32LL64_ON_I32LP64, "x86 savefile on Unix 64" }, + { SF_DM_ILP32LL64_ON_IL32LLP64, "x86 savefile on Windows x64" }, + { SF_DM_I32LP64_ON_IL32LLP64, "Unix 64 savefile on Windows x64" }, + { SF_DM_IL32LLP64_ON_I32LP64, "Windows x64 savefile on Unix 64" }, + { SF_DM_MISMATCH, "generic savefile mismatch" }, +}; + +staticfn NHFILE * +problematic_savefile(int sfstatus, const char *savefilenm) +{ + int i; + NHFILE *nhfp = (NHFILE *) 0; + + switch (sfstatus) { + case SF_UPTODATE: + break; + case SF_DM_IL32LLP64_ON_ILP32LL64: + case SF_DM_I32LP64_ON_ILP32LL64: + case SF_DM_ILP32LL64_ON_I32LP64: + case SF_DM_ILP32LL64_ON_IL32LLP64: + case SF_DM_I32LP64_ON_IL32LLP64: + case SF_DM_IL32LLP64_ON_I32LP64: + case SF_DM_MISMATCH: + case SF_OUTDATED: + case SF_CRITICAL_BYTE_COUNT_MISMATCH: + default: + for (i = 0; i < SIZE(sf2msg); ++i) { + if (sf2msg[i].sfstatus == sfstatus) { + raw_printf("\n%s is %s %s\n", + savefilenm, + (sfstatus == SF_OUTDATED) ? "an" : "a", + sf2msg[i].msg); + break; + } + } + } + return nhfp; +} + +/* ---------- END PROBLEMATIC SAVEFILE HANDLING ----------- */ + /* ---------- BEGIN FILE LOCKING HANDLING ----------- */ #if defined(NO_FILE_LINKS) || defined(USE_FCNTL) /* implies UNIX */ @@ -2413,18 +2553,22 @@ testinglog(const char *filenm, /* ad hoc file name */ #ifdef SELF_RECOVER /* ---------- BEGIN INTERNAL RECOVER ----------- */ + +extern uchar critical_sizes[], cscbuf[]; /* version.c */ + boolean recover_savefile(void) { NHFILE *gnhfp, *lnhfp, *snhfp; - int lev, savelev, hpid, pltmpsiz; + int lev, savelev, hpid, + pltmpsiz, cscount = get_critical_size_count(); xint8 levc; struct version_info version_data; int processed[256]; - char savename[SAVESIZE], errbuf[BUFSZ], indicator; + char savename[SAVESIZE], errbuf[BUFSZ], indicator, file_cscount; char tmpplbuf[PL_NSIZ_PLUS]; const char *savewrite_failure = (const char *) 0; - int ccbresult = 0; + off_t filesz = 0; for (lev = 0; lev < 256; lev++) processed[lev] = 0; @@ -2442,6 +2586,30 @@ recover_savefile(void) raw_printf("%s\n", errbuf); return FALSE; } + filesz = lseek(gnhfp->fd, 0L, SEEK_END); + (void) lseek(gnhfp->fd, 0L, SEEK_SET); + if ((size_t) filesz < (sizeof hpid + + sizeof lev + + sizeof savename + + sizeof indicator + + sizeof file_cscount + + sizeof version_data + sizeof pltmpsiz)) { + const char *fq_save; + + /* this indicates a .0 file that was created as part of + * recover that did not complete. There could be an intact + * savefile already there. Check for that and return TRUE + * if there is. */ + set_savefile_name(TRUE); + fq_save = fqname(gs.SAVEF, SAVEPREFIX, 0); + if (access(fq_save, F_OK) == 0) { + close_nhfile(gnhfp); + delete_levelfile(0); + return TRUE; + } else { + /* savefile doesn't exist, so fall through */ + } + } if (read(gnhfp->fd, (genericptr_t) &hpid, sizeof hpid) != sizeof hpid) { raw_printf("\n%s\n%s\n", "Checkpoint data incompletely written" @@ -2463,7 +2631,11 @@ recover_savefile(void) != sizeof savename) || (read(gnhfp->fd, (genericptr_t) &indicator, sizeof indicator) != sizeof indicator) - || ((ccbresult = compare_critical_bytes(gnhfp)) != 0) + || (read(gnhfp->fd, (genericptr_t) &file_cscount, sizeof file_cscount) + != sizeof file_cscount) + || (file_cscount <= cscount + && read(gnhfp->fd, (genericptr_t) &cscbuf, file_cscount) + != file_cscount) || (read(gnhfp->fd, (genericptr_t) &version_data, sizeof version_data) != sizeof version_data) || (read(gnhfp->fd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz) @@ -2476,7 +2648,9 @@ recover_savefile(void) } /* save file should contain: - * format indicator and critical_bytes + * format indicator (1 byte) + * n = count of critical size list (1 byte) + * n bytes of critical sizes (n bytes) * version info * plnametmp = player name size (int, 2 bytes) * player name (PL_NSIZ_PLUS) @@ -2486,6 +2660,7 @@ recover_savefile(void) */ /* + * * Set a flag for the savefile routines to know the * circumstances and act accordingly: * program_state.in_self_recover @@ -2509,21 +2684,19 @@ recover_savefile(void) } store_version(snhfp); + if (savewrite_failure) goto cleanup; - if (snhfp->structlevel) { - if (write(snhfp->fd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz) - != sizeof pltmpsiz) - savewrite_failure = "player name size"; - } + /* TODO: this is not a single byte, so a big-endian byte swap + * might be necessary here, if anyone is concerned about big-endian */ + Sfo_int(snhfp, &pltmpsiz, "plname-size"); + savewrite_failure = (const char *) 0; if (savewrite_failure) goto cleanup; - if (snhfp->structlevel) { - if (write(snhfp->fd, (genericptr_t) &tmpplbuf, pltmpsiz) != pltmpsiz) - savewrite_failure = "player name"; - } + Sfo_char(snhfp, tmpplbuf, "plname", pltmpsiz); + savewrite_failure = (const char *) 0; if (savewrite_failure) goto cleanup; @@ -3173,7 +3346,6 @@ Death_quote(char *buf, int bufsz) } /* ---------- END TRIBUTE ----------- */ - #ifdef LIVELOG #define LLOG_SEP "\t" /* livelog field separator, as a string literal */ #define LLOG_EOL "\n" /* end-of-line, for abstraction consistency */ diff --git a/src/hacklib.c b/src/hacklib.c index 1fb76c37a..fd8f20c91 100644 --- a/src/hacklib.c +++ b/src/hacklib.c @@ -953,5 +953,54 @@ copy_bytes(int ifd, int ofd) } while (nfrom == BUFSIZ); return TRUE; } +#define MAX_D 5 +struct datamodel_information { + int sz[MAX_D]; + const char *datamodel; +}; +static struct datamodel_information dm[] = { + { { (int) sizeof(short), (int) sizeof(int), (int) sizeof(long), + (int) sizeof(long long), (int) sizeof(genericptr_t) }, + "" }, + { { 2, 4, 4, 8, 4 }, "ILP32LL64" }, /* Windows, Unix x86 */ + { { 2, 4, 4, 8, 8 }, "IL32LLP64" }, /* Windows x64 */ + { { 2, 4, 8, 8, 8 }, "I32LP64" }, /* Unix 64-bit */ + { { 2, 8, 8, 8, 8 }, "ILP64" }, /* HAL, SPARC64 */ +}; + +const char * +datamodel(void) +{ + int i, j, matchcount; + static const char *unknown = "Unknown"; + + for (i = 1; i < SIZE(dm); ++i) { + matchcount = 0; + for (j = 0; j < MAX_D; ++j) { + if (dm[0].sz[j] == dm[i].sz[j]) + ++matchcount; + } + if (matchcount == MAX_D) + return dm[i].datamodel; + } + return unknown; +} + +const char * +what_datamodel_is_this(int szshort, int szint, int szlong, int szll, + int szptr) +{ + int i; + static const char *unknown = "Unknown"; + + for (i = 1; i < SIZE(dm); ++i) { + if (szshort == dm[i].sz[0] && szint == dm[i].sz[1] + && szlong == dm[i].sz[2] && szll == dm[i].sz[3] + && szptr == dm[i].sz[4]) + return dm[i].datamodel; + } + return unknown; +} +#undef MAX_D /*hacklib.c*/ diff --git a/src/light.c b/src/light.c index f783855eb..618ba5684 100644 --- a/src/light.c +++ b/src/light.c @@ -429,11 +429,9 @@ save_light_sources(NHFILE *nhfp, int range) discard_flashes(); gv.vision_full_recalc = 0; - if (perform_bwrite(nhfp)) { + if (update_file(nhfp)) { count = maybe_write_ls(nhfp, range, FALSE); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &count, sizeof count); - } + Sfo_int(nhfp, &count, "lightsource-count"); actual = maybe_write_ls(nhfp, range, TRUE); if (actual != count) panic("counted %d light sources, wrote %d! [range=%d]", count, @@ -482,20 +480,17 @@ restore_light_sources(NHFILE *nhfp) light_source *ls; /* restore elements */ - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &count, sizeof count); - } + Sfi_int(nhfp, &count, "lightsource-count"); while (count-- > 0) { ls = (light_source *) alloc(sizeof(light_source)); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) ls, sizeof(light_source)); - } + Sfi_ls_t(nhfp, ls, "lightsource"); ls->next = gl.light_base; gl.light_base = ls; } } + DISABLE_WARNING_FORMAT_NONLITERAL /* to support '#stats' wizard-mode command */ @@ -641,9 +636,7 @@ write_ls(NHFILE *nhfp, light_source *ls) if (ls->type == LS_OBJECT || ls->type == LS_MONSTER) { if (ls->flags & LSF_NEEDS_FIXUP) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) ls, sizeof(light_source)); - } + Sfo_ls_t(nhfp, ls, "lightsource"); } else { /* replace object pointer with id for write, then put back */ arg_save = ls->id; @@ -695,9 +688,7 @@ write_ls(NHFILE *nhfp, light_source *ls) /* TODO: cleanup this ls, or skip writing it */ } ls->flags |= LSF_NEEDS_FIXUP; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) ls, sizeof(light_source)); - } + Sfo_ls_t(nhfp, ls, "lightsource"); ls->id = arg_save; ls->flags &= ~LSF_NEEDS_FIXUP; ls->flags &= ~LSF_IS_PROBLEMATIC; @@ -985,5 +976,4 @@ wiz_light_sources(void) #undef LSF_SHOW #undef LSF_NEEDS_FIXUP #undef mon_is_local - /*light.c*/ diff --git a/src/mdlib.c b/src/mdlib.c index dc69e8a28..95d4f1f2a 100644 --- a/src/mdlib.c +++ b/src/mdlib.c @@ -56,6 +56,7 @@ static boolean date_via_env = FALSE; extern unsigned long md_ignored_features(void); +extern const char *datamodel(void); char *version_id_string(char *, size_t, const char *) NONNULL NONNULLPTRS; char *bannerc_string(char *, size_t, const char *) NONNULL NONNULLPTRS; int case_insensitive_comp(const char *, const char *) NONNULLPTRS; @@ -87,7 +88,6 @@ staticfn void build_options(void); staticfn int count_and_validate_winopts(void); staticfn void opt_out_words(char *, int *) NONNULLPTRS; staticfn void build_savebones_compat_string(void); -staticfn const char *datamodel(void); static int idxopttext, done_runtime_opt_init_once = 0; #define MAXOPT 60 /* 3.7: currently 40 lines get inserted into opttext[] */ @@ -237,41 +237,6 @@ md_ignored_features(void) ); } -#define MAX_D 5 -struct datamodel_information { - int sz[MAX_D]; - const char *datamodel; -}; - -static struct datamodel_information dm[] = { - { { (int) sizeof(short), (int) sizeof(int), (int) sizeof(long), - (int) sizeof(long long), (int) sizeof(genericptr_t) }, - "" }, - { { 2, 4, 4, 8, 4 }, "ILP32LL64" }, /* Windows, Unix x86 */ - { { 2, 4, 4, 8, 8 }, "IL32LLP64" }, /* Windows x64 */ - { { 2, 4, 8, 8, 8 }, "I32LP64" }, /* Unix 64-bit */ - { { 2, 8, 8, 8, 8 }, "ILP64" }, /* HAL, SPARC64 */ -}; - -staticfn const char * -datamodel(void) -{ - int i, j, matchcount; - static const char *unknown = "Unknown"; - - for (i = 1; i < SIZE(dm); ++i) { - matchcount = 0; - for (j = 0; j < MAX_D; ++j) { - if (dm[0].sz[j] == dm[i].sz[j]) - ++matchcount; - } - if (matchcount == MAX_D) - return dm[i].datamodel; - } - return unknown; -} -#undef MAX_D - staticfn void make_version(void) { diff --git a/src/mkmaze.c b/src/mkmaze.c index 8e09bbf79..af12ba15e 100644 --- a/src/mkmaze.c +++ b/src/mkmaze.c @@ -1720,21 +1720,17 @@ save_waterlevel(NHFILE *nhfp) if (!svb.bbubbles) return; - if (perform_bwrite(nhfp)) { + if (update_file(nhfp)) { int n = 0; for (b = svb.bbubbles; b; b = b->next) ++n; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &n, sizeof(int)); - bwrite(nhfp->fd, (genericptr_t) &svx.xmin, sizeof(int)); - bwrite(nhfp->fd, (genericptr_t) &svy.ymin, sizeof(int)); - bwrite(nhfp->fd, (genericptr_t) &svx.xmax, sizeof(int)); - bwrite(nhfp->fd, (genericptr_t) &svy.ymax, sizeof(int)); - } + Sfo_int(nhfp, &n, "waterlevel-bubble_count"); + Sfo_int(nhfp, &svx.xmin, "waterlevel-xmin"); + Sfo_int(nhfp, &svy.ymin, "waterlevel-ymin"); + Sfo_int(nhfp, &svx.xmax, "waterlevel-xmax"); + Sfo_int(nhfp, &svy.ymax, "waterlevel-ymax"); for (b = svb.bbubbles; b; b = b->next) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) b, sizeof(struct bubble)); - } + Sfo_bubble(nhfp, b, "waterlevel-bubble"); } } if (release_data(nhfp)) @@ -1748,21 +1744,15 @@ restore_waterlevel(NHFILE *nhfp) struct bubble *b = (struct bubble *) 0, *btmp; int i, n = 0; - svb.bbubbles = (struct bubble *) 0; - set_wportal(); - if (nhfp->structlevel) { - mread(nhfp->fd,(genericptr_t) &n, sizeof (int)); - mread(nhfp->fd,(genericptr_t) &svx.xmin, sizeof (int)); - mread(nhfp->fd,(genericptr_t) &svy.ymin, sizeof (int)); - mread(nhfp->fd,(genericptr_t) &svx.xmax, sizeof (int)); - mread(nhfp->fd,(genericptr_t) &svy.ymax, sizeof (int)); - } + Sfi_int(nhfp, &n, "waterlevel-bubble_count"); + Sfi_int(nhfp, &svx.xmin, "waterlevel-xmin"); + Sfi_int(nhfp, &svy.ymin, "waterlevel-ymin"); + Sfi_int(nhfp, &svx.xmax, "waterlevel-xmax"); + Sfi_int(nhfp, &svy.ymax, "waterlevel-ymax"); for (i = 0; i < n; i++) { btmp = b; b = (struct bubble *) alloc((unsigned) sizeof *b); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) b, (unsigned) sizeof *b); - } + Sfi_bubble(nhfp, b, "waterlevel-bubble"); if (btmp) { btmp->next = b; b->prev = btmp; diff --git a/src/mkroom.c b/src/mkroom.c index d96eca758..21dd56912 100644 --- a/src/mkroom.c +++ b/src/mkroom.c @@ -25,8 +25,10 @@ staticfn void mktemple(void); staticfn coord *shrine_pos(int); staticfn struct permonst *morguemon(void); staticfn struct permonst *squadmon(void); + staticfn void save_room(NHFILE *, struct mkroom *); staticfn void rest_room(NHFILE *, struct mkroom *); + staticfn boolean invalid_shop_shape(struct mkroom *sroom); #define sq(x) ((x) * (x)) @@ -845,9 +847,7 @@ save_room(NHFILE *nhfp, struct mkroom *r) * of writing the whole structure. That is I should not write * the gs.subrooms pointers, but who cares ? */ - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) r, sizeof (struct mkroom)); - } + Sfo_mkroom(nhfp, r, "room-mkroom"); for (i = 0; i < r->nsubrooms; i++) { save_room(nhfp, r->sbrooms[i]); } @@ -862,9 +862,7 @@ save_rooms(NHFILE *nhfp) short i; /* First, write the number of rooms */ - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svn.nroom, sizeof svn.nroom); - } + Sfo_int(nhfp, &svn.nroom, "room-nroom"); for (i = 0; i < svn.nroom; i++) save_room(nhfp, &svr.rooms[i]); } @@ -874,9 +872,7 @@ rest_room(NHFILE *nhfp, struct mkroom *r) { short i; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) r, sizeof (struct mkroom)); - } + Sfi_mkroom(nhfp, r, "room-mkroom"); for (i = 0; i < r->nsubrooms; i++) { r->sbrooms[i] = &gs.subrooms[gn.nsubroom]; @@ -894,9 +890,7 @@ rest_rooms(NHFILE *nhfp) { short i; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &svn.nroom, sizeof svn.nroom); - } + Sfi_int(nhfp, &svn.nroom, "room-nroom"); gn.nsubroom = 0; for (i = 0; i < svn.nroom; i++) { diff --git a/src/muse.c b/src/muse.c index b044af098..42243c832 100644 --- a/src/muse.c +++ b/src/muse.c @@ -3115,7 +3115,7 @@ muse_unslime( * Monsters don't start with oil and don't actively pick up oil * so this may never occur in a real game. (Possible though; * nymph can steal potions of oil; shapechanger could take on - * nymph form or vacuum up stuff as a g.cube and then eventually + * nymph form or vacuum up stuff as a gel.cube and then eventually * engage with a green slime.) */ diff --git a/src/nhlua.c b/src/nhlua.c index 080cf1552..0a77eb108 100644 --- a/src/nhlua.c +++ b/src/nhlua.c @@ -1264,6 +1264,8 @@ get_nh_lua_variables(void) RESTORE_WARNING_UNREACHABLE_CODE +/* char *lua_data; */ + /* save nh_lua_variables table to file */ void save_luadata(NHFILE *nhfp) @@ -1274,11 +1276,8 @@ save_luadata(NHFILE *nhfp) if (!lua_data) lua_data = dupstr(emptystr); lua_data_len = Strlen(lua_data) + 1; /* +1: include the terminator */ - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &lua_data_len, - (unsigned) sizeof lua_data_len); - bwrite(nhfp->fd, (genericptr_t) lua_data, lua_data_len); - } + Sfo_unsigned(nhfp, &lua_data_len, "luadata-lua_data_len"); + Sfo_char(nhfp, lua_data, "lua_data", lua_data_len); free(lua_data); } @@ -1288,14 +1287,10 @@ restore_luadata(NHFILE *nhfp) { unsigned lua_data_len = 0; char *lua_data; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &lua_data_len, - (unsigned) sizeof lua_data_len); - } + + Sfi_unsigned(nhfp, &lua_data_len, "luadata-lua_data_len"); lua_data = (char *) alloc(lua_data_len); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) lua_data, lua_data_len); - } + Sfi_char(nhfp, lua_data, "luadata", lua_data_len); if (!gl.luacore) l_nhcore_init(); luaL_loadstring(gl.luacore, lua_data); diff --git a/src/o_init.c b/src/o_init.c index 42fbf73a1..04730e3a2 100644 --- a/src/o_init.c +++ b/src/o_init.c @@ -375,22 +375,15 @@ savenames(NHFILE *nhfp) int i; unsigned int len; - if (perform_bwrite(nhfp)) { - for (i = 0; i < (MAXOCLASSES + 2); ++i) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svb.bases[i], sizeof (int)); - } + if (update_file(nhfp)) { + for (i = 0; i < (MAXOCLASSES + 2); ++i) { + Sfo_int(nhfp, &svb.bases[i], "names-bases"); } for (i = 0; i < NUM_OBJECTS; ++i) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svd.disco[i], sizeof (short)); - } + Sfo_short(nhfp, &svd.disco[i], "names-disco"); } for (i = 0; i < NUM_OBJECTS; ++i) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &objects[i], - sizeof (struct objclass)); - } + Sfo_objclass(nhfp, &objects[i], "names-objclass"); } } /* as long as we use only one version of Hack we @@ -398,12 +391,11 @@ savenames(NHFILE *nhfp) oc_uname for all objects */ for (i = 0; i < NUM_OBJECTS; i++) if (objects[i].oc_uname) { - if (perform_bwrite(nhfp)) { + if (update_file(nhfp)) { len = Strlen(objects[i].oc_uname) + 1; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &len, sizeof len); - bwrite(nhfp->fd, (genericptr_t) &objects[i].oc_uname[0], len); - } + Sfo_unsigned(nhfp, &len, "names-len"); + Sfo_char(nhfp, objects[i].oc_uname, "names-oc_uname", + (int) len); } if (release_data(nhfp)) { free((genericptr_t) objects[i].oc_uname); @@ -419,30 +411,19 @@ restnames(NHFILE *nhfp) unsigned int len = 0; for (i = 0; i < (MAXOCLASSES + 2); ++i) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &svb.bases[i], sizeof(int)); - } + Sfi_int(nhfp, &svb.bases[i], "names-bases"); } for (i = 0; i < NUM_OBJECTS; ++i) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &svd.disco[i], sizeof(short)); - } + Sfi_short(nhfp, &svd.disco[i], "names-disco"); } for (i = 0; i < NUM_OBJECTS; ++i) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &objects[i], - sizeof(struct objclass)); - } + Sfi_objclass(nhfp, &objects[i], "names-objclass"); } for (i = 0; i < NUM_OBJECTS; i++) { if (objects[i].oc_uname) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &len, sizeof len); - } + Sfi_unsigned(nhfp, &len, "names-len"); objects[i].oc_uname = (char *) alloc(len); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &objects[i].oc_uname[0], len); - } + Sfi_char(nhfp, objects[i].oc_uname, "names-oc_uname", (int) len); } } #ifdef TILES_IN_GLYPHMAP diff --git a/src/options.c b/src/options.c index 82e1bafbb..090300fe1 100644 --- a/src/options.c +++ b/src/options.c @@ -814,7 +814,7 @@ freeroleoptvals(void) void saveoptvals(NHFILE *nhfp) { - if (perform_bwrite(nhfp)) { + if (update_file(nhfp)) { char *val; unsigned len; int i, j; @@ -823,11 +823,9 @@ saveoptvals(NHFILE *nhfp) for (j = 0; j < num_opt_phases; ++j) { val = roleoptvals[i][j]; len = val ? Strlen(val) + 1 : 0; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &len, sizeof len); - if (val) - bwrite(nhfp->fd, (genericptr_t) val, len); - } + Sfo_unsigned(nhfp, &len, "optvals-len"); + if (val) + Sfo_char(nhfp, val, "optvals-val", len); } } if (release_data(nhfp)) @@ -846,10 +844,10 @@ restoptvals(NHFILE *nhfp) for (i = 0; i < 4; ++i) for (j = 0; j < num_opt_phases; ++j) { /* len includes terminating '\0' for non-Null values */ - mread(nhfp->fd, (genericptr_t) &len, sizeof len); + Sfi_unsigned(nhfp, &len, "optvals-len"); if (len) { val = roleoptvals[i][j] = (char *) alloc(len); - mread(nhfp->fd, (genericptr_t) val, len); + Sfi_char(nhfp, val, "opvals-val", (int) len); } else { roleoptvals[i][j] = NULL; } @@ -7127,6 +7125,8 @@ initoptions_init(void) boolean have_branch = (nomakedefs.git_branch && *nomakedefs.git_branch); go.opt_phase = builtin_opt; /* Did I need to move this here? */ + /* initialize the function pointers for saving the game */ + sf_init(); memcpy(allopt, allopt_init, sizeof(allopt)); determine_ambiguities(); @@ -7777,6 +7777,7 @@ msgtype_free(void) tmp2 = tmp->next; free((genericptr_t) tmp->pattern); regex_free(tmp->regex); + tmp->regex = 0; free((genericptr_t) tmp); } gp.plinemsg_types = (struct plinemsg_type *) 0; diff --git a/src/region.c b/src/region.c index b38ba0d7c..b0aeb1127 100644 --- a/src/region.c +++ b/src/region.c @@ -12,6 +12,7 @@ #define NO_CALLBACK (-1) +void free_region(NhRegion *); boolean inside_gas_cloud(genericptr, genericptr); boolean expire_gas_cloud(genericptr, genericptr); boolean inside_rect(NhRect *, int, int); @@ -24,7 +25,6 @@ boolean mon_in_region(NhRegion *, struct monst *); #if 0 NhRegion *clone_region(NhRegion *); #endif -void free_region(NhRegion *); void add_region(NhRegion *); void remove_region(NhRegion *); @@ -739,72 +739,49 @@ save_regions(NHFILE *nhfp) int i, j; unsigned n; - if (!perform_bwrite(nhfp)) + if (!update_file(nhfp)) goto skip_lots; - if (nhfp->structlevel) { - /* timestamp */ - bwrite(nhfp->fd, (genericptr_t) &svm.moves, sizeof svm.moves); - bwrite(nhfp->fd, (genericptr_t) &svn.n_regions, sizeof svn.n_regions); - } + /* timestamp */ + Sfo_long(nhfp, &svm.moves, "region-tmstamp"); + Sfo_int(nhfp, &svn.n_regions, "region-region_count"); + for (i = 0; i < svn.n_regions; i++) { r = gr.regions[i]; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &r->bounding_box, - sizeof (NhRect)); - bwrite(nhfp->fd, (genericptr_t) &r->nrects, sizeof (short)); - } + Sfo_nhrect(nhfp, &r->bounding_box, "region-bounding_box"); + Sfo_short(nhfp, &r->nrects, "region-nrects"); for (j = 0; j < r->nrects; j++) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &r->rects[j], - sizeof (NhRect)); - } + Sfo_nhrect(nhfp, &r->rects[j], "region-rect"); } - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &r->attach_2_u, sizeof (boolean)); - bwrite(nhfp->fd, (genericptr_t) &r->attach_2_m, sizeof (unsigned)); - } - + Sfo_boolean(nhfp, &r->attach_2_u, "region-attach_2_u"); + Sfo_unsigned(nhfp, &r->attach_2_m, "region-attach_2_m"); + n = 0; n = !r->enter_msg ? 0U : (unsigned) strlen(r->enter_msg); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &n, sizeof n); - } + Sfo_unsigned(nhfp, &n, "region-enter_msg_length"); if (n > 0) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) r->enter_msg, n); - } + Sfo_char(nhfp, (char *) r->enter_msg, + "region-enter_msg", (int) n); } n = !r->leave_msg ? 0U : (unsigned) strlen(r->leave_msg); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &n, sizeof n); - } + Sfo_unsigned(nhfp, &n, "region-leave_msg_length"); if (n > 0) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) r->leave_msg, n); - } - } - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &r->ttl, sizeof (long)); - bwrite(nhfp->fd, (genericptr_t) &r->expire_f, sizeof (short)); - bwrite(nhfp->fd, (genericptr_t) &r->can_enter_f, sizeof (short)); - bwrite(nhfp->fd, (genericptr_t) &r->enter_f, sizeof (short)); - bwrite(nhfp->fd, (genericptr_t) &r->can_leave_f, sizeof (short)); - bwrite(nhfp->fd, (genericptr_t) &r->leave_f, sizeof (short)); - bwrite(nhfp->fd, (genericptr_t) &r->inside_f, sizeof (short)); - bwrite(nhfp->fd, (genericptr_t) &r->player_flags, - sizeof (unsigned)); - bwrite(nhfp->fd, (genericptr_t) &r->n_monst, sizeof (short)); + Sfo_char(nhfp, (char *) r->leave_msg, "region-leave_msg", (int) n); } + Sfo_long(nhfp, &r->ttl, "region-ttl"); + Sfo_short(nhfp, &r->expire_f, "region-expire_f"); + Sfo_short(nhfp, &r->can_enter_f, "region-can_enter_f"); + Sfo_short(nhfp, &r->enter_f, "region-enter_f"); + Sfo_short(nhfp, &r->can_leave_f, "region-can_leave_f"); + Sfo_short(nhfp, &r->leave_f, "region-leave_f"); + Sfo_short(nhfp, &r->inside_f, "region-inside_f"); + Sfo_unsigned(nhfp, &r->player_flags, "region-player_flags"); + Sfo_short(nhfp, &r->n_monst, "region-monster_count"); + for (j = 0; j < r->n_monst; j++) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &r->monsters[j], - sizeof (unsigned)); - } - } - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &r->visible, sizeof (boolean)); - bwrite(nhfp->fd, (genericptr_t) &r->glyph, sizeof (int)); - bwrite(nhfp->fd, (genericptr_t) &r->arg, sizeof (anything)); + Sfo_unsigned(nhfp, &r->monsters[j], "region-monster"); } + Sfo_boolean(nhfp, &r->visible, "region-visible"); + Sfo_int(nhfp, &r->glyph, "region-glyph"); + Sfo_any(nhfp, &r->arg, "region-arg"); } skip_lots: @@ -823,105 +800,77 @@ rest_regions(NHFILE *nhfp) boolean ghostly = (nhfp->ftype == NHF_BONESFILE); clear_regions(); /* Just for security */ - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &tmstamp, sizeof(tmstamp)); - } + Sfi_long(nhfp, &tmstamp, "region-tmstamp"); if (ghostly) tmstamp = 0; else tmstamp = (svm.moves - tmstamp); - - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &svn.n_regions, sizeof svn.n_regions); - } - + Sfi_int(nhfp, &svn.n_regions, "region-region_count"); gm.max_regions = svn.n_regions; if (svn.n_regions > 0) gr.regions = (NhRegion **) alloc(svn.n_regions * sizeof (NhRegion *)); for (i = 0; i < svn.n_regions; i++) { r = gr.regions[i] = (NhRegion *) alloc(sizeof (NhRegion)); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &r->bounding_box, sizeof (NhRect)); - mread(nhfp->fd, (genericptr_t) &r->nrects, sizeof (short)); - } + Sfi_nhrect(nhfp, &r->bounding_box, "region-bounding box"); + Sfi_short(nhfp, &r->nrects, "region-nrects"); if (r->nrects > 0) r->rects = (NhRect *) alloc(r->nrects * sizeof (NhRect)); else r->rects = (NhRect *) 0; for (j = 0; j < r->nrects; j++) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &r->rects[j], sizeof(NhRect)); - } - } - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &r->attach_2_u, sizeof (boolean)); - mread(nhfp->fd, (genericptr_t) &r->attach_2_m, sizeof (unsigned)); - mread(nhfp->fd, (genericptr_t) &n, sizeof n); + Sfi_nhrect(nhfp, &r->rects[j], "region-rect"); } + + Sfi_boolean(nhfp, &r->attach_2_u, "region-attach_2_u"); + Sfi_unsigned(nhfp, &r->attach_2_m, "region-attach_2_m"); + Sfi_unsigned(nhfp, &n, "region-enter_msg_length"); if (n > 0) { msg_buf = (char *) alloc(n + 1); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) msg_buf, n); - } + Sfi_char(nhfp, msg_buf, "region-enter_msg", n); msg_buf[n] = '\0'; } else { msg_buf = (char *) 0; } r->enter_msg = (const char *) msg_buf; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &n, sizeof n); - } - if (n > 0) { + Sfi_unsigned(nhfp, &n, "region-leave_msg_length"); + if (n > 0) { msg_buf = (char *) alloc(n + 1); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) msg_buf, n); - } + Sfi_char(nhfp, msg_buf, "region-leave_msg", n); msg_buf[n] = '\0'; - } else { - msg_buf = (char *) 0; - } - r->leave_msg = (const char *) msg_buf; + r->leave_msg = (const char *) msg_buf; + } else { + msg_buf = (char *) 0; + } + r->leave_msg = (const char *) msg_buf; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &r->ttl, sizeof(long)); - } + Sfi_long(nhfp, &r->ttl, "region-ttl"); /* check for expired region */ if (r->ttl >= 0L) r->ttl = (r->ttl > tmstamp) ? r->ttl - tmstamp : 0L; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &r->expire_f, sizeof (short)); - mread(nhfp->fd, (genericptr_t) &r->can_enter_f, sizeof (short)); - mread(nhfp->fd, (genericptr_t) &r->enter_f, sizeof (short)); - mread(nhfp->fd, (genericptr_t) &r->can_leave_f, sizeof (short)); - mread(nhfp->fd, (genericptr_t) &r->leave_f, sizeof (short)); - mread(nhfp->fd, (genericptr_t) &r->inside_f, sizeof (short)); - mread(nhfp->fd, (genericptr_t) &r->player_flags, - sizeof (unsigned)); - } + Sfi_short(nhfp, &r->expire_f, "region-expire_f"); + Sfi_short(nhfp, &r->can_enter_f, "region-can_enter_f"); + Sfi_short(nhfp, &r->enter_f, "region-enter_f"); + Sfi_short(nhfp, &r->can_leave_f, "region-can_leave_f"); + Sfi_short(nhfp, &r->leave_f, "region-leave_f"); + Sfi_short(nhfp, &r->inside_f, "region-inside_f"); + Sfi_unsigned(nhfp, &r->player_flags, "region-player_flags"); if (ghostly) { /* settings pertained to old player */ clear_hero_inside(r); clear_heros_fault(r); } - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &r->n_monst, sizeof (short)); - } + Sfi_short(nhfp, &r->n_monst, "region-monster_count"); if (r->n_monst > 0) r->monsters = (unsigned *) alloc(r->n_monst * sizeof (unsigned)); else r->monsters = (unsigned *) 0; r->max_monst = r->n_monst; for (j = 0; j < r->n_monst; j++) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &r->monsters[j], - sizeof(unsigned)); - } - } - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &r->visible, sizeof (boolean)); - mread(nhfp->fd, (genericptr_t) &r->glyph, sizeof (int)); - mread(nhfp->fd, (genericptr_t) &r->arg, sizeof (anything)); + Sfi_unsigned(nhfp, &r->monsters[j], "region-monster"); } + Sfi_boolean(nhfp, &r->visible, "region-visible"); + Sfi_int(nhfp, &r->glyph, "region-glyph"); + Sfi_any(nhfp, &r->arg, "region-arg"); } /* remove expired regions, do not trigger the expire_f callback (yet!); also update monster lists if this data is coming from a bones file */ diff --git a/src/restore.c b/src/restore.c index dc89bd33d..77e4e2383 100644 --- a/src/restore.c +++ b/src/restore.c @@ -59,12 +59,8 @@ extern int amii_numcolors; #define Is_IceBox(o) ((o)->otyp == ICE_BOX ? TRUE : FALSE) -/* third arg passed to mread() should be 'unsigned' but most calls use - sizeof so are attempting to pass 'size_t'; mread()'s prototype results - in an implicit conversion; this macro does it explicitly */ -#define Mread(fd,adr,siz) mread((fd), (genericptr_t) (adr), (unsigned) (siz)) - /* Recalculate svl.level.objects[x][y], since this info was not saved. */ + staticfn void find_lev_obj(void) { @@ -129,14 +125,10 @@ restlevchn(NHFILE *nhfp) s_level *tmplev, *x; svs.sp_levchn = (s_level *) 0; - if (nhfp->structlevel) { - Mread(nhfp->fd, &cnt, sizeof cnt); - } + Sfi_int(nhfp, &cnt, "levchn-lev_count"); for (; cnt > 0; cnt--) { tmplev = (s_level *) alloc(sizeof(s_level)); - if (nhfp->structlevel) { - Mread(nhfp->fd, tmplev, sizeof *tmplev); - } + Sfi_s_level(nhfp, tmplev, "levchn-s_level"); if (!svs.sp_levchn) svs.sp_levchn = tmplev; @@ -157,19 +149,15 @@ restdamage(NHFILE *nhfp) struct damage *tmp_dam; boolean ghostly = (nhfp->ftype == NHF_BONESFILE); - if (nhfp->structlevel) { - Mread(nhfp->fd, &dmgcount, sizeof dmgcount); - } + Sfi_unsigned(nhfp, &dmgcount, "damage-damage_count"); counter = (int) dmgcount; if (!counter) return; do { tmp_dam = (struct damage *) alloc(sizeof *tmp_dam); - if (nhfp->structlevel) { - Mread(nhfp->fd, tmp_dam, sizeof *tmp_dam); - } + Sfi_damage(nhfp, tmp_dam, "damage"); if (ghostly) tmp_dam->when += (svm.moves - svo.omoves); @@ -183,11 +171,9 @@ staticfn void restobj(NHFILE *nhfp, struct obj *otmp) { int buflen = 0; + unsigned omid = 0; - if (nhfp->structlevel) { - Mread(nhfp->fd, otmp, sizeof *otmp); - } - + Sfi_obj(nhfp, otmp, "obj"); otmp->lua_ref_cnt = 0; /* next object pointers are invalid; otmp->cobj needs to be left as is--being non-null is key to restoring container contents */ @@ -197,20 +183,14 @@ restobj(NHFILE *nhfp, struct obj *otmp) otmp->oextra = newoextra(); /* oname - object's name */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &buflen, sizeof buflen); - } + Sfi_int(nhfp, &buflen, "obj-oname_length"); if (buflen > 0) { /* includes terminating '\0' */ new_oname(otmp, buflen); - if (nhfp->structlevel) { - Mread(nhfp->fd, ONAME(otmp), buflen); - } + Sfi_char(nhfp, ONAME(otmp), "obj-oname", buflen); } /* omonst - corpse or statue might retain full monster details */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &buflen, sizeof buflen); - } + Sfi_int(nhfp, &buflen, "obj-omonst_length"); if (buflen > 0) { newomonst(otmp); /* this is actually a monst struct, so we @@ -219,24 +199,19 @@ restobj(NHFILE *nhfp, struct obj *otmp) } /* omailcmd - feedback mechanism for scroll of mail */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &buflen, sizeof buflen); - } + Sfi_int(nhfp, &buflen, "obj-omail_length"); if (buflen > 0) { char *omailcmd = (char *) alloc(buflen); - if (nhfp->structlevel) { - Mread(nhfp->fd, omailcmd, buflen); - } + Sfi_char(nhfp, omailcmd, "obj-omailcmd", buflen); new_omailcmd(otmp, omailcmd); free((genericptr_t) omailcmd); } /* omid - monster id number, connecting corpse to ghost */ newomid(otmp); /* superfluous; we're already allocated otmp->oextra */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &OMID(otmp), sizeof OMID(otmp)); - } + Sfi_unsigned(nhfp, &omid, "obj-omid_length"); + OMID(otmp) = omid; } } @@ -249,9 +224,7 @@ restobjchn(NHFILE *nhfp, boolean frozen) boolean ghostly = (nhfp->ftype == NHF_BONESFILE); while (1) { - if (nhfp->structlevel) { - Mread(nhfp->fd, &buflen, sizeof buflen); - } + Sfi_int(nhfp, &buflen, "obj-obj_length"); if (buflen == -1) break; @@ -287,6 +260,7 @@ restobjchn(NHFILE *nhfp, boolean frozen) for (otmp3 = otmp->cobj; otmp3; otmp3 = otmp3->nobj) otmp3->ocontainer = otmp; } + if (otmp->bypass) otmp->bypass = 0; if (!ghostly) { @@ -304,7 +278,6 @@ restobjchn(NHFILE *nhfp, boolean frozen) impossible("Restobjchn: error reading objchn."); otmp2->nobj = 0; } - return first; } @@ -314,9 +287,7 @@ restmon(NHFILE *nhfp, struct monst *mtmp) { int buflen = 0, mc = 0; - if (nhfp->structlevel) { - Mread(nhfp->fd, mtmp, sizeof *mtmp); - } + Sfi_monst(nhfp, mtmp, "monst"); /* next monster pointer is invalid */ mtmp->nmon = (struct monst *) 0; @@ -325,84 +296,54 @@ restmon(NHFILE *nhfp, struct monst *mtmp) mtmp->mextra = newmextra(); /* mgivenname - monster's name */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &buflen, sizeof buflen); - } + Sfi_int(nhfp, &buflen, "monst-mgivenname_length"); if (buflen > 0) { /* includes terminating '\0' */ new_mgivenname(mtmp, buflen); - if (nhfp->structlevel) { - Mread(nhfp->fd, MGIVENNAME(mtmp), buflen); - } + Sfi_char(nhfp, MGIVENNAME(mtmp), "monst-mgivenname", (int) buflen); } /* egd - vault guard */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &buflen, sizeof buflen); - } + Sfi_int(nhfp, &buflen, "monst-egd_length"); if (buflen > 0) { newegd(mtmp); - if (nhfp->structlevel) { - Mread(nhfp->fd, EGD(mtmp), sizeof(struct egd)); - } + Sfi_egd(nhfp, EGD(mtmp), "monst-egd"); } /* epri - temple priest */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &buflen, sizeof buflen); - } + Sfi_int(nhfp, &buflen, "monst-epri_length"); if (buflen > 0) { newepri(mtmp); - if (nhfp->structlevel) { - Mread(nhfp->fd, EPRI(mtmp), sizeof(struct epri)); - } + Sfi_epri(nhfp, EPRI(mtmp), "monst-epri"); } /* eshk - shopkeeper */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &buflen, sizeof buflen); - } + Sfi_int(nhfp, &buflen, "monst-eshk_length"); if (buflen > 0) { neweshk(mtmp); - if (nhfp->structlevel) { - Mread(nhfp->fd, ESHK(mtmp), sizeof(struct eshk)); - } + Sfi_eshk(nhfp, ESHK(mtmp), "monst-eshk"); } /* emin - minion */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &buflen, sizeof buflen); - } + Sfi_int(nhfp, &buflen, "monst-emin_length"); if (buflen > 0) { newemin(mtmp); - if (nhfp->structlevel) { - Mread(nhfp->fd, EMIN(mtmp), sizeof(struct emin)); - } + Sfi_emin(nhfp, EMIN(mtmp), "monst-emin"); } /* edog - pet */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &buflen, sizeof buflen); - } + Sfi_int(nhfp, &buflen, "monst-edog_length"); if (buflen > 0) { newedog(mtmp); - if (nhfp->structlevel) { - Mread(nhfp->fd, EDOG(mtmp), sizeof(struct edog)); - } + Sfi_edog(nhfp, EDOG(mtmp), "monst-edog"); /* sanity check to prevent rn2(0) */ if (EDOG(mtmp)->apport <= 0) { EDOG(mtmp)->apport = 1; } } /* ebones */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &buflen, sizeof buflen); - } + Sfi_int(nhfp, &buflen, "monst-ebones_length"); if (buflen > 0) { newebones(mtmp); - if (nhfp->structlevel) { - Mread(nhfp->fd, EBONES(mtmp), sizeof(struct ebones)); - } + Sfi_ebones(nhfp, EBONES(mtmp), "monst-ebones"); } /* mcorpsenm - obj->corpsenm for mimic posing as corpse or statue (inline int rather than pointer to something) */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &mc, sizeof mc); - } + Sfi_int(nhfp, &mc, "monst-mcorpsenm"); MCORPSENM(mtmp) = mc; } /* mextra */ } @@ -416,9 +357,7 @@ restmonchn(NHFILE *nhfp) boolean ghostly = (nhfp->ftype == NHF_BONESFILE); while (1) { - if (nhfp->structlevel) { - Mread(nhfp->fd, &buflen, sizeof buflen); - } + Sfi_int(nhfp, &buflen, "monst-monst_length"); if (buflen == -1) break; @@ -494,9 +433,7 @@ loadfruitchn(NHFILE *nhfp) flist = 0; for (;;) { fnext = newfruit(); - if (nhfp->structlevel) { - Mread(nhfp->fd, fnext, sizeof *fnext); - } + Sfi_fruit(nhfp, fnext, "fruit"); if (fnext->fid != 0) { fnext->nextf = flist; flist = fnext; @@ -546,29 +483,29 @@ restgamestate(NHFILE *nhfp) int i; struct flag newgameflags; struct context_info newgamecontext; /* all 0, but has some pointers */ - struct obj *otmp; struct obj *bc_obj; char timebuf[15]; unsigned long uid = 0; boolean defer_perm_invent, restoring_special; + struct obj *otmp; - if (nhfp->structlevel) { - Mread(nhfp->fd, &uid, sizeof uid); - } - + Sfi_ulong(nhfp, &uid, "gamestate-uid"); if (SYSOPT_CHECK_SAVE_UID && uid != (unsigned long) getuid()) { /* strange ... */ - /* for wizard mode, issue a reminder; for others, treat it - as an attempt to cheat and refuse to restore this file */ - pline("Saved game was not yours."); - if (!wizard) + if (!gc.converted_savefile_loaded) + /* for wizard mode, issue a reminder; for others, treat it + as an attempt to cheat and refuse to restore this file */ + pline("Saved game was not yours."); + if (wizard || gc.converted_savefile_loaded) { + if (gc.converted_savefile_loaded) + gc.converted_savefile_loaded = FALSE; + } else { return FALSE; + } } newgamecontext = svc.context; /* copy statically init'd context */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &svc.context, sizeof svc.context); - } + Sfi_context_info(nhfp, &svc.context, "gamestate-context"); svc.context.warntype.species = (ismnum(svc.context.warntype.speciesidx)) ? &mons[svc.context.warntype.speciesidx] : (struct permonst *) 0; @@ -580,9 +517,7 @@ restgamestate(NHFILE *nhfp) file option values instead of keeping old save file option values if partial restore fails and we resort to starting a new game */ newgameflags = flags; - if (nhfp->structlevel) { - Mread(nhfp->fd, &flags, sizeof flags); - } + Sfi_flag(nhfp, &flags, "gamestate-flags"); /* avoid keeping permanent inventory window up to date during restore (setworn() calls update_inventory); attempting to include the cost @@ -610,9 +545,8 @@ restgamestate(NHFILE *nhfp) #ifdef AMII_GRAPHICS amii_setpens(amii_numcolors); /* use colors from save file */ #endif - if (nhfp->structlevel) { - Mread(nhfp->fd, &u, sizeof u); - } + + Sfi_you(nhfp, &u, "gamestate-you"); gy.youmonst.cham = u.mcham; if (restoring_special && iflags.explore_error_flag) { @@ -622,17 +556,11 @@ restgamestate(NHFILE *nhfp) u.uhp = 0; } - if (nhfp->structlevel) { - Mread(nhfp->fd, timebuf, 14); - } + Sfi_char(nhfp, timebuf, "gamestate-ubirthday", 14); timebuf[14] = '\0'; ubirthday = time_from_yyyymmddhhmmss(timebuf); - if (nhfp->structlevel) { - Mread(nhfp->fd, &urealtime.realtime, sizeof urealtime.realtime); - } - if (nhfp->structlevel) { - Mread(nhfp->fd, timebuf, 14); - } + Sfi_long(nhfp, &urealtime.realtime, "gamestate-realtime"); + Sfi_char(nhfp, timebuf, "gamestate-start_timing", 14); timebuf[14] = '\0'; urealtime.start_timing = time_from_yyyymmddhhmmss(timebuf); @@ -672,6 +600,7 @@ restgamestate(NHFILE *nhfp) /* restore dangling (not on floor or in inventory) ball and/or chain */ bc_obj = restobjchn(nhfp, FALSE); + while (bc_obj) { struct obj *nobj = bc_obj->nobj; @@ -680,13 +609,12 @@ restgamestate(NHFILE *nhfp) setworn(bc_obj, bc_obj->owornmask); bc_obj = nobj; } + gm.migrating_objs = restobjchn(nhfp, FALSE); gm.migrating_mons = restmonchn(nhfp); for (i = 0; i < NUMMONS; ++i) { - if (nhfp->structlevel) { - Mread(nhfp->fd, &svm.mvitals[i], sizeof (struct mvitals)); - } + Sfi_mvitals(nhfp, &svm.mvitals[i], "gamestate-mvitals"); } /* * There are some things after this that can have unintended display @@ -712,26 +640,19 @@ restgamestate(NHFILE *nhfp) restore_dungeon(nhfp); restlevchn(nhfp); - if (nhfp->structlevel) { - Mread(nhfp->fd, &svm.moves, sizeof svm.moves); - } + Sfi_long(nhfp, &svm.moves, "gamestate-moves"); /* hero_seq isn't saved and restored because it can be recalculated */ gh.hero_seq = svm.moves << 3; /* normally handled in moveloop() */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &svq.quest_status, sizeof svq.quest_status); - } + Sfi_q_score(nhfp, &svq.quest_status, "gamestate-quest_status"); + for (i = 0; i < (MAXSPELL + 1); ++i) { - if (nhfp->structlevel) { - Mread(nhfp->fd, &svs.spl_book[i], - sizeof (struct spell)); - } + Sfi_spell(nhfp, &svs.spl_book[i], "gamestate-spl_book"); } restore_artifacts(nhfp); restore_oracles(nhfp); - if (nhfp->structlevel) { - Mread(nhfp->fd, svp.pl_character, sizeof svp.pl_character); - Mread(nhfp->fd, svp.pl_fruit, sizeof svp.pl_fruit); - } + Sfi_char(nhfp, svp.pl_character, + "gamestate-pl_character", sizeof svp.pl_character); + Sfi_char(nhfp, svp.pl_fruit, "gamestate-pl_fruit", sizeof svp.pl_fruit); freefruitchn(gf.ffruit); /* clean up fruit(s) made by initoptions() */ gf.ffruit = loadfruitchn(nhfp); @@ -782,6 +703,21 @@ restlevelfile(xint8 ltmp) return 2; } +/* + * restore_saved_game() prior to this left us at this position in + * the savefile for dorecover(): + * + * format indicator (1 byte) + * n = count of critical size list (1 byte) + * n bytes of critical sizes (n bytes) + * version info + * --> plnametmp = player name size (int, 2 bytes) + * player name (PL_NSIZ_PLUS) + * current level (including pets) + * (non-level-based) game state + * other levels + */ + int dorecover(NHFILE *nhfp) { @@ -792,6 +728,19 @@ dorecover(NHFILE *nhfp) program_state.restoring = REST_GSTATE; get_plname_from_file(nhfp, svp.plname, TRUE); + /* + * The position in the save file is now here: + * + * format indicator (1 byte) + * n = count of critical size list (1 byte) + * n bytes of critical sizes (n bytes) + * version info + * plnametmp = player name size (int, 2 bytes) + * player name (PL_NSIZ_PLUS) + * --> current level (including pets) + * (non-level-based) game state + * other levels + */ getlev(nhfp, 0, (xint8) 0); if (!restgamestate(nhfp)) { NHFILE tnhfp; @@ -855,10 +804,8 @@ dorecover(NHFILE *nhfp) #endif restoreinfo.mread_flags = 1; /* return despite error */ while (1) { - if (nhfp->structlevel) { - Mread(nhfp->fd, <mp, sizeof ltmp); - } - if (restoreinfo.mread_flags == -1) + Sfi_xint8(nhfp, <mp, "gamestate-level_number"); + if (nhfp->eof) break; getlev(nhfp, 0, ltmp); #ifdef MICRO @@ -949,16 +896,11 @@ rest_stairs(NHFILE *nhfp) stairway_free_all(); while (1) { - if (nhfp->structlevel) { - Mread(nhfp->fd, &buflen, sizeof buflen); - } - + Sfi_int(nhfp, &buflen, "stairs-staircount"); if (buflen == -1) break; - if (nhfp->structlevel) { - Mread(nhfp->fd, &stway, sizeof stway); - } + Sfi_stairway(nhfp, &stway, "stairs-stairway"); if (program_state.restoring != REST_GSTATE && stway.tolev.dnum == u.uz.dnum) { /* stairway dlevel is relative, make it absolute */ @@ -978,22 +920,29 @@ restcemetery(NHFILE *nhfp, struct cemetery **cemeteryaddr) struct cemetery *bonesinfo, **bonesaddr; int cflag = 0; - if (nhfp->structlevel) { - Mread(nhfp->fd, &cflag, sizeof cflag); - } + Sfi_int(nhfp, &cflag, "cemetery-cemetery_flag"); if (cflag == 0) { bonesaddr = cemeteryaddr; do { bonesinfo = (struct cemetery *) alloc(sizeof *bonesinfo); - if (nhfp->structlevel) { - Mread(nhfp->fd, bonesinfo, sizeof *bonesinfo); - } + Sfi_cemetery(nhfp, bonesinfo, "cemetery-bonesinfo"); *bonesaddr = bonesinfo; bonesaddr = &(*bonesaddr)->next; } while (*bonesaddr); } else { *cemeteryaddr = 0; } + if ((nhfp->mode & CONVERTING) != 0) { + struct cemetery *thisbones, *nextbones; + + /* free the memory */ + nextbones = *cemeteryaddr; + while ((thisbones = nextbones) != 0) { + nextbones = thisbones->next; + free((genericptr_t)thisbones); + } + *cemeteryaddr = 0; + } } /*ARGSUSED*/ @@ -1004,9 +953,7 @@ rest_levl(NHFILE *nhfp) for (c = 0; c < COLNO; ++c) { for (r = 0; r < ROWNO; ++r) { - if (nhfp->structlevel) { - Mread(nhfp->fd, &levl[c][r], sizeof (struct rm)); - } + Sfi_rm(nhfp, &levl[c][r], "location-rm"); } } } @@ -1043,10 +990,13 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) if (ghostly) clear_id_mapping(); +#if 0 #if defined(MSDOS) || defined(OS2) if (nhfp->structlevel) setmode(nhfp->fd, O_BINARY); #endif +#endif + /* Load the old fruit info. We have to do it first, so the * information is available when restoring the objects. */ @@ -1054,13 +1004,9 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) go.oldfruit = loadfruitchn(nhfp); /* First some sanity checks */ - if (nhfp->structlevel) { - Mread(nhfp->fd, &hpid, sizeof hpid); - } - - if (nhfp->structlevel) { - Mread(nhfp->fd, &dlvl, sizeof dlvl); - } + Sfi_int(nhfp, &hpid, "gamestate-hackpid"); +/* CHECK: This may prevent restoration */ + Sfi_xint8(nhfp, &dlvl, "gamestate-dlvl"); if ((pid && pid != hpid) || (lev && dlvl != lev)) { char trickbuf[BUFSZ]; @@ -1075,42 +1021,38 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) } restcemetery(nhfp, &svl.level.bonesinfo); rest_levl(nhfp); - for (c = 0; c < COLNO; ++c) + + for (c = 0; c < COLNO; ++c) { for (r = 0; r < ROWNO; ++r) { - if (nhfp->structlevel) { - Mread(nhfp->fd, &svl.lastseentyp[c][r], sizeof (schar)); - } - } - Mread(nhfp->fd, &svo.omoves, sizeof svo.omoves); - elapsed = svm.moves - svo.omoves; + Sfi_schar(nhfp, &svl.lastseentyp[c][r], "lastseentyp"); + } + } + Sfi_long(nhfp, &svo.omoves, "lev-timestmp"); + elapsed = (svm.moves - svo.omoves); rest_stairs(nhfp); - if (nhfp->structlevel) { - Mread(nhfp->fd, &svu.updest, sizeof svu.updest); - Mread(nhfp->fd, &svd.dndest, sizeof svd.dndest); - Mread(nhfp->fd, &svl.level.flags, sizeof svl.level.flags); - } + Sfi_dest_area(nhfp, &svu.updest, "lev-updest"); + Sfi_dest_area(nhfp, &svd.dndest, "lev-dndest"); + Sfi_levelflags(nhfp, &svl.level.flags, "lev-level_flags"); + if (svd.doors) { free(svd.doors); svd.doors = 0; } - if (nhfp->structlevel) { - Mread(nhfp->fd, &svd.doors_alloc, sizeof svd.doors_alloc); - } + + Sfi_int(nhfp, &svd.doors_alloc, "lev-doors_alloc"); if (svd.doors_alloc) { /* avoid pointless alloc(0) */ - svd.doors = (coord *) alloc(svd.doors_alloc * sizeof(coord)); + svd.doors = (coord *) alloc(svd.doors_alloc * sizeof (coord)); tmpc = svd.doors; for (i = 0; i < svd.doors_alloc; ++i) { - if (nhfp->structlevel) { - Mread(nhfp->fd, tmpc, sizeof (coord)); - } + Sfi_nhcoord(nhfp, tmpc, "lev-doors"); tmpc++; } } rest_rooms(nhfp); /* No joke :-) */ if (svn.nroom) { gd.doorindex = svr.rooms[svn.nroom - 1].fdoor - + svr.rooms[svn.nroom - 1].doorct; + + svr.rooms[svn.nroom - 1].doorct; } else { gd.doorindex = 0; } @@ -1123,9 +1065,7 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) gf.ftrap = 0; for (;;) { trap = newtrap(); - if (nhfp->structlevel) { - Mread(nhfp->fd, trap, sizeof *trap); - } + Sfi_trap(nhfp, trap, "trap"); if (trap->tx != 0) { if (program_state.restoring != REST_GSTATE && trap->dst.dnum == u.uz.dnum) { @@ -1147,6 +1087,7 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) gb.billobjs = restobjchn(nhfp, FALSE); rest_engravings(nhfp); + /* reset level.monsters for new level */ for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) @@ -1192,6 +1133,7 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) if (ghostly || (elapsed > 00 && elapsed > (long) rnd(10))) hide_monst(mtmp); } + restdamage(nhfp); rest_regions(nhfp); rest_bubbles(nhfp); /* for water and air; empty marker on other levels */ @@ -1265,7 +1207,6 @@ getlev(NHFILE *nhfp, int pid, xint8 lev) } } } - /* must come after all mons & objs are restored */ relink_timers(ghostly); relink_light_sources(ghostly); @@ -1288,13 +1229,12 @@ get_plname_from_file( int pltmpsiz = 0; plbuf[0] = '\0'; - if (nhfp->structlevel) { - (void) read(nhfp->fd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz); - /* pltmpsiz should now be PL_NSIZ_PLUS */ - (void) read(nhfp->fd, (genericptr_t) plbuf, pltmpsiz); - /* plbuf[PL_NSIZ_PLUS-2] should be '\0'; - plbuf[PL_NSIZ_PLUS-1] should be '-' or 'X' or 'D' */ - } + + Sfi_int(nhfp, &pltmpsiz, "plname-size"); + /* pltmpsiz should now be PL_NSIZ_PLUS */ + Sfi_char(nhfp, plbuf, "plname", pltmpsiz); + /* plbuf[PL_NSIZ_PLUS-2] should be '\0'; + plbuf[PL_NSIZ_PLUS-1] should be '-' or 'X' or 'D' */ /* "-race-role-gend-algn" is already present except that it has been hidden by replacing the initial dash with NUL; if we want that information, replace the NUL with a dash */ @@ -1316,10 +1256,11 @@ rest_bubbles(NHFILE *nhfp) clouds are present is recorded during save so that we don't have to know what level is being restored */ bbubbly = 0; - if (nhfp->structlevel) { - Mread(nhfp->fd, &bbubbly, sizeof bbubbly); - } - + Sfi_xint8(nhfp, &bbubbly, "bubbles-bbubbly"); +#if 0 + if (nhfp->structlevel) + xxread(nhfp->fd, &bbubbly, sizeof bbubbly); +#endif if (bbubbly) restore_waterlevel(nhfp); } @@ -1332,20 +1273,14 @@ restore_gamelog(NHFILE *nhfp) struct gamelog_line tmp = { 0 }; while (1) { - if (nhfp->structlevel) { - Mread(nhfp->fd, &slen, sizeof slen); - } + Sfi_int(nhfp, &slen, "gamelog-length"); if (slen == -1) break; if (slen > ((BUFSZ*2) - 1)) panic("restore_gamelog: msg too big (%d)", slen); - if (nhfp->structlevel) { - Mread(nhfp->fd, msg, slen); - } + Sfi_char(nhfp, msg, "gamelog-gamelog_text", slen); msg[slen] = '\0'; - if (nhfp->structlevel) { - Mread(nhfp->fd, &tmp, sizeof tmp); - } + Sfi_gamelog_line(nhfp, &tmp, "gamelog-gamelog_line"); gamelog_add(tmp.flags, tmp.turn, msg); } } @@ -1353,20 +1288,17 @@ restore_gamelog(NHFILE *nhfp) staticfn void restore_msghistory(NHFILE *nhfp) { - int msgsize = 0, msgcount = 0; + int msgsize = 0; + int msgcount = 0; char msg[BUFSZ]; while (1) { - if (nhfp->structlevel) { - Mread(nhfp->fd, &msgsize, sizeof msgsize); - } + Sfi_int(nhfp, &msgsize, "msghistory-length"); if (msgsize == -1) break; if (msgsize > BUFSZ - 1) panic("restore_msghistory: msg too big (%d)", msgsize); - if (nhfp->structlevel) { - Mread(nhfp->fd, msg, msgsize); - } + Sfi_char(nhfp, msg, "msghistory-msg", msgsize); msg[msgsize] = '\0'; putmsghistory(msg, TRUE); ++msgcount; @@ -1552,22 +1484,4 @@ restore_menu( } #endif /* SELECTSAVED */ -int -validate(NHFILE *nhfp, const char *name, boolean without_waitsynch_perfile) -{ - unsigned long utdflags = 0L; - boolean reslt = FALSE; - - if (nhfp->structlevel) - utdflags |= UTD_CHECKSIZES; - if (without_waitsynch_perfile) - utdflags |= UTD_WITHOUT_WAITSYNCH_PERFILE; - if (!(reslt = uptodate(nhfp, name, utdflags))) - return 1; - - return 0; -} - -#undef Mread - /*restore.c*/ diff --git a/src/rumors.c b/src/rumors.c index d1d709516..2e58d6225 100644 --- a/src/rumors.c +++ b/src/rumors.c @@ -584,10 +584,10 @@ init_oracles(dlb *fp) (void) dlb_fgets(line, sizeof line, fp); if (sscanf(line, "%5d\n", &cnt) == 1 && cnt > 0) { svo.oracle_cnt = (unsigned) cnt; - go.oracle_loc = (unsigned long *) alloc((unsigned) cnt * sizeof(long)); + svo.oracle_loc = (unsigned long *) alloc((unsigned) cnt * sizeof(long)); for (i = 0; i < cnt; i++) { (void) dlb_fgets(line, sizeof line, fp); - (void) sscanf(line, "%5lx\n", &go.oracle_loc[i]); + (void) sscanf(line, "%5lx\n", &svo.oracle_loc[i]); } } return; @@ -598,17 +598,11 @@ save_oracles(NHFILE *nhfp) { int i; - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svo.oracle_cnt, - sizeof svo.oracle_cnt); - } + if (update_file(nhfp)) { + Sfo_unsigned(nhfp, &svo.oracle_cnt, "oracle-oracle_cnt"); if (svo.oracle_cnt) { for (i = 0; (unsigned) i < svo.oracle_cnt; ++i) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &go.oracle_loc[i], - sizeof (unsigned long)); - } + Sfo_ulong(nhfp, &svo.oracle_loc[i], "oracle-oracle_loc"); } } } @@ -616,9 +610,8 @@ save_oracles(NHFILE *nhfp) if (svo.oracle_cnt) { svo.oracle_cnt = 0, go.oracle_flg = 0; } - if (go.oracle_loc) { - free((genericptr_t) go.oracle_loc); - go.oracle_loc = 0; + if (svo.oracle_loc) { + free((genericptr_t) svo.oracle_loc); } } } @@ -628,18 +621,12 @@ restore_oracles(NHFILE *nhfp) { int i; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &svo.oracle_cnt, - sizeof svo.oracle_cnt); - } + Sfi_unsigned(nhfp, &svo.oracle_cnt, "oracle-oracle_cnt"); if (svo.oracle_cnt) { - go.oracle_loc = + svo.oracle_loc = (unsigned long *) alloc(svo.oracle_cnt * sizeof (unsigned long)); for (i = 0; (unsigned) i < svo.oracle_cnt; ++i) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &go.oracle_loc[i], - sizeof (unsigned long)); - } + Sfi_ulong(nhfp, &svo.oracle_loc[i], "oracle-oracle_loc"); } go.oracle_flg = 1; /* no need to call init_oracles() */ } @@ -672,9 +659,9 @@ outoracle(boolean special, boolean delphi) if (svo.oracle_cnt <= 1 && !special) goto close_oracles; /*(shouldn't happen)*/ oracle_idx = special ? 0 : rnd((int) svo.oracle_cnt - 1); - (void) dlb_fseek(oracles, (long) go.oracle_loc[oracle_idx], SEEK_SET); + (void) dlb_fseek(oracles, (long) svo.oracle_loc[oracle_idx], SEEK_SET); if (!special) /* move offset of very last one into this slot */ - go.oracle_loc[oracle_idx] = go.oracle_loc[--svo.oracle_cnt]; + svo.oracle_loc[oracle_idx] = svo.oracle_loc[--svo.oracle_cnt]; tmpwin = create_nhwindow(NHW_TEXT); if (delphi) diff --git a/src/save.c b/src/save.c index 69b9de6cb..4e4f568a3 100644 --- a/src/save.c +++ b/src/save.c @@ -115,6 +115,7 @@ dosave0(void) clear_nhwindow(WIN_MESSAGE); There("seems to be an old save file."); if (y_n("Overwrite the old file?") == 'n') { + //nh_sfconvert(fq_save); nh_compress(fq_save); goto done; } @@ -129,6 +130,10 @@ dosave0(void) (void) delete_savefile(); /* ab@unido */ goto done; } + if (nhfp && nhfp->fplog) { + /* (void) fprintf(nhfp->fplog, "# just opened\n"); */ + nhfp->count = 0L; + } vision_recalc(2); /* shut down vision to prevent problems in the event of an impossible() call */ @@ -150,8 +155,6 @@ dosave0(void) #endif nhfp->mode = WRITING | FREEING; store_version(nhfp); - if (nhfp && nhfp->fplog) - (void) fprintf(nhfp->fplog, "# post-validation\n"); store_plname_in_file(nhfp); /* savelev() might save uball and uchain, releasing their memory if FREEING, so we need to check their status now; if hero is swallowed, @@ -206,9 +209,7 @@ dosave0(void) } getlev(onhfp, svh.hackpid, ltmp); close_nhfile(onhfp); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) <mp, sizeof ltmp); /* lvl no. */ - } + Sfo_xint8(nhfp, <mp, "gamestate-level_number"); savelev(nhfp, ltmp); /* actual level*/ delete_levelfile(ltmp); } @@ -220,6 +221,7 @@ dosave0(void) /* get rid of current level --jgm */ delete_levelfile(ledger_no(&u.uz)); delete_levelfile(0); + ///nh_sfconvert(fq_save); nh_compress(fq_save); /* this should probably come sooner... */ program_state.something_worth_saving = 0; @@ -239,28 +241,23 @@ save_gamelog(NHFILE *nhfp) while (tmp) { tmp2 = tmp->next; - if (perform_bwrite(nhfp)) { + if (nhfp->mode & (COUNTING | WRITING)) { slen = Strlen(tmp->text); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &slen, sizeof slen); - bwrite(nhfp->fd, (genericptr_t) tmp->text, slen); - bwrite(nhfp->fd, (genericptr_t) tmp, - sizeof (struct gamelog_line)); - } + Sfo_int(nhfp, &slen, "gamelog-length"); + Sfo_char(nhfp, tmp->text, "gamelog-gamelog_text", slen); + Sfo_gamelog_line(nhfp, tmp, "gamelog-gamelog_line"); } - if (release_data(nhfp)) { + if (nhfp->mode & FREEING) { free((genericptr_t) tmp->text); free((genericptr_t) tmp); } tmp = tmp2; } - if (perform_bwrite(nhfp)) { + if (nhfp->mode & (COUNTING | WRITING)) { slen = -1; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &slen, sizeof slen); - } + Sfo_int(nhfp, &slen, "gamelog-length"); } - if (release_data(nhfp)) + if (nhfp->mode & FREEING) gg.gamelog = NULL; } @@ -272,21 +269,16 @@ savegamestate(NHFILE *nhfp) program_state.saving++; /* caller should/did already set this... */ uid = (unsigned long) getuid(); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &uid, sizeof uid); - bwrite(nhfp->fd, (genericptr_t) &svc.context, sizeof svc.context); - bwrite(nhfp->fd, (genericptr_t) &flags, sizeof flags); - } + Sfo_ulong(nhfp, &uid, "gamestate-uid"); + Sfo_context_info(nhfp, &svc.context, "gamestate-context"); + Sfo_flag(nhfp, &flags, "gamestate-flags"); urealtime.finish_time = getnow(); urealtime.realtime += timet_delta(urealtime.finish_time, urealtime.start_timing); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &u, sizeof u); - bwrite(nhfp->fd, yyyymmddhhmmss(ubirthday), 14); - bwrite(nhfp->fd, (genericptr_t) &urealtime.realtime, - sizeof urealtime.realtime); - bwrite(nhfp->fd, yyyymmddhhmmss(urealtime.start_timing), 14); - } + Sfo_you(nhfp, &u, "gamestate-you"); + Sfo_char(nhfp, yyyymmddhhmmss(ubirthday), "gamestate-ubirthday", 14); + Sfo_long(nhfp, &urealtime.realtime, "gamestate-realtime"); + Sfo_char(nhfp, yyyymmddhhmmss(urealtime.start_timing), "gamestate-start_timing", 14); /* this is the value to use for the next update of urealtime.realtime */ urealtime.start_timing = urealtime.finish_time; save_killers(nhfp); @@ -307,32 +299,20 @@ savegamestate(NHFILE *nhfp) if (release_data(nhfp)) gm.migrating_mons = (struct monst *) 0; for (i = 0; i < NUMMONS; ++i) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svm.mvitals[i], - sizeof (struct mvitals)); - } + Sfo_mvitals(nhfp, &svm.mvitals[i], "gamestate-mvitals"); } - save_dungeon(nhfp, (boolean) !!perform_bwrite(nhfp), + save_dungeon(nhfp, (boolean) !!update_file(nhfp), (boolean) !!release_data(nhfp)); savelevchn(nhfp); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svm.moves, sizeof svm.moves); - bwrite(nhfp->fd, (genericptr_t) &svq.quest_status, - sizeof svq.quest_status); - } + Sfo_long(nhfp, &svm.moves, "gamestate-moves"); + Sfo_q_score(nhfp, &svq.quest_status, "gamestate-quest_status"); for (i = 0; i < (MAXSPELL + 1); ++i) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svs.spl_book[i], - sizeof(struct spell)); - } + Sfo_spell(nhfp, &svs.spl_book[i], "gamestate-spl_book"); } save_artifacts(nhfp); save_oracles(nhfp); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) svp.pl_character, - sizeof svp.pl_character); - bwrite(nhfp->fd, (genericptr_t) svp.pl_fruit, sizeof svp.pl_fruit); - } + Sfo_char(nhfp, svp.pl_character, "gamestate-pl_character", sizeof svp.pl_character); + Sfo_char(nhfp, svp.pl_fruit, "gamestate-pl_fruit", sizeof svp.pl_fruit); savefruitchn(nhfp); savenames(nhfp); save_msghistory(nhfp); @@ -391,9 +371,7 @@ savestateinlock(void) return; } - if (nhfp->structlevel) { - (void) read(nhfp->fd, (genericptr_t) &hpid, sizeof hpid); - } + Sfi_int(nhfp, &hpid, "gamestate-hackpid"); if (svh.hackpid != hpid) { Sprintf(whynot, "Level #0 pid (%d) doesn't match ours (%d)!", hpid, svh.hackpid); @@ -416,16 +394,11 @@ savestateinlock(void) return; } nhfp->mode = WRITING; - if (nhfp->structlevel) - (void) write(nhfp->fd, (genericptr_t) &svh.hackpid, - sizeof svh.hackpid); + Sfo_int(nhfp, &svh.hackpid, "gamestate-hackpid"); if (flags.ins_chkpt) { int currlev = ledger_no(&u.uz); - if (nhfp->structlevel) { - (void) write(nhfp->fd, (genericptr_t) &currlev, - sizeof currlev); - } + Sfo_int(nhfp, &currlev, "gamestate-savestateinlock"); save_savefile_name(nhfp); store_version(nhfp); store_plname_in_file(nhfp); @@ -453,7 +426,7 @@ savelev(NHFILE *nhfp, xint8 lev) if not, we need to set it for save_bubbles(); caveat: if the player quits during character selection, u.uz won't be set yet but we'll be called during run-down */ - if (set_uz_save && perform_bwrite(nhfp)) { + if (set_uz_save && (nhfp->mode & (COUNTING | WRITING))) { if (u.uz.dnum == 0 && u.uz.dlevel == 0) { program_state.something_worth_saving = 0; panic("savelev: where are we?"); @@ -511,10 +484,8 @@ savelev_core(NHFILE *nhfp, xint8 lev) if (lev >= 0 && lev <= maxledgerno()) svl.level_info[lev].flags |= VISITED; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svh.hackpid, sizeof svh.hackpid); - bwrite(nhfp->fd, (genericptr_t) &lev, sizeof lev); - } + Sfo_int(nhfp, &svh.hackpid, "gamestate-hackpid"); + Sfo_xint8(nhfp, &lev, "gamestate-dlvl"); } /* bones info comes before level data; the intent is for an external @@ -528,35 +499,25 @@ savelev_core(NHFILE *nhfp, xint8 lev) goto skip_lots; savelevl(nhfp); - for (c = 0; c < COLNO; ++c) + for (c = 0; c < COLNO; ++c) { for (r = 0; r < ROWNO; ++r) { - bwrite(nhfp->fd, (genericptr_t) &svl.lastseentyp[c][r], - sizeof(schar)); + Sfo_schar(nhfp, &svl.lastseentyp[c][r], "lastseentyp"); } - /* svm.moves below will actually be read back into svo.omoves on restore */ - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svm.moves, sizeof svm.moves); } + /* svm.moves will actually be read back into svo.omoves on restore */ + Sfo_long(nhfp, &svm.moves, "lev-timestmp"); save_stairs(nhfp); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svu.updest, sizeof(dest_area)); - bwrite(nhfp->fd, (genericptr_t) &svd.dndest, sizeof(dest_area)); - bwrite(nhfp->fd, (genericptr_t) &svl.level.flags, - sizeof svl.level.flags); - } - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svd.doors_alloc, - sizeof svd.doors_alloc); - } + Sfo_dest_area(nhfp, &svu.updest, "lev-updest"); + Sfo_dest_area(nhfp, &svd.dndest, "lev-dndest"); + Sfo_levelflags(nhfp, &svl.level.flags, "lev-level_flags"); + + Sfo_int(nhfp, &svd.doors_alloc, "lev-doors_alloc"); /* don't rely on underlying write() behavior to write - * nothing if count arg is 0, just skip it */ + * nothing if count arg is 0, just skip it */ if (svd.doors_alloc) { tmpc = svd.doors; for (i = 0; i < svd.doors_alloc; ++i) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) tmpc, - sizeof (coord)); - } + Sfo_nhcoord(nhfp, tmpc, "lev-doors"); tmpc++; } } @@ -602,11 +563,8 @@ savelevl(NHFILE *nhfp) for (x = 0; x < COLNO; x++) { for (y = 0; y < ROWNO; y++) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &levl[x][y], - sizeof(struct rm)); - } - } + Sfo_rm(nhfp, &levl[x][y], "location-rm"); + } } return; } @@ -626,9 +584,12 @@ save_bubbles(NHFILE *nhfp, xint8 lev) bbubbly = 0; if (lev == ledger_no(&water_level) || lev == ledger_no(&air_level)) bbubbly = lev; /* non-zero */ - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &bbubbly, sizeof bbubbly); - } + if (update_file(nhfp)) + Sfo_xint8(nhfp, &bbubbly, "bubbles-bbubbly"); +#if 0 + if (nhfp->structlevel) + xxwrite(nhfp->fd, (genericptr_t) &bbubbly, sizeof bbubbly); +#endif if (bbubbly) save_waterlevel(nhfp); /* save air bubbles or clouds */ @@ -642,18 +603,14 @@ savecemetery(NHFILE *nhfp, struct cemetery **cemeteryaddr) int flag; flag = *cemeteryaddr ? 0 : -1; - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &flag, sizeof flag); - } + if (update_file(nhfp)) { + Sfo_int(nhfp, &flag, "cemetery-cemetery_flag"); } nextbones = *cemeteryaddr; while ((thisbones = nextbones) != 0) { nextbones = thisbones->next; - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) thisbones, sizeof *thisbones); - } + if (update_file(nhfp)) { + Sfo_cemetery(nhfp, thisbones, "cemetery-bonesinfo"); } if (release_data(nhfp)) free((genericptr_t) thisbones); @@ -671,16 +628,12 @@ savedamage(NHFILE *nhfp) damageptr = svl.level.damagelist; for (tmp_dam = damageptr; tmp_dam; tmp_dam = tmp_dam->next) xl++; - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &xl, sizeof xl); - } + if (update_file(nhfp)) { + Sfo_unsigned(nhfp, &xl, "damage-damage_count"); } while (damageptr) { - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) damageptr, sizeof *damageptr); - } + if (update_file(nhfp)) { + Sfo_damage(nhfp, damageptr, "damage"); } tmp_dam = damageptr; damageptr = damageptr->next; @@ -698,17 +651,15 @@ save_stairs(NHFILE *nhfp) int buflen = (int) sizeof *stway; while (stway) { - if (perform_bwrite(nhfp)) { + if (update_file(nhfp)) { boolean use_relative = (program_state.restoring != REST_GSTATE && stway->tolev.dnum == u.uz.dnum); if (use_relative) { /* make dlevel relative to current level */ stway->tolev.dlevel -= u.uz.dlevel; } - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); - bwrite(nhfp->fd, (genericptr_t) stway, sizeof *stway); - } + Sfo_int(nhfp, &buflen, "stairs-staircount"); + Sfo_stairway(nhfp, stway, "stairs-stairway"); if (use_relative) { /* reset stairway dlevel back to absolute */ stway->tolev.dlevel += u.uz.dlevel; @@ -716,11 +667,9 @@ save_stairs(NHFILE *nhfp) } stway = stway->next; } - if (perform_bwrite(nhfp)) { + if (update_file(nhfp)) { buflen = -1; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); - } + Sfo_int(nhfp, &buflen, "stairs-staircount"); } } @@ -755,51 +704,38 @@ save_bc(NHFILE *nhfp) } /* save one object; - caveat: this is only for perform_bwrite(); caller handles release_data() */ + caveat: this is only for update_file(); caller handles release_data() */ staticfn void saveobj(NHFILE *nhfp, struct obj *otmp) { int buflen, zerobuf = 0; buflen = (int) sizeof (struct obj); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); - bwrite(nhfp->fd, (genericptr_t) otmp, buflen); - } + Sfo_int(nhfp, &buflen, "obj-obj_length"); + Sfo_obj(nhfp, otmp, "obj"); if (otmp->oextra) { buflen = ONAME(otmp) ? (int) strlen(ONAME(otmp)) + 1 : 0; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); - } + Sfo_int(nhfp, &buflen, "obj-oname_length"); + if (buflen > 0) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) ONAME(otmp), buflen); - } + Sfo_char(nhfp, ONAME(otmp), "obj-oname", buflen); } /* defer to savemon() for this one */ if (OMONST(otmp)) { savemon(nhfp, OMONST(otmp)); } else { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &zerobuf, sizeof zerobuf); - } + Sfo_int(nhfp, &zerobuf, "obj-omonst_length"); } /* extra info about scroll of mail */ buflen = OMAILCMD(otmp) ? (int) strlen(OMAILCMD(otmp)) + 1 : 0; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); - } + Sfo_int(nhfp, &buflen, "obj-omailcmd_length"); if (buflen > 0) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) OMAILCMD(otmp), buflen); - } + Sfo_char(nhfp, OMAILCMD(otmp), "obj-omailcmd", buflen); } /* omid used to be indirect via a pointer in oextra but has become part of oextra itself; 0 means not applicable and gets saved/restored whenever any other oextra components do */ - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &OMID(otmp), sizeof OMID(otmp)); - } + Sfo_unsigned(nhfp, &OMID(otmp), "obj-omid"); } } @@ -815,7 +751,7 @@ saveobjchn(NHFILE *nhfp, struct obj **obj_p) while (otmp) { otmp2 = otmp->nobj; - if (perform_bwrite(nhfp)) { + if (update_file(nhfp)) { saveobj(nhfp, otmp); } if (Has_contents(otmp)) @@ -859,10 +795,8 @@ saveobjchn(NHFILE *nhfp, struct obj **obj_p) } otmp = otmp2; } - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &minusone, sizeof(int)); - } + if (update_file(nhfp)) { + Sfo_int(nhfp, &minusone, "obj-obj_length"); } if (release_data(nhfp)) { if (is_invent) @@ -879,80 +813,48 @@ savemon(NHFILE *nhfp, struct monst *mtmp) mtmp->mtemplit = 0; /* normally clear; if set here then a panic save * is being written while bhit() was executing */ buflen = (int) sizeof (struct monst); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); - bwrite(nhfp->fd, (genericptr_t) mtmp, buflen); - } + Sfo_int(nhfp, &buflen, "monst-monst_length"); + Sfo_monst(nhfp, mtmp, "monst"); if (mtmp->mextra) { buflen = MGIVENNAME(mtmp) ? (int) strlen(MGIVENNAME(mtmp)) + 1 : 0; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); - } + Sfo_int(nhfp, &buflen, "monst-mgivenname_length"); if (buflen > 0) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) MGIVENNAME(mtmp), buflen); - } + Sfo_char(nhfp, MGIVENNAME(mtmp), "monst-mgivenname", buflen); } buflen = EGD(mtmp) ? (int) sizeof (struct egd) : 0; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); - } + Sfo_int(nhfp, &buflen, "monst-egd_length"); if (buflen > 0) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) EGD(mtmp), buflen); - } + Sfo_egd(nhfp, EGD(mtmp), "monst-egd"); } buflen = EPRI(mtmp) ? (int) sizeof (struct epri) : 0; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen); - } + Sfo_int(nhfp, &buflen, "monst-epri_length"); if (buflen > 0) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) EPRI(mtmp), buflen); - } + Sfo_epri(nhfp, EPRI(mtmp), "monst-epri"); } buflen = ESHK(mtmp) ? (int) sizeof (struct eshk) : 0; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof(int)); - } + Sfo_int(nhfp, &buflen, "monst-eshk_length"); if (buflen > 0) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) ESHK(mtmp), buflen); - } + Sfo_eshk(nhfp, ESHK(mtmp), "monst-eshk"); } buflen = EMIN(mtmp) ? (int) sizeof (struct emin) : 0; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof(int)); - } + Sfo_int(nhfp, &buflen, "monst-emin_length"); if (buflen > 0) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) EMIN(mtmp), buflen); - } + Sfo_emin(nhfp, EMIN(mtmp), "monst-emin"); } buflen = EDOG(mtmp) ? (int) sizeof (struct edog) : 0; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof(int)); - } + Sfo_int(nhfp, &buflen, "monst-edog_length"); if (buflen > 0) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) EDOG(mtmp), buflen); - } + Sfo_edog(nhfp, EDOG(mtmp), "monst-edog"); } buflen = EBONES(mtmp) ? (int) sizeof (struct ebones) : 0; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof(int)); - } + Sfo_int(nhfp, &buflen, "monst-ebones_length"); if (buflen > 0) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) EBONES(mtmp), buflen); - } + Sfo_ebones(nhfp, EBONES(mtmp), "monst-ebones"); } /* mcorpsenm is inline int rather than pointer to something, so doesn't need to be preceded by a length field */ buflen = (int) MCORPSENM(mtmp); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof (int)); - } + Sfo_int(nhfp, &buflen, "monst-mcorpsenm"); } } @@ -964,7 +866,7 @@ savemonchn(NHFILE *nhfp, struct monst *mtmp) while (mtmp) { mtmp2 = mtmp->nmon; - if (perform_bwrite(nhfp)) { + if (update_file(nhfp)) { mtmp->mnum = monsndx(mtmp->data); if (mtmp->ispriest) forget_temple_entry(mtmp); /* EPRI() */ @@ -986,10 +888,8 @@ savemonchn(NHFILE *nhfp, struct monst *mtmp) } mtmp = mtmp2; } - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &minusone, sizeof(int)); - } + if (update_file(nhfp)) { + Sfo_int(nhfp, &minusone, "monst-monst_length"); } } @@ -1006,10 +906,8 @@ savetrapchn(NHFILE *nhfp, struct trap *trap) trap2 = trap->ntrap; if (use_relative) trap->dst.dlevel -= u.uz.dlevel; /* make it relative */ - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) trap, sizeof *trap); - } + if (update_file(nhfp)) { + Sfo_trap(nhfp, trap, "trap"); } if (use_relative) trap->dst.dlevel += u.uz.dlevel; /* reset back to absolute */ @@ -1017,10 +915,8 @@ savetrapchn(NHFILE *nhfp, struct trap *trap) dealloc_trap(trap); trap = trap2; } - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &zerotrap, sizeof zerotrap); - } + if (update_file(nhfp)) { + Sfo_trap(nhfp, &zerotrap, "trap"); } } @@ -1038,19 +934,15 @@ savefruitchn(NHFILE *nhfp) f1 = gf.ffruit; while (f1) { f2 = f1->nextf; - if (f1->fid >= 0 && perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) f1, sizeof *f1); - } + if (f1->fid >= 0 && update_file(nhfp)) { + Sfo_fruit(nhfp, f1, "fruit"); } if (release_data(nhfp)) dealloc_fruit(f1); f1 = f2; } - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &zerofruit, sizeof zerofruit); - } + if (update_file(nhfp)) { + Sfo_fruit(nhfp, &zerofruit, "fruit"); } if (release_data(nhfp)) gf.ffruit = 0; @@ -1064,17 +956,13 @@ savelevchn(NHFILE *nhfp) for (tmplev = svs.sp_levchn; tmplev; tmplev = tmplev->next) cnt++; - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &cnt, sizeof cnt); - } + if (update_file(nhfp)) { + Sfo_int(nhfp, &cnt, "levchn-lev_count"); } for (tmplev = svs.sp_levchn; tmplev; tmplev = tmplev2) { tmplev2 = tmplev->next; - if (perform_bwrite(nhfp)) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) tmplev, sizeof *tmplev); - } + if (update_file(nhfp)) { + Sfo_s_level(nhfp, tmplev, "levchn-s_level"); } if (release_data(nhfp)) free((genericptr_t) tmplev); @@ -1107,13 +995,12 @@ store_plname_in_file(NHFILE *nhfp) assert(hero[PL_NSIZ_PLUS - 1 - 1] == '\0'); hero[PL_NSIZ_PLUS - 1] = wizard ? 'D' : discover ? 'X' : '-'; - if (nhfp->structlevel) { - bufoff(nhfp->fd); - /* bwrite() before bufon() uses plain write() */ - bwrite(nhfp->fd, (genericptr_t) &plsiztmp, sizeof plsiztmp); - bwrite(nhfp->fd, (genericptr_t) hero, plsiztmp); + if (nhfp->structlevel) + bufoff(nhfp->fd); /* bwrite() before bufon() uses plain write() */ + Sfo_int(nhfp, &plsiztmp, "plname-size"); + Sfo_char(nhfp, hero, "plname", plsiztmp); + if (nhfp->structlevel) bufon(nhfp->fd); - } return; } @@ -1121,11 +1008,11 @@ staticfn void save_msghistory(NHFILE *nhfp) { char *msg; - int msgcount = 0, msglen; - int minusone = -1; + int msgcount = 0; + int minusone = -1, msglen; boolean init = TRUE; - if (perform_bwrite(nhfp)) { + if (update_file(nhfp)) { /* ask window port for each message in sequence */ while ((msg = getmsghistory(init)) != 0) { init = FALSE; @@ -1136,15 +1023,11 @@ save_msghistory(NHFILE *nhfp) no need to modify msg[] since terminator isn't written */ if (msglen > BUFSZ - 1) msglen = BUFSZ - 1; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &msglen, sizeof msglen); - bwrite(nhfp->fd, (genericptr_t) msg, msglen); - } + Sfo_int(nhfp, &msglen, "msghistory-length"); + Sfo_char(nhfp, msg, "msghistory-msg", msglen); ++msgcount; } - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &minusone, sizeof(int)); - } + Sfo_int(nhfp, &minusone, "msghistory-length"); } debugpline1("Stored %d messages into savefile.", msgcount); /* note: we don't attempt to handle release_data() here */ @@ -1261,6 +1144,7 @@ freedynamicdata(void) #endif discard_gamelog(); release_runtime_info(); /* build-time options and version stuff */ + //free_convert_filenames(); #endif /* FREE_ALL_MEMORY */ if (VIA_WINDOWPORT()) @@ -1275,7 +1159,6 @@ freedynamicdata(void) /* last, because it frees data that might be used by panic() to provide feedback to the user; conceivably other freeing might trigger panic */ sysopt_release(); /* SYSCF strings */ - return; } /*save.c*/ diff --git a/src/sfbase.c b/src/sfbase.c new file mode 100644 index 000000000..6a62865af --- /dev/null +++ b/src/sfbase.c @@ -0,0 +1,209 @@ +/* NetHack 3.7 sfbase.c.template $NHDT-Date$ $NHDT-Branch$:$NHDT-Revision$ */ +/* Copyright (c) Michael Allison, 2025. */ +/* NetHack may be freely redistributed. See license for details. */ + +#include "hack.h" +#include "sfprocs.h" + +/* #define DO_DEBUG */ + +struct sf_structlevel_procs sfoprocs[NUM_SAVEFORMATS], sfiprocs[NUM_SAVEFORMATS], + zerosfoprocs = {0}, zerosfiprocs = {0}; + +void sf_log(NHFILE *, const char *, size_t, int); + +#define SF_A(dtyp) \ +void sfo_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, const char *myname) \ +{ \ + if (nhfp->fplog) \ + sf_log(nhfp, myname, sizeof *d_##dtyp, 1); \ + if (nhfp->structlevel) { \ + (*sfoprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname); \ + } \ +} \ + \ +void sfi_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, const char *myname) \ +{ \ + if (nhfp->structlevel) { \ + (*sfiprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname); \ + } \ + if (nhfp->fplog && !nhfp->eof) \ + sf_log(nhfp, myname, sizeof *d_##dtyp, 1); \ + if (nhfp->eof) \ + return; \ + if (((nhfp->mode & CONVERTING) != 0) && nhfp->nhfpconvert) \ + sfo_##dtyp(nhfp->nhfpconvert, d_##dtyp, myname); \ +} + +#define SF_C(keyw, dtyp) \ +void sfo_##dtyp(NHFILE *nhfp, keyw dtyp *d_##dtyp, const char *myname) \ +{ \ + \ + if (nhfp->structlevel) { \ + (*sfoprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname); \ + } \ + if (nhfp->fplog && !nhfp->eof) \ + sf_log(nhfp, myname, sizeof *d_##dtyp, 1); \ +} \ + \ +void sfi_##dtyp(NHFILE *nhfp, keyw dtyp *d_##dtyp, const char *myname) \ +{ \ + if (nhfp->structlevel) { \ + (*sfiprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname); \ + } \ + if (nhfp->fplog && !nhfp->eof) \ + sf_log(nhfp, myname, sizeof *d_##dtyp, 1); \ + if (nhfp->eof) \ + return; \ + if (((nhfp->mode & CONVERTING) != 0) && nhfp->nhfpconvert) \ + sfo_##dtyp(nhfp->nhfpconvert, d_##dtyp, myname); \ +} + +#define SF_X(xxx, dtyp) \ +void sfo_##dtyp(NHFILE *nhfp, xxx *d_##dtyp, const char *myname, int bfsz) \ +{ \ + if (nhfp->structlevel) { \ + (*sfoprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname, bfsz); \ + } \ + if (nhfp->fplog && !nhfp->eof) \ + sf_log(nhfp, myname, sizeof *d_##dtyp, 1); \ +} \ + \ +void sfi_##dtyp(NHFILE *nhfp, xxx *d_##dtyp, const char *myname, int bfsz) \ +{ \ + if (nhfp->structlevel) { \ + (*sfiprocs[nhfp->fnidx].fn.sf_##dtyp)(nhfp, d_##dtyp, myname, bfsz); \ + } \ + if (nhfp->fplog && !nhfp->eof) \ + sf_log(nhfp, myname, sizeof *d_##dtyp, 1); \ + if (nhfp->eof) \ + return; \ + if (((nhfp->mode & CONVERTING) != 0) && nhfp->nhfpconvert) \ + sfo_##dtyp(nhfp->nhfpconvert, d_##dtyp, myname, bfsz); \ +} + +SF_C(struct, arti_info) +SF_C(struct, nhrect) +SF_C(struct, branch) +SF_C(struct, bubble) +SF_C(struct, cemetery) +SF_C(struct, context_info) +SF_C(struct, nhcoord) +SF_C(struct, damage) +SF_C(struct, dest_area) +SF_C(struct, dgn_topology) +SF_C(struct, dungeon) +SF_C(struct, d_level) +SF_C(struct, ebones) +SF_C(struct, edog) +SF_C(struct, egd) +SF_C(struct, emin) +SF_C(struct, engr) +SF_C(struct, epri) +SF_C(struct, eshk) +SF_C(struct, fe) +SF_C(struct, flag) +SF_C(struct, fruit) +SF_C(struct, gamelog_line) +SF_C(struct, kinfo) +SF_C(struct, levelflags) +SF_C(struct, ls_t) +SF_C(struct, linfo) +SF_C(struct, mapseen_feat) +SF_C(struct, mapseen_flags) +SF_C(struct, mapseen_rooms) +SF_C(struct, mkroom) +SF_C(struct, monst) +SF_C(struct, mvitals) +SF_C(struct, obj) +SF_C(struct, objclass) +SF_C(struct, q_score) +SF_C(struct, rm) +SF_C(struct, spell) +SF_C(struct, stairway) +SF_C(struct, s_level) +SF_C(struct, trap) +SF_C(struct, version_info) +SF_C(struct, you) +SF_C(union, any) + +SF_A(aligntyp) +SF_A(boolean) +SF_A(coordxy) +SF_A(genericptr) +SF_A(int) +SF_A(int16) +SF_A(int32) +SF_A(int64) +SF_A(long) +SF_A(schar) +SF_A(short) +SF_A(size_t) +SF_A(time_t) +SF_A(uchar) +SF_A(uint16) +SF_A(uint32) +SF_A(uint64) +SF_A(ulong) +SF_A(unsigned) +SF_A(ushort) +SF_A(xint16) +SF_A(xint8) + +void +sfo_char(NHFILE *nhfp, char *d_char, const char *myname, int cnt) +{ + if (nhfp->structlevel) { + (*sfoprocs[nhfp->fnidx].fn.sf_char)(nhfp, d_char, myname, cnt); + } + if (nhfp->fplog && !nhfp->eof) + sf_log(nhfp, myname, sizeof (char), cnt); +} + +void +sfi_char(NHFILE *nhfp, char *d_char, const char *myname, int cnt) +{ + if (nhfp->structlevel) { + (*sfiprocs[nhfp->fnidx].fn.sf_char)(nhfp, d_char, myname, cnt); + } + if (nhfp->fplog && !nhfp->eof) + sf_log(nhfp, myname, sizeof (char), cnt); + if (nhfp->eof) + return; + if (((nhfp->mode & CONVERTING) != 0) && nhfp->nhfpconvert) + sfo_char(nhfp->nhfpconvert, d_char, myname, cnt); +} +SF_X(uint8_t, bitfield) + +/* ---------------------------------------------------------------*/ + +void +sf_log(NHFILE *nhfp, const char *t1, size_t sz, int cnt) +{ + FILE *fp = nhfp->fplog; + + if (fp) { + (void) fprintf(fp, "%ld %s sz=%zu cnt=%d\n", + nhfp->count++, + t1, sz, cnt); + fflush(fp); + } +} + +/* + *---------------------------------------------------------------------------- + * initialize the function pointers. These are called from initoptions_init(). + *---------------------------------------------------------------------------- + */ + +void +sf_init(void) +{ + sfoprocs[invalid] = zerosfoprocs; + sfiprocs[invalid] = zerosfiprocs; + sfoprocs[historical] = historical_sfo_procs; + sfiprocs[historical] = historical_sfi_procs; +} + + + diff --git a/src/sfstruct.c b/src/sfstruct.c index f4a09163f..c4eda5418 100644 --- a/src/sfstruct.c +++ b/src/sfstruct.c @@ -1,9 +1,326 @@ /* NetHack 3.7 sfstruct.c $NHDT-Date: 1606765215 2020/11/30 19:40:15 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.4 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ -/*-Copyright (c) Michael Allison, 2009. */ +/*-Copyright (c) Michael Allison, 2025. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" +#include "sfprocs.h" + +/* #define SFLOGGING */ /* debugging */ + +/* historical full struct savings */ + +#ifdef SAVEFILE_DEBUGGING +#if defined(__GNUC__) +#define DEBUGFORMATSTR64 "%s %s %ld %ld %d\n" +#elif defined(_MSC_VER) +#define DEBUGFORMATSTR64 "%s %s %lld %ld %d\n" +#endif +#endif + +#ifdef SFLOGGING +staticfn void logging_finish(void); +#endif + +#define SFO_BODY(dt) \ +{ \ + bwrite(nhfp->fd, (genericptr_t) d_##dt, sizeof *d_##dt); \ +} + +#define SFI_BODY(dt) \ +{ \ + mread(nhfp->fd, (genericptr_t) d_##dt, sizeof *d_##dt); \ + if (restoreinfo.mread_flags == -1) \ + nhfp->eof = TRUE; \ +} + +#define SF_A(dtyp) \ +void historical_sfo_##dtyp(NHFILE *, dtyp *d_##dtyp, const char *); \ +void historical_sfi_##dtyp(NHFILE *, dtyp *d_##dtyp, const char *); \ + \ +void historical_sfo_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, \ + const char *myname UNUSED) \ + SFO_BODY(dtyp) \ + \ +void historical_sfi_##dtyp(NHFILE *nhfp, dtyp *d_##dtyp, \ + const char *myname UNUSED) \ + SFI_BODY(dtyp) + + +#define SF_C(keyw, dtyp) \ +void historical_sfo_##dtyp(NHFILE *, keyw dtyp *d_##dtyp, \ + const char *); \ +void historical_sfi_##dtyp(NHFILE *, keyw dtyp *d_##dtyp, \ + const char *); \ + \ +void historical_sfo_##dtyp(NHFILE *nhfp, keyw dtyp *d_##dtyp, \ + const char *myname UNUSED) \ + SFO_BODY(dtyp) \ + \ +void historical_sfi_##dtyp(NHFILE *nhfp, keyw dtyp *d_##dtyp, \ + const char *myname UNUSED) \ + SFI_BODY(dtyp) + +#define SF_X(xxx, dtyp) \ +void historical_sfo_##dtyp(NHFILE *, xxx *d_##dtyp, const char *, int); \ +void historical_sfi_##dtyp(NHFILE *, xxx *d_##dtyp, const char *, int); \ + \ +void historical_sfo_##dtyp(NHFILE *nhfp, xxx *d_##dtyp, \ + const char *myname UNUSED, int bflen UNUSED) \ + SFO_BODY(dtyp) \ + \ +void historical_sfi_##dtyp(NHFILE *nhfp, xxx *d_##dtyp, \ + const char *myname UNUSED, int bflen UNUSED) \ + SFI_BODY(dtyp) + +SF_C(struct, arti_info) +SF_C(struct, nhrect) +SF_C(struct, branch) +SF_C(struct, bubble) +SF_C(struct, cemetery) +SF_C(struct, context_info) +SF_C(struct, nhcoord) +SF_C(struct, damage) +SF_C(struct, dest_area) +SF_C(struct, dgn_topology) +SF_C(struct, dungeon) +SF_C(struct, d_level) +SF_C(struct, ebones) +SF_C(struct, edog) +SF_C(struct, egd) +SF_C(struct, emin) +SF_C(struct, engr) +SF_C(struct, epri) +SF_C(struct, eshk) +SF_C(struct, fe) +SF_C(struct, flag) +SF_C(struct, fruit) +SF_C(struct, gamelog_line) +SF_C(struct, kinfo) +SF_C(struct, levelflags) +SF_C(struct, ls_t) +SF_C(struct, linfo) +SF_C(struct, mapseen_feat) +SF_C(struct, mapseen_flags) +SF_C(struct, mapseen_rooms) +SF_C(struct, mkroom) +SF_C(struct, monst) +SF_C(struct, mvitals) +SF_C(struct, obj) +SF_C(struct, objclass) +SF_C(struct, q_score) +SF_C(struct, rm) +SF_C(struct, spell) +SF_C(struct, stairway) +SF_C(struct, s_level) +SF_C(struct, trap) +SF_C(struct, version_info) +SF_C(struct, you) + +SF_C(union, any) +SF_A(aligntyp) +SF_A(boolean) +SF_A(coordxy) +SF_A(genericptr_t) +SF_A(int) +SF_A(int16) +SF_A(int32) +SF_A(int64) +SF_A(long) +SF_A(schar) +SF_A(short) +SF_A(size_t) +SF_A(time_t) +SF_A(uchar) +SF_A(uint16) +SF_A(uint32) +SF_A(uint64) +SF_A(ulong) +SF_A(unsigned) +SF_A(ushort) +SF_A(xint16) +SF_A(xint8) + +void historical_sfo_char(NHFILE *, char *d_char, const char *, int); +void historical_sfi_char(NHFILE *, char *d_char, const char *, int); + +void +historical_sfo_char(NHFILE *nhfp, char *d_char, + const char *myname UNUSED, int cnt) +{ + bwrite(nhfp->fd, (genericptr_t) d_char, cnt * sizeof (char)); +} + +void +historical_sfi_char(NHFILE *nhfp, char *d_char, + const char *myname UNUSED, int cnt) +{ + mread(nhfp->fd, (genericptr_t) d_char, cnt * sizeof (char)); + if (restoreinfo.mread_flags == -1) + nhfp->eof = TRUE; +} + +SF_X(uint8_t, bitfield) + +struct sf_structlevel_procs historical_sfo_procs = { + "", + /* sf */ + { + historical_sfo_arti_info, + historical_sfo_nhrect, + historical_sfo_branch, + historical_sfo_bubble, + historical_sfo_cemetery, + historical_sfo_context_info, + historical_sfo_nhcoord, + historical_sfo_damage, + historical_sfo_dest_area, + historical_sfo_dgn_topology, + historical_sfo_dungeon, + historical_sfo_d_level, + historical_sfo_ebones, + historical_sfo_edog, + historical_sfo_egd, + historical_sfo_emin, + historical_sfo_engr, + historical_sfo_epri, + historical_sfo_eshk, + historical_sfo_fe, + historical_sfo_flag, + historical_sfo_fruit, + historical_sfo_gamelog_line, + historical_sfo_kinfo, + historical_sfo_levelflags, + historical_sfo_ls_t, + historical_sfo_linfo, + historical_sfo_mapseen_feat, + historical_sfo_mapseen_flags, + historical_sfo_mapseen_rooms, + historical_sfo_mkroom, + historical_sfo_monst, + historical_sfo_mvitals, + historical_sfo_obj, + historical_sfo_objclass, + historical_sfo_q_score, + historical_sfo_rm, + historical_sfo_spell, + historical_sfo_stairway, + historical_sfo_s_level, + historical_sfo_trap, + historical_sfo_version_info, + historical_sfo_you, + historical_sfo_any, + + historical_sfo_aligntyp, + historical_sfo_boolean, + historical_sfo_coordxy, + historical_sfo_genericptr_t, + historical_sfo_int, + historical_sfo_int16, + historical_sfo_int32, + historical_sfo_int64, + historical_sfo_long, + historical_sfo_schar, + historical_sfo_short, + historical_sfo_size_t, + historical_sfo_time_t, + historical_sfo_uchar, + historical_sfo_uint16, + historical_sfo_uint32, + historical_sfo_uint64, + historical_sfo_ulong, + historical_sfo_unsigned, + historical_sfo_ushort, + historical_sfo_xint16, + historical_sfo_xint8, + historical_sfo_char, + historical_sfo_bitfield, + } +}; + +struct sf_structlevel_procs historical_sfi_procs = { + "", + /* sf */ + { + historical_sfi_arti_info, + historical_sfi_nhrect, + historical_sfi_branch, + historical_sfi_bubble, + historical_sfi_cemetery, + historical_sfi_context_info, + historical_sfi_nhcoord, + historical_sfi_damage, + historical_sfi_dest_area, + historical_sfi_dgn_topology, + historical_sfi_dungeon, + historical_sfi_d_level, + historical_sfi_ebones, + historical_sfi_edog, + historical_sfi_egd, + historical_sfi_emin, + historical_sfi_engr, + historical_sfi_epri, + historical_sfi_eshk, + historical_sfi_fe, + historical_sfi_flag, + historical_sfi_fruit, + historical_sfi_gamelog_line, + historical_sfi_kinfo, + historical_sfi_levelflags, + historical_sfi_ls_t, + historical_sfi_linfo, + historical_sfi_mapseen_feat, + historical_sfi_mapseen_flags, + historical_sfi_mapseen_rooms, + historical_sfi_mkroom, + historical_sfi_monst, + historical_sfi_mvitals, + historical_sfi_obj, + historical_sfi_objclass, + historical_sfi_q_score, + historical_sfi_rm, + historical_sfi_spell, + historical_sfi_stairway, + historical_sfi_s_level, + historical_sfi_trap, + historical_sfi_version_info, + historical_sfi_you, + historical_sfi_any, + + historical_sfi_aligntyp, + historical_sfi_boolean, + historical_sfi_coordxy, + historical_sfi_genericptr_t, + historical_sfi_int, + historical_sfi_int16, + historical_sfi_int32, + historical_sfi_int64, + historical_sfi_long, + historical_sfi_schar, + historical_sfi_short, + historical_sfi_size_t, + historical_sfi_time_t, + historical_sfi_uchar, + historical_sfi_uint16, + historical_sfi_uint32, + historical_sfi_uint64, + historical_sfi_ulong, + historical_sfi_unsigned, + historical_sfi_ushort, + historical_sfi_xint16, + historical_sfi_xint8, + historical_sfi_char, + historical_sfi_bitfield, + } +}; + +/* + * The historical bwrite() and mread() functions follow + */ + +#ifdef SAVEFILE_DEBUGGING +static long floc = 0L; +#endif /* * historical structlevel savefile writing and reading routines follow. @@ -28,6 +345,19 @@ static int bw_buffered[MAXFD] = {0,0,0,0,0}; static FILE *bw_FILE[MAXFD] = {0,0,0,0,0}; #endif +#ifdef SFLOGGING +static FILE *ofp[20] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + char ofnamebuf[80]; + static long ocnt = 0L; + + static FILE *ifp[20] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + char ifnamebuf[80]; + static long icnt = 0L; +#endif + + /* * Presumably, the fdopen() to allow use of stdio fwrite() * over write() was done for performance or functionality @@ -146,6 +476,17 @@ bclose(int fd) /* return the idx to the pool */ bw_sticky[idx] = -1; } +#ifdef SFLOGGING + if (fd >= 0 && fd <= SIZE(ofp)) { + if (ofp[fd]) { + fclose(ofp[fd]); + ofp[fd] = 0; + } else if (ifp[fd]) { + fclose(ifp[fd]); + ifp[fd] = 0; + } + } +#endif return; } @@ -171,6 +512,20 @@ bwrite(int fd, const genericptr_t loc, unsigned num) boolean failed; int idx = getidx(fd, NOFLG); +#ifdef SFLOGGING + if (fd >= 0 && fd < SIZE(ofp)) { + if (!ofp[fd]) { + Snprintf(ofnamebuf, sizeof ofnamebuf, "bwrite_%02d.log", fd); + ofp[fd] = fopen(ofnamebuf, "w"); + } + if (ofp[fd]) { + fprintf(ofp[fd], "%08ld, %08ld, %d\n", ocnt, + ftell(ofp[fd]), num); + ocnt++; + } + } +#endif + if (idx >= 0) { if (num == 0) { /* nothing to do; we need a special case to exit early @@ -209,7 +564,22 @@ bwrite(int fd, const genericptr_t loc, unsigned num) void mread(int fd, genericptr_t buf, unsigned len) { -#if defined(BSD) || defined(ULTRIX) + +#ifdef SFLOGGING + if (fd >= 0 && fd < 9) { + if (!ifp[fd]) { + Snprintf(ifnamebuf, sizeof ifnamebuf, "mread_%02d.log", fd); + ifp[fd] = fopen(ifnamebuf, "w"); + } + if (ifp[fd]) { + fprintf(ifp[fd], "%08ld, %08ld, %d\n", icnt, + ftell(ifp[fd]), (int) len); + icnt++; + } + } +#endif + +#if defined(BSD) || defined(ULTRIX) || defined(WIN32) #define readLenType int #else /* e.g. SYSV, __TURBOC__ */ #define readLenType unsigned @@ -235,3 +605,27 @@ mread(int fd, genericptr_t buf, unsigned len) } +#ifdef SFLOGGING +staticfn void +logging_finish(void) +{ + int i; + + for (i = 0; i < SIZE(ofp); ++i) { + if (ofp[i]) { + fclose(ofp[i]); + ofp[i] = 0; + } + } + ocnt = 0L; + + for (i = 0; i < SIZE(ifp); ++i) { + if (ifp[i]) { + fclose(ifp[i]); + ifp[i] = 0; + } + } + icnt = 0L; +} +#endif + diff --git a/src/sys.c b/src/sys.c index 9cdead0ba..4d8ad2dcf 100644 --- a/src/sys.c +++ b/src/sys.c @@ -99,8 +99,7 @@ sys_early_init(void) sysopt.check_plname = 0; sysopt.seduce = 1; /* if it's compiled in, default to on */ sysopt_seduce_set(sysopt.seduce); - /* default to little-endian in 3.7 */ - sysopt.saveformat[0] = sysopt.bonesformat[0] = lendian; + sysopt.saveformat[0] = sysopt.bonesformat[0] = historical; sysopt.accessibility = 0; #ifdef WIN32 sysopt.portable_device_paths = 0; diff --git a/src/timeout.c b/src/timeout.c index 34e95806a..dbfa90762 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -2022,7 +2022,7 @@ print_queue(winid win, timer_element *base) for (curr = base; curr; curr = curr->next) { #ifdef VERBOSE_TIMER Sprintf(buf, " %4ld %4ld %-6s %s(%s)", curr->timeout, - curr->tid, kind_name(curr->kind), + (long) curr->tid, kind_name(curr->kind), timeout_funcs[curr->func_index].name, fmt_ptr((genericptr_t) curr->arg.a_void)); #else @@ -2496,25 +2496,19 @@ write_timer(NHFILE *nhfp, timer_element *timer) case TIMER_GLOBAL: case TIMER_LEVEL: /* assume no pointers in arg */ - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) timer, sizeof(timer_element)); - } + Sfo_fe(nhfp, timer, "timer"); break; case TIMER_OBJECT: if (timer->needs_fixup) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) timer, sizeof(timer_element)); - } + Sfo_fe(nhfp, timer, "timer"); } else { /* replace object pointer with id */ arg_save.a_obj = timer->arg.a_obj; timer->arg = cg.zeroany; timer->arg.a_uint = (arg_save.a_obj)->o_id; timer->needs_fixup = 1; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) timer, sizeof(timer_element)); - } + Sfo_fe(nhfp, timer, "timer"); timer->arg.a_obj = arg_save.a_obj; timer->needs_fixup = 0; } @@ -2522,18 +2516,14 @@ write_timer(NHFILE *nhfp, timer_element *timer) case TIMER_MONSTER: if (timer->needs_fixup) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) timer, sizeof(timer_element)); - } + Sfo_fe(nhfp, timer, "timer"); } else { /* replace monster pointer with id */ arg_save.a_monst = timer->arg.a_monst; timer->arg = cg.zeroany; timer->arg.a_uint = (arg_save.a_monst)->m_id; timer->needs_fixup = 1; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) timer, sizeof(timer_element)); - } + Sfo_fe(nhfp, timer, "timer"); timer->arg.a_monst = arg_save.a_monst; timer->needs_fixup = 0; } @@ -2665,17 +2655,12 @@ save_timers(NHFILE *nhfp, int range) timer_element *curr, *prev, *next_timer = 0; int count; - if (perform_bwrite(nhfp)) { + if (update_file(nhfp)) { if (range == RANGE_GLOBAL) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &svt.timer_id, - sizeof svt.timer_id); - } + Sfo_ulong(nhfp, &svt.timer_id, "timer-timer_id"); } count = maybe_write_timer(nhfp, range, FALSE); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &count, sizeof count); - } + Sfo_int(nhfp, &count, "timer-timer_count"); (void) maybe_write_timer(nhfp, range, TRUE); } @@ -2710,22 +2695,14 @@ restore_timers(NHFILE *nhfp, int range, long adjust) boolean ghostly = (nhfp->ftype == NHF_BONESFILE); /* from a ghost level */ if (range == RANGE_GLOBAL) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &svt.timer_id, - sizeof svt.timer_id); - } + Sfi_ulong(nhfp, &svt.timer_id, "timer-timer_id"); } /* restore elements */ - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &count, sizeof count); - } - + Sfi_int(nhfp, &count, "timer-timer_count"); while (count-- > 0) { curr = (timer_element *) alloc(sizeof(timer_element)); - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) curr, sizeof(timer_element)); - } + Sfi_fe(nhfp, curr, "timer"); if (ghostly) curr->timeout += adjust; insert_timer(curr); diff --git a/src/track.c b/src/track.c index 60a0d382b..6f455a694 100644 --- a/src/track.c +++ b/src/track.c @@ -69,20 +69,13 @@ hastrack(coordxy x, coordxy y) void save_track(NHFILE *nhfp) { - if (perform_bwrite(nhfp)) { + if (update_file(nhfp)) { int i; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &utcnt, sizeof utcnt); - bwrite(nhfp->fd, (genericptr_t) &utpnt, sizeof utpnt); - } + Sfo_int(nhfp, &utcnt, "track-utcnt"); + Sfo_int(nhfp, &utpnt, "track-utpnt"); for (i = 0; i < utcnt; i++) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &utrack[i].x, - sizeof utrack[i].x); - bwrite(nhfp->fd, (genericptr_t) &utrack[i].y, - sizeof utrack[i].y); - } + Sfo_nhcoord(nhfp, &utrack[i], "utrack"); } } if (release_data(nhfp)) @@ -95,17 +88,13 @@ rest_track(NHFILE *nhfp) { int i; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &utcnt, sizeof utcnt); - mread(nhfp->fd, (genericptr_t) &utpnt, sizeof utpnt); - } + Sfi_int(nhfp, &utcnt, "track-utcnt"); + Sfi_int(nhfp, &utpnt, "track-utpnt"); + if (utcnt > UTSZ || utpnt > UTSZ) panic("rest_track: impossible pt counts"); for (i = 0; i < utcnt; i++) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &utrack[i].x, sizeof utrack[i].x); - mread(nhfp->fd, (genericptr_t) &utrack[i].y, sizeof utrack[i].y); - } + Sfi_nhcoord(nhfp, &utrack[i], "utrack"); } } diff --git a/src/version.c b/src/version.c index f1303744d..dc1d0e654 100644 --- a/src/version.c +++ b/src/version.c @@ -373,6 +373,10 @@ check_version( #endif complain = FALSE; /* 'complain' requires 'filename' for pline("%s") */ } + if ((version_data->feature_set & SFCTOOL_BIT) != 0) { + gc.converted_savefile_loaded = TRUE; + version_data->feature_set &= ~(SFCTOOL_BIT); + } if ( #ifdef VERSION_COMPATIBILITY /* patchlevel.h */ version_data->incarnation < VERSION_COMPATIBILITY @@ -421,13 +425,11 @@ store_version(NHFILE *nhfp) bufoff(nhfp->fd); store_critical_bytes(nhfp); - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &version_data, - (unsigned) (sizeof version_data)); - } + Sfo_version_info(nhfp, (struct version_info *) &version_data, + "version_info"); if (nhfp->structlevel) - bufon(nhfp->fd); + bufon(nhfp->fd); return; } @@ -661,90 +663,170 @@ store_critical_bytes(NHFILE *nhfp) if (nhfp->mode & WRITING) { indicate = (nhfp->structlevel) ? 'h' - : (nhfp->fnidx == ascii) ? 'a' - : 'l'; - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &indicate, - (unsigned) sizeof indicate); - } - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &csc_count, - (unsigned) sizeof csc_count); - } + : (nhfp->fnidx == cnvascii) ? 'a' + : '?'; + Sfo_char(nhfp, &indicate, "indicate-format", 1); + Sfo_char(nhfp, &csc_count, "count-critical_sizes", 1); cnt = (int) csc_count; for (i = 0; i < cnt; ++i) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &critical_sizes[i].ucsize, - (unsigned) sizeof (uchar)); - } + Sfo_uchar(nhfp, &critical_sizes[i].ucsize, "critical_sizes"); } } } /* this used to be based on file date and somewhat OS-dependent, - but now examines the initial part of the file's contents */ -boolean + * but now examines the initial part of the file's contents. + * + * returns: + * + * SF_UPTODATE (0) everything matched and looks good + * SF_OUTDATED (1) savefile is outdated + * SF_CRITICAL_BYTE_COUNT_MISMATCH (2) critical size count mismatch + * SF_DM_IL32LLP64_ON_ILP32LL64 (3) Windows x64 savefile on x86 + * SF_DM_I32LP64_ON_ILP32LL64 (4) Unix 64 savefile on x86 + * SF_DM_ILP32LL64_ON_I32LP64 (5) x86 savefile on Unix 64 + * SF_DM_ILP32LL64_ON_IL32LLP64 (6) x86 savefile on Windows x64 + * SF_DM_I32LP64_ON_IL32LLP64 (7) Unix 64 savefile on Windows x64 + * SF_DM_IL32LLP64_ON_I32LP64 (8) Windows x64 savefile on Unix 64 + * SF_DM_MISMATCH (9) some other mismatch + */ +int uptodate(NHFILE *nhfp, const char *name, unsigned long utdflags) { struct version_info vers_info; char indicator; + int sfstatus = 0, idx_1st_mismatch = 0; + boolean quietly = (utdflags & UTD_QUIETLY) != 0; boolean verbose = name ? TRUE : FALSE; - int ccbresult = 0; - /* int you_size = (int) sizeof (struct you); */ - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &indicator, sizeof indicator); - } - if ((ccbresult = compare_critical_bytes(nhfp)) != 0) { - if (ccbresult > 0) { - raw_printf("compare of critical bytes failed at %d (%s).", - critical_sizes[ccbresult].ucsize, - critical_sizes[ccbresult].nm); + Sfi_char(nhfp, &indicator, "indicate-format", 1); + if ((sfstatus = compare_critical_bytes(nhfp, &idx_1st_mismatch, utdflags)) + != SF_UPTODATE) { + if (sfstatus > 0 && idx_1st_mismatch) { + if (!quietly) + raw_printf("comparison of critical bytes mismatched at %d (%s).", + critical_sizes[idx_1st_mismatch].ucsize, + critical_sizes[idx_1st_mismatch].nm); } - return FALSE; + return sfstatus; } - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &vers_info, sizeof vers_info); - } + Sfi_version_info(nhfp, &vers_info, "version_info"); if (!check_version(&vers_info, name, verbose, utdflags)) { if (verbose) { if ((utdflags & UTD_WITHOUT_WAITSYNCH_PERFILE) == 0) wait_synch(); } - return FALSE; + return SF_OUTDATED; } - return TRUE; + + return SF_UPTODATE; } +/* + * returns: + * + * SF_UPTODATE (0) everything matched and looks good + * SF_OUTDATED (1) savefile is outdated + * SF_CRITICAL_BYTE_COUNT_MISMATCH (2) critical size count mismatch + * SF_DM_IL32LLP64_ON_ILP32LL64 (3) Windows x64 savefile on x86 + * SF_DM_I32LP64_ON_ILP32LL64 (4) Unix 64 savefile on x86 + * SF_DM_ILP32LL64_ON_I32LP64 (5) x86 savefile on Unix 64 + * SF_DM_ILP32LL64_ON_IL32LLP64 (6) x86 savefile on Windows x64 + * SF_DM_I32LP64_ON_IL32LLP64 (7) Unix 64 savefile on Windows x64 + * SF_DM_IL32LLP64_ON_I32LP64 (8) Windows x64 savefile on Unix 64 + * SF_DM_MISMATCH (9) some other mismatch + */ int -compare_critical_bytes(NHFILE *nhfp) +compare_critical_bytes(NHFILE *nhfp, int *idx_1st_mismatch, unsigned long utdflags) { char active_csc_count = (char) SIZE(critical_sizes), - file_csc_count = 0; - int i, cnt = (int) active_csc_count; + file_csc_count; + int i, cnt = (int) active_csc_count, + dmmismatch = SF_DM_MISMATCH; + boolean quietly = (utdflags & UTD_QUIETLY) != 0; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &file_csc_count, - sizeof file_csc_count); - } + Sfi_char(nhfp, &file_csc_count, "count-critical_sizes", 1); if (file_csc_count > cnt) { - raw_printf("critical byte counts do not match" - ", file:%d, critical_sizes:%d.", - file_csc_count, SIZE(critical_sizes)); - return -1; + if (!quietly) + raw_printf("critical byte counts do not match" + ", file:%d, critical_sizes:%d.", + file_csc_count, SIZE(critical_sizes)); + return SF_CRITICAL_BYTE_COUNT_MISMATCH; } for (i = 0; i < (int) file_csc_count; ++i) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &cscbuf[i], - sizeof (uchar)); - } + Sfi_uchar(nhfp, &cscbuf[i], "critical_sizes"); } for (i = 1; i < cnt; ++i) { - if (cscbuf[i] != critical_sizes[i].ucsize) - return i; + if (cscbuf[i] != critical_sizes[i].ucsize) { + const char *dm = datamodel(), *dmfile; + + dmfile = what_datamodel_is_this(cscbuf[1], /* short */ + cscbuf[2], /* int */ + cscbuf[3], /* long */ + cscbuf[4], /* long long */ + cscbuf[5]); /* ptr */ + + if (!strcmp(dmfile, "IL32LLP64") && !strcmp(dm, "ILP32LL64")) { + /* Windows x64 savefile on x86 */ + dmmismatch = SF_DM_IL32LLP64_ON_ILP32LL64; + } else if (!strcmp(dmfile, "I32LP64") + && !strcmp(dm, "ILP32LL64")) { + /* Unix 64 savefile on x86*/ + dmmismatch = SF_DM_I32LP64_ON_ILP32LL64; + } else if (!strcmp(dmfile, "ILP32LL64") + && !strcmp(dm, "I32LP64")) { + /* x86 savefile on Unix 64 */ + dmmismatch = SF_DM_ILP32LL64_ON_I32LP64; + } else if (!strcmp(dmfile, "ILP32LL64") + && !strcmp(dm, "IL32LLP64")) { + /* x86 savefile on Windows x64 */ + dmmismatch = SF_DM_ILP32LL64_ON_IL32LLP64; + } else if (!strcmp(dmfile, "I32LP64") + && !strcmp(dm, "IL32LLP64")) { + /* Unix 64 savefile on Windows x64 */ + dmmismatch = SF_DM_I32LP64_ON_IL32LLP64; + } else if (!strcmp(dmfile, "IL32LLP64") + && !strcmp(dm, "I32LP64")) { + /* Windows x64 savefile on Unix 64 */ + dmmismatch = SF_DM_IL32LLP64_ON_I32LP64; + } + if (idx_1st_mismatch) + *idx_1st_mismatch = i; + return dmmismatch; + } } - return 0; /* everything matched */ + return SF_UPTODATE; /* everything matched */ +} + +/* + * returns: + * + * SF_UPTODATE (0) everything matched and looks good + * SF_OUTDATED (1) savefile is outdated + * SF_CRITICAL_BYTE_COUNT_MISMATCH (2) critical size count mismatch + * SF_DM_IL32LLP64_ON_ILP32LL64 (3) Windows x64 savefile on x86 + * SF_DM_I32LP64_ON_ILP32LL64 (4) Unix 64 savefile on x86 + * SF_DM_ILP32LL64_ON_I32LP64 (5) x86 savefile on Unix 64 + * SF_DM_ILP32LL64_ON_IL32LLP64 (6) x86 savefile on Windows x64 + * SF_DM_I32LP64_ON_IL32LLP64 (7) Unix 64 savefile on Windows x64 + * SF_DM_IL32LLP64_ON_I32LP64 (8) Windows x64 savefile on Unix 64 + * SF_DM_MISMATCH (9) some other mismatch + */ +int +validate(NHFILE *nhfp, const char *name, boolean without_waitsynch_perfile) +{ + unsigned long utdflags = 0L; + int validsf = 0; + + if (nhfp->structlevel) + utdflags |= UTD_CHECKSIZES; + if (without_waitsynch_perfile) + utdflags |= UTD_WITHOUT_WAITSYNCH_PERFILE; + if (nhfp->fieldlevel) + utdflags |= UTD_CHECKFIELDCOUNTS | UTD_SKIP_SANITY1 | UTD_QUIETLY; + validsf = uptodate(nhfp, name, utdflags); + return validsf; } #endif /* MINIMAL_FOR_RECOVER */ diff --git a/src/worm.c b/src/worm.c index c760bc3a3..af68084d1 100644 --- a/src/worm.c +++ b/src/worm.c @@ -16,6 +16,7 @@ struct wseg { staticfn void toss_wsegs(struct wseg *, boolean) NO_NNARGS; staticfn void shrink_worm(int); + #if 0 staticfn void random_dir(int, int, int *, int *); #endif @@ -527,31 +528,22 @@ save_worm(NHFILE *nhfp) int count; struct wseg *curr, *temp; - if (perform_bwrite(nhfp)) { + if (update_file(nhfp)) { for (i = 1; i < MAX_NUM_WORMS; i++) { for (count = 0, curr = wtails[i]; curr; curr = curr->nseg) count++; /* Save number of segments */ - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &count, sizeof count); - } + Sfo_int(nhfp, &count, "worm-segment_count"); /* Save segment locations of the monster. */ if (count) { for (curr = wtails[i]; curr; curr = curr->nseg) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &(curr->wx), - sizeof curr->wx); - bwrite(nhfp->fd, (genericptr_t) &(curr->wy), - sizeof curr->wy); - } + Sfo_coordxy(nhfp, &(curr->wx), "worm-wx"); + Sfo_coordxy(nhfp, &(curr->wy), "worm-wy"); } } } - for (i = 0; i < MAX_NUM_WORMS; ++i) { - if (nhfp->structlevel) { - bwrite(nhfp->fd, (genericptr_t) &wgrowtime[i], sizeof (long)); - } - } + for (i = 0; i < MAX_NUM_WORMS; ++i) + Sfo_long(nhfp, &wgrowtime[i], "worm-wgrowtime"); } if (release_data(nhfp)) { @@ -580,22 +572,19 @@ save_worm(NHFILE *nhfp) void rest_worm(NHFILE *nhfp) { - int i, j, count = 0; + int i, j; + int count = 0; struct wseg *curr, *temp; for (i = 1; i < MAX_NUM_WORMS; i++) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &count, sizeof count); - } + Sfi_int(nhfp, &count, "worm-segment_count"); /* Get the segments. */ for (curr = (struct wseg *) 0, j = 0; j < count; j++) { temp = newseg(); temp->nseg = (struct wseg *) 0; - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &(temp->wx), sizeof temp->wx); - mread(nhfp->fd, (genericptr_t) &(temp->wy), sizeof temp->wy); - } + Sfi_coordxy(nhfp, &(temp->wx), "worm-wx"); + Sfi_coordxy(nhfp, &(temp->wy), "worm-wy"); if (curr) curr->nseg = temp; else @@ -605,9 +594,7 @@ rest_worm(NHFILE *nhfp) wheads[i] = curr; } for (i = 0; i < MAX_NUM_WORMS; ++i) { - if (nhfp->structlevel) { - mread(nhfp->fd, (genericptr_t) &wgrowtime[i], sizeof (long)); - } + Sfi_long(nhfp, &wgrowtime[i], "worm-wgrowtime"); } } diff --git a/sys/share/pcmain.c b/sys/share/pcmain.c index cad2bc69a..4093eff48 100644 --- a/sys/share/pcmain.c +++ b/sys/share/pcmain.c @@ -7,6 +7,7 @@ #include "hack.h" #include "dlb.h" +#include "sfproto.h" #ifndef NO_SIGNAL #include @@ -429,9 +430,7 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ raw_print("Cannot create lock file"); } else { svh.hackpid = 1; - if (nhfp->structlevel) { - write(nhfp->fd, (genericptr_t) &svh.hackpid, sizeof svh.hackpid); - } + Sfo_int(nhfp, &svh.hackpid, "svh.hackpid"); close_nhfile(nhfp); } diff --git a/sys/unix/Makefile.src b/sys/unix/Makefile.src index d2e3c8e91..89836554a 100644 --- a/sys/unix/Makefile.src +++ b/sys/unix/Makefile.src @@ -518,7 +518,7 @@ HACKCSRC = allmain.c alloc.c apply.c artifact.c attrib.c ball.c bones.c \ nhlua.c nhlsel.c nhlobj.c nhmd4.c o_init.c objects.c objnam.c \ options.c pager.c pickup.c pline.c polyself.c potion.c pray.c \ priest.c quest.c questpgr.c read.c rect.c region.c report.c restore.c \ - rip.c rnd.c role.c rumors.c save.c selvar.c sfstruct.c \ + rip.c rnd.c role.c rumors.c save.c selvar.c sfbase.c sfstruct.c \ shk.c shknam.c sit.c sounds.c sp_lev.c spell.c stairs.c steal.c steed.c \ strutil.c symbols.c sys.c teleport.c \ timeout.c topten.c track.c trap.c u_init.c utf8map.c \ @@ -561,14 +561,15 @@ CSOURCES = $(HACKCSRC) $(HACKLIBSRC) $(SYSCSRC) $(WINCSRC) $(CHAINSRC) $(GENCSRC # HACKINCL = align.h artifact.h artilist.h attrib.h botl.h \ color.h config.h config1.h context.h coord.h cstd.h decl.h \ - display.h dlb.h dungeon.h engrave.h extern.h flag.h fnamesiz.h \ - func_tab.h global.h warnings.h hack.h lint.h mextra.h mfndpos.h \ - micro.h mkroom.h monattk.h mondata.h monflag.h monst.h monsters.h \ - nhmd4.h obj.h objects.h objclass.h optlist.h patchlevel.h \ - pcconf.h permonst.h prop.h rect.h region.h selvar.h sym.h defsym.h \ - rm.h sp_lev.h spell.h sndprocs.h seffects.h stairs.h sys.h tcap.h \ - timeout.h tradstdc.h trap.h unixconf.h vision.h vmsconf.h wintty.h \ - wincurs.h winX.h winprocs.h wintype.h you.h youprop.h weight.h + defsym.h display.h dlb.h dungeon.h engrave.h extern.h flag.h \ + fnamesiz.h func_tab.h global.h warnings.h hack.h lint.h mextra.h \ + micro.h mfndpos.h mkroom.h monattk.h mondata.h monflag.h monst.h \ + monsters.h nhmd4.h obj.h objects.h objclass.h optlist.h patchlevel.h \ + pcconf.h permonst.h prop.h rect.h region.h savefile.h selvar.h sym.h \ + rm.h sp_lev.h spell.h sndprocs.h seffects.h stairs.h sys.h \ + tcap.h timeout.h tradstdc.h trap.h unixconf.h vision.h vmsconf.h \ + wintty.h wincurs.h winX.h winprocs.h wintype.h you.h youprop.h \ + weight.h HSOURCES = $(HACKINCL) dgn_file.h @@ -610,7 +611,7 @@ HOBJ = $(TARGETPFX)allmain.o $(TARGETPFX)alloc.o \ $(TARGETPFX)rect.o $(TARGETPFX)region.o $(TARGETPFX)report.o \ $(TARGETPFX)restore.o $(TARGETPFX)rip.o $(TARGETPFX)rnd.o \ $(TARGETPFX)role.o $(TARGETPFX)rumors.o $(TARGETPFX)save.o \ - $(TARGETPFX)selvar.o $(TARGETPFX)sfstruct.o \ + $(TARGETPFX)selvar.o $(TARGETPFX)sfbase.o $(TARGETPFX)sfstruct.o \ $(TARGETPFX)shk.o $(TARGETPFX)shknam.o $(TARGETPFX)sit.o \ $(TARGETPFX)sounds.o $(TARGETPFX)sp_lev.o $(TARGETPFX)spell.o \ $(TARGETPFX)stairs.o $(TARGETPFX)symbols.o $(TARGETPFX)sys.o \ @@ -760,7 +761,7 @@ hacklib.a: hacklib.o ../win/gnome/gn_rip.h: ../win/X11/rip.xpm cp ../win/X11/rip.xpm ../win/gnome/gn_rip.h -$(TARGETPFX)sfstruct.o: sfstruct.c $(HACK_H) +$(TARGETPFX)sfbase.o: sfbase.c $(HACK_H) ../include/sfprocs.h # date.c should be recompiled any time any of the source or include code # is modified. @@ -1232,7 +1233,7 @@ $(TARGETPFX)role.o: role.c $(HACK_H) $(TARGETPFX)rumors.o: rumors.c $(HACK_H) ../include/dlb.h $(TARGETPFX)save.o: save.c $(HACK_H) $(TARGETPFX)selvar.o: selvar.c $(HACK_H) ../include/sp_lev.h -$(TARGETPFX)sfstruct.o: sfstruct.c $(HACK_H) +$(TARGETPFX)sfstruct.o: sfstruct.c $(HACK_H) ../include/sfprocs.h $(TARGETPFX)shk.o: shk.c $(HACK_H) $(TARGETPFX)shknam.o: shknam.c $(HACK_H) $(TARGETPFX)sit.o: sit.c $(HACK_H) ../include/artifact.h diff --git a/sys/unix/Makefile.utl b/sys/unix/Makefile.utl index c63caea3b..11a50aa1b 100644 --- a/sys/unix/Makefile.utl +++ b/sys/unix/Makefile.utl @@ -168,6 +168,7 @@ AT_V1 := @ AT = $(AT_V$(QUIETCC)) # Verbosity, end +GAME=nethack # timestamps for primary header files, matching src/Makefile CONFIG_H = ../src/config.h-t HACK_H = ../src/hack.h-t @@ -220,6 +221,7 @@ TARGET_CXX = $(CXX) TARGET_CXXFLAGS = $(CXXFLAGS) TARGET_AR = $(AR) +# # dependencies for makedefs # makedefs: $(HACKLIB) $(MAKEOBJS) mdgrep.h diff --git a/sys/vms/Makefile.src b/sys/vms/Makefile.src index f2efc62bb..dee166f8e 100644 --- a/sys/vms/Makefile.src +++ b/sys/vms/Makefile.src @@ -174,15 +174,18 @@ VERSOURCES = $(HACKCSRC) $(SYSSRC) $(WINSRC) $(RANDSRC) $(GENCSRC) # all .h files except date.h which would # cause dependency loops if run through "make depend" # -HACKINCL = align.h artifact.h artilist.h attrib.h color.h \ - config.h config1.h context.h coord.h decl.h defsym.h display.h \ - dlb.h dungeon.h engrave.h extern.h flag.h func_tab.h global.h \ - hack.h hacklib.h mextra.h mfndpos.h micro.h mkroom.h \ - monattk.h mondata.h monflag.h monst.h sym.h obj.h objclass.h \ - patchlevel.h pcconf.h permonst.h prop.h rect.h \ - region.h sym.h defsym.h rm.h sp_lev.h spell.h sys.h system.h \ - tcap.h timeout.h tradstdc.h trap.h unixconf.h vision.h \ - vmsconf.h wintty.h winX.h winprocs.h wintype.h you.h youprop.h +HACKINCL = align.h artifact.h artilist.h attrib.h botl.h \ + color.h config.h config1.h context.h coord.h cstd.h decl.h \ + defsym.h display.h dlb.h dungeon.h engrave.h extern.h flag.h \ + fnamesiz.h func_tab.h global.h warnings.h hack.h lint.h mextra.h \ + micro.h mkroom.h monattk.h mondata.h monflag.h monst.h monsters.h \ + mfndpos.h nhmd4.h obj.h objects.h objclass.h optlist.h patchlevel.h \ + pcconf.h permonst.h prop.h rect.h region.h savefile.h selvar.h sym.h \ + rm.h sp_lev.h spell.h sndprocs.h seffects.h stairs.h sys.h \ + tcap.h timeout.h tradstdc.h trap.h unixconf.h vision.h vmsconf.h \ + wintty.h wincurs.h winX.h winprocs.h wintype.h you.h youprop.h \ + weight.h + #HSOURCES = $(HACKINCL) date.h onames.h pm.h diff --git a/sys/windows/Makefile.nmake b/sys/windows/Makefile.nmake index 14273dd61..10c35a454 100644 --- a/sys/windows/Makefile.nmake +++ b/sys/windows/Makefile.nmake @@ -665,7 +665,7 @@ HACKCSRC = \ $(SRC)potion.c $(SRC)pray.c $(SRC)priest.c $(SRC)quest.c \ $(SRC)questpgr.c $(SRC)read.c $(SRC)rect.c $(SRC)region.c \ $(SRC)restore.c $(SRC)rip.c $(SRC)rnd.c $(SRC)role.c \ - $(SRC)rumors.c $(SRC)save.c $(SRC)selvar.c $(SRC)sfstruct.c \ + $(SRC)rumors.c $(SRC)save.c $(SRC)selvar.c $(SRC)sfstruct.c sfbase.c \ $(SRC)shk.c $(SRC)shknam.c $(SRC)sit.c $(SRC)sounds.c \ $(SRC)sp_lev.c $(SRC)spell.c $(SRC)stairs.c $(SRC)steal.c \ $(SRC)steed.c $(SRC)symbols.c $(SRC)sys.c $(SRC)teleport.c \ @@ -677,29 +677,30 @@ HACKCSRC = \ # all .h files except date.h HACKINCL = \ - $(INCL)align.h $(INCL)artifact.h $(INCL)artilist.h \ - $(INCL)attrib.h $(INCL)botl.h $(INCL)color.h \ - $(INCL)config.h $(INCL)config1.h $(INCL)context.h \ - $(INCL)coord.h $(INCL)cstd.h $(INCL)decl.h \ - $(INCL)display.h $(INCL)dlb.h $(INCL)dungeon.h \ - $(INCL)engrave.h $(INCL)extern.h $(INCL)flag.h \ - $(INCL)fnamesiz.h $(INCL)func_tab.h $(INCL)global.h \ - $(INCL)warnings.h $(INCL)hack.h $(INCL)lint.h \ - $(INCL)mextra.h $(INCL)mfndpos.h $(INCL)micro.h \ - $(INCL)mkroom.h $(INCL)monattk.h $(INCL)mondata.h \ - $(INCL)monflag.h $(INCL)monst.h $(INCL)monsters.h \ - $(INCL)nhmd4.h $(INCL)obj.h $(INCL)objects.h \ - $(INCL)objclass.h $(INCL)optlist.h $(INCL)patchlevel.h \ - $(INCL)pcconf.h $(INCL)permonst.h $(INCL)prop.h \ - $(INCL)rect.h $(INCL)region.h $(INCL)selvar.h \ - $(INCL)sym.h $(INCL)defsym.h $(INCL)rm.h \ - $(INCL)sp_lev.h $(INCL)spell.h $(INCL)sndprocs.h \ - $(INCL)seffects.h $(INCL)stairs.h $(INCL)sys.h \ - $(INCL)tcap.h $(INCL)timeout.h $(INCL)tradstdc.h \ - $(INCL)trap.h $(INCL)unixconf.h $(INCL)vision.h \ - $(INCL)vmsconf.h $(INCL)wintty.h $(INCL)wincurs.h \ - $(INCL)winX.h $(INCL)winprocs.h $(INCL)wintype.h \ - $(INCL)you.h $(INCL)youprop.h + $(INCL)align.h $(INCL)artifact.h $(INCL)artilist.h \ + $(INCL)attrib.h $(INCL)botl.h $(INCL)color.h \ + $(INCL)config.h $(INCL)config1.h $(INCL)context.h \ + $(INCL)coord.h $(INCL)cstd.h $(INCL)decl.h \ + $(INCL)defsym.h $(INCL)display.h $(INCL)dlb.h \ + $(INCL)dungeon.h $(INCL)engrave.h $(INCL)extern.h \ + $(INCL)flag.h $(INCL)fnamesiz.h $(INCL)func_tab.h \ + $(INCL)global.h $(INCL)warnings.h $(INCL)hack.h \ + $(INCL)lint.h $(INCL)mextra.h $(INCL)micro.h \ + $(INCL)mfndpos.h $(INCL)mkroom.h $(INCL)monattk.h \ + $(INCL)mondata.h $(INCL)monflag.h $(INCL)monst.h \ + $(INCL)monsters.h $(INCL)nhmd4.h $(INCL)obj.h \ + $(INCL)objects.h $(INCL)objclass.h $(INCL)optlist.h \ + $(INCL)patchlevel.h $(INCL)pcconf.h $(INCL)permonst.h \ + $(INCL)prop.h $(INCL)rect.h $(INCL)region.h \ + $(INCL)savefile.h $(INCL)selvar.h $(INCL)sym.h \ + $(INCL)rm.h $(INCL)sp_lev.h $(INCL)spell.h \ + $(INCL)sndprocs.h $(INCL)seffects.h $(INCL)stairs.h \ + $(INCL)sys.h $(INCL)tcap.h $(INCL)timeout.h \ + $(INCL)tradstdc.h $(INCL)trap.h $(INCL)unixconf.h \ + $(INCL)vision.h $(INCL)vmsconf.h $(INCL)wintty.h \ + $(INCL)wincurs.h $(INCL)winX.h $(INCL)winprocs.h \ + $(INCL)wintype.h $(INCL)you.h $(INCL)youprop.h \ + $(INCL)weight.h LUA_FILES = $(DAT)asmodeus.lua $(DAT)baalz.lua $(DAT)bigrm-1.lua \ $(DAT)bigrm-10.lua $(DAT)bigrm-11.lua $(DAT)bigrm-12.lua \ @@ -873,7 +874,7 @@ COREOBJTTY = \ $(OTTY)uhitm.o $(OTTY)utf8map.o $(OTTY)vault.o $(OTTY)vision.o \ $(OTTY)weapon.o $(OTTY)were.o $(OTTY)wield.o $(OTTY)windows.o \ $(OTTY)wizard.o $(OTTY)wizcmds.o $(OTTY)worm.o $(OTTY)worn.o \ - $(OTTY)write.o $(OTTY)zap.o + $(OTTY)write.o $(OTTY)zap.o $(OTTY)sfbase.o OBJSTTY = $(MDLIBTTY) $(COREOBJTTY) $(REGEXTTY) $(RANDOMTTY) @@ -936,7 +937,7 @@ COREOBJGUI = \ $(OGUI)uhitm.o $(OGUI)utf8map.o $(OGUI)vault.o $(OGUI)vision.o \ $(OGUI)weapon.o $(OGUI)were.o $(OGUI)wield.o $(OGUI)windows.o \ $(OGUI)wizard.o $(OGUI)wizcmds.o $(OGUI)worm.o $(OGUI)worn.o \ - $(OGUI)write.o $(OGUI)zap.o + $(OGUI)write.o $(OGUI)zap.o $(OGUI)sfbase.o OBJSGUI = $(MDLIBGUI) $(COREOBJGUI) $(REGEXGUI) $(RANDOMGUI) @@ -1458,6 +1459,8 @@ DLB = #========================================== {$(R_UTIL)}.c{$(R_OBJUTIL)}.o: + echo R_UTIL=$(R_UTIL) + echo R_OBJUTIL=$(R_OBJUTIL) $(Q)$(CC) $(CFLAGS) -Fo$@ $< #========================================== @@ -1864,6 +1867,14 @@ $(OGUI)date.o: $(HACKINCL) $(HACKSRC) $(HACKOBJ) $(ALLOBJGUI) @$(MAKE) /NOLOGO /A -f date.nmk !ENDIF +$(OGUI)sfbase.o: sfbase.c $(HACK_H) + $(Q)$(CC) $(CFLAGS) /EP $(@B).c > $(OGUI)$(@B).c.preproc + $(Q)$(CC) $(CFLAGS) -Fo$@ $(@B).c + +$(OTTY)sfbase.o: sfbase.c $(HACK_H) + $(Q)$(CC) $(CFLAGS) /EP $(@B).c > $(OTTY)$(@B).c.preproc + $(Q)$(CC) $(CFLAGS) -Fo$@ $(@B).c + # # date.h is not used with NetHack 3.7 # onames.h is not used with NetHack 3.7 @@ -3069,6 +3080,8 @@ $(OTTY)rumors.o: rumors.c $(HACK_H) $(INCL)dlb.h $(OTTY)save.o: save.c $(HACK_H) $(OTTY)selvar.o: selvar.c $(HACK_H) $(INCL)sp_lev.h $(OTTY)sfstruct.o: sfstruct.c $(HACK_H) + $(Q)$(CC) $(CFLAGS) /EP $(@B).c > $(OTTY)$(@B).c.preproc + $(Q)$(CC) $(CFLAGS) -Fo$@ $(@B).c $(OTTY)shk.o: shk.c $(HACK_H) $(OTTY)shknam.o: shknam.c $(HACK_H) $(OTTY)sit.o: sit.c $(HACK_H) $(INCL)artifact.h @@ -3445,6 +3458,8 @@ $(OGUI)rumors.o: rumors.c $(HACK_H) $(INCL)dlb.h $(OGUI)save.o: save.c $(HACK_H) $(OGUI)selvar.o: selvar.c $(HACK_H) $(INCL)sp_lev.h $(OGUI)sfstruct.o: sfstruct.c $(HACK_H) + $(Q)$(CC) $(CFLAGS) /EP $(@B).c > $(OGUI)$(@B).c.preproc + $(Q)$(CC) $(CFLAGS) -Fo$@ $(@B).c $(OGUI)shk.o: shk.c $(HACK_H) $(OGUI)shknam.o: shknam.c $(HACK_H) $(OGUI)sit.o: sit.c $(HACK_H) $(INCL)artifact.h diff --git a/sys/windows/vs/NetHack/NetHack.vcxproj b/sys/windows/vs/NetHack/NetHack.vcxproj index 7dfa0cf6b..bdc5d771f 100644 --- a/sys/windows/vs/NetHack/NetHack.vcxproj +++ b/sys/windows/vs/NetHack/NetHack.vcxproj @@ -220,6 +220,7 @@ + @@ -294,6 +295,8 @@ + + @@ -314,4 +317,4 @@ - + \ No newline at end of file diff --git a/sys/windows/vs/NetHackW/NetHackW.vcxproj b/sys/windows/vs/NetHackW/NetHackW.vcxproj index 78a43906d..5ba44b3dc 100644 --- a/sys/windows/vs/NetHackW/NetHackW.vcxproj +++ b/sys/windows/vs/NetHackW/NetHackW.vcxproj @@ -252,6 +252,7 @@ + @@ -353,6 +354,8 @@ + + @@ -376,4 +379,4 @@ - + \ No newline at end of file diff --git a/sys/windows/windmain.c b/sys/windows/windmain.c index 04b4668ac..a2fe2da5e 100644 --- a/sys/windows/windmain.c +++ b/sys/windows/windmain.c @@ -366,6 +366,9 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ nethack_exit(EXIT_SUCCESS); if (getlock_result < 0) { + if (program_state.in_self_recover) { + program_state.in_self_recover = FALSE; + } set_savefile_name(TRUE); } /* Set up level 0 file to keep the game state. diff --git a/sys/windows/windsys.c b/sys/windows/windsys.c index ea425ce26..d7178cffa 100644 --- a/sys/windows/windsys.c +++ b/sys/windows/windsys.c @@ -505,20 +505,6 @@ get_port_id(char *buf) extern void free_winmain_stuff(void); #endif -/* return TRUE if s contains a directory, not just a filespec */ -boolean -contains_directory(const char *s) -{ - int i, slen = strlen(s); - const char *cp = s; - - for (i = 0; i < slen; ++i) { - if (*cp == '\\' || *cp == '/' || *cp == ':') - return TRUE; - } - return FALSE; -} - void nethack_exit(int code) { diff --git a/util/.gitignore b/util/.gitignore index 56d768999..11fa8a1f0 100644 --- a/util/.gitignore +++ b/util/.gitignore @@ -30,4 +30,5 @@ heaputil heaputil.c tilemappings.lst clang_rt.asan*.dll +*.sln diff --git a/util/recover.c b/util/recover.c index 07481cbc5..f43d1132c 100644 --- a/util/recover.c +++ b/util/recover.c @@ -12,9 +12,16 @@ #include "win32api.h" #endif +#define RECOVER_C + #include "config.h" #include "hacklib.h" +#include "artifact.h" +#include "rect.h" +#include "dungeon.h" +#include "hack.h" + #if !defined(O_WRONLY) && !defined(LSC) && !defined(AZTEC_C) #include #endif @@ -267,10 +274,12 @@ restore_savefile(char *basename) } /* save file should contain: - * format indicator and cmc + * format indicator (1 byte) + * n = count of critical size list (1 byte) + * n bytes of critical sizes (n bytes) * version info - * savefile info - * player name + * plnametmp = player name size (int, 2 bytes) + * player name (PL_NSIZ_PLUS) * current level (including pets) * (non-level-based) game state * other levels