]> granicus.if.org Git - nethack/commitdiff
NetHack minor release checklist items - savefiles
authornhmall <nhmall@nethack.org>
Sun, 23 Jun 2019 04:11:46 +0000 (00:11 -0400)
committernhmall <nhmall@nethack.org>
Sun, 23 Jun 2019 04:11:46 +0000 (00:11 -0400)
Make some progress on a couple of next minor release checklist
items, hopefully without introducing too many new bugs. This
is just the initial commit, and work continues.

Checklist items:

Savefiles compatible between Windows versions, whether 64-bit
or 32-bit in little-endian field format.

Selection of file formats:
 historical (structlevel saves),
 lendian (little-endian, fieldlevel saves),
 and just for proof-of-concept, ascii fieldlevel saves
 (the ascii is huge! 10x bigger than little-endian).

For the fieldlevel save, all complex data structures recursively
get broken down until until it is one of the simple types that
can't be broken down any further, and that gets when it gets
written to the output file.

New files needed for this build:

hand-coded:
include/sfprocs.h
src/sfbase.c      - really a dispatcher to one of the
                    output/input format routines.
src/sflendian.c   - little-endian output writer/reader.
src/sfascii.c     - ascii text output writer/reader.

auto-coded (generated):
include/sfproto.h
src/sfdata.c

This is just one approach. I'm sure there are countless others
and they have different pros and cons.

For producing the auto-coded files a utility called
universal-ctags, that is actively maintained and evolving,
was used to do all the heavy-lifting of parsing the
NetHack C sources to tabulate the data fields, and store
them in an intermediate file called util/nethack.tags
(not required for building NetHack if you already have a
generated include/sfproto.h and src/sfdata.c)

util/readtags (also not required for building NetHack
itself) will decipher the nethack.tags file and produce
the functions that can deal with the NetHack struct data
fields.

You can obtain the source for universal-ctags by cloning it
from here:
https://github.com/universal-ctags/ctags.git

The combination universal-ctags + util/readtags has been
tried and tested under both Windows and Linux, so it is
not tied to a particular platform.

Note: util/readtags will work only with universal-ctags
output, so other ctags are unlikely to work as-is.
Universal-ctags can be build from source very easily
under Linux, or under Windows using visual studio.

45 files changed:
doc/Guidebook.mn
doc/Guidebook.tex
include/decl.h
include/extern.h
include/hack.h
include/lev.h
include/ntconf.h
include/sfprocs.h [new file with mode: 0644]
include/sfproto.h [new file with mode: 0644]
include/sys.h
include/you.h
src/artifact.c
src/bones.c
src/cmd.c
src/do.c
src/dungeon.c
src/end.c
src/engrave.c
src/files.c
src/light.c
src/mkmaze.c
src/mkroom.c
src/o_init.c
src/options.c
src/region.c
src/restore.c
src/rumors.c
src/save.c
src/sfascii.c [new file with mode: 0644]
src/sfbase.c [new file with mode: 0644]
src/sfdata.c [new file with mode: 0644]
src/sflendian.c [new file with mode: 0644]
src/sp_lev.c
src/timeout.c
src/version.c
src/worm.c
sys/share/pcmain.c
sys/unix/Makefile.src
sys/unix/Makefile.utl
sys/unix/unixmain.c
sys/winnt/Makefile.msc
sys/winnt/windmain.c
util/readtags.c [new file with mode: 0644]
win/win32/vs2017/NetHack.vcxproj
win/win32/vs2017/NetHackW.vcxproj

index eca99a1a47c5634acf3ac8c3e859b561148e26c3..3b7a6335f4dadce7ca6c072189eba7613a019e2e 100644 (file)
 .ds h0 "NetHack Guidebook
 .ds h1
 .ds h2 %
-.ds vr "NetHack 3.6
+.ds vr "NetHack 3.7
 .ds f0 "\*(vr
 .ds f1
-.ds f2 "May 7, 2019
+.ds f2 "June 20, 2019
 .
 .\" A note on some special characters:
 .\" \(lq = left double quote
@@ -4650,6 +4650,20 @@ The syntax is the same as WIZARDS.
 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
index 9a28448bb2eb6eb58f777d25d0c9d20cb8e9d668..6d240777fe28185fb8121abb45003ba5caf5c7f4 100644 (file)
@@ -45,7 +45,7 @@
 %.au
 \author{Original version - Eric S. Raymond\\
 (Edited and expanded for 3.6 by Mike Stephenson and others)}
-\date{May 7, 2019}
+\date{June 20, 2019}
 
 \maketitle
 
@@ -5161,6 +5161,22 @@ The syntax is the same as WIZARDS.
 \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 explainign how to get local support (no default value).
 %.lp
index d07cc3ef40637926fcea54527ce35da308626f63..87bb872c7f2ac83da66b5f810feb841b1c27832f 100644 (file)
@@ -8,7 +8,7 @@
 
 #define E extern
 
-#if !defined(MFLOPPY) && !defined(VMS) && !defined(WIN32)
+#if !defined(MFLOPPY) && !defined(VMS)
 #define LOCKNAMESIZE (PL_NSIZ + 14) /* long enough for uid+name+.99 */
 #define LOCKNAMEINIT "1lock"
 #define BONESINIT "bonesnn.xxx"
 #define BONESINIT "bonesnn.xxx;1"
 #define BONESSIZE sizeof(BONESINIT)
 #endif
-#if defined(WIN32)
-#define LOCKNAMESIZE (PL_NSIZ + 25) /* long enough for username+-+name+.99 */
-#define LOCKNAMEINIT ""
-#define BONESINIT "bonesnn.xxx"
-#define BONESSIZE sizeof(BONESINIT)
-#endif
 #endif
 
+/* This is written to a savefile by a defined size on some platforms,
+   so let's not create an automatic and unnecessary incompatibility */
 #if defined(UNIX) || defined(__BEOS__)
-#define SAVESIZE (PL_NSIZ + 13) /* save/99999player.e */
+#define SAVESIZE (PL_NSIZ + 50) /* save/99999player.e */
 #else
 #ifdef VMS
-#define SAVESIZE (PL_NSIZ + 22) /* [.save]<uid>player.e;1 */
+#define SAVESIZE (PL_NSIZ + 50) /* [.save]<uid>player.e;1 */
 #else
 #if defined(WIN32)
-#define SAVESIZE (PL_NSIZ + 40) /* username-player.NetHack-saved-game */
+#define SAVESIZE (PL_NSIZ + 50) /* username-player.NetHack-saved-game */
 #else
 #define SAVESIZE FILENAME /* from macconf.h or pcconf.h */
 #endif
@@ -162,6 +158,52 @@ struct sinfo {
     int wizkit_wishing;
 };
 
+/* Flags for controlling uptodate */
+#define UTD_CHECKSIZES                 0x01
+#define UTD_CHECKFIELDCOUNTS           0x02
+#define UTD_SKIP_SANITY1               0x04
+#define UTD_SKIP_SAVEFILEINFO          0x08
+
+/* 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
+/* operations of the various saveXXXchn & co. routines */
+#define perform_bwrite(nhfp) ((nhfp)->mode & (COUNTING | WRITING))
+#define release_data(nhfp) ((nhfp)->mode & FREEING)
+
+/* Content types for fieldlevel files */
+struct fieldlevel_content {
+    boolean deflt;        /* individual fields */
+    boolean binary;       /* binary rather than text */
+    boolean json;         /* JSON */
+};
+    
+typedef struct {
+    int fd;               /* for traditional structlevel binary writes */
+    int mode;             /* holds READING, WRITING, or FREEING modes  */
+    int ftype;            /* NHF_LEVELFILE, NHF_SAVEFILE, or NHF_BONESFILE */
+    int fnidx;            /* index of procs for fieldlevel saves */
+    long count;           /* holds current line count for default style file,
+                             field count for binary style */
+    boolean structlevel;  /* traditional structure binary saves */
+    boolean fieldlevel;   /* fieldlevel saves saves each field individually */
+    boolean addinfo;      /* if set, some additional context info from core */
+    boolean eof;          /* place to mark eof reached */
+    boolean bendian;      /* set to true if executing on a big-endian machine */
+    FILE *fpdef;          /* file pointer for fieldlevel default style */
+    FILE *fpdefmap;       /* file pointer mapfile for def format */
+    FILE *fplog;          /* file pointer logfile */
+    FILE *fpdebug;        /* file pointer debug info */
+    struct fieldlevel_content style;
+} NHFILE;
+
 E const char quitchars[];
 E const char vowels[];
 E const char ynchars[];
@@ -349,6 +391,14 @@ E const char *const monexplain[], invisexplain[], *const oclass_names[];
 E const char *fqn_prefix_names[PREFIX_COUNT];
 #endif
 
+struct restore_procs {
+       const char *name;
+       int mread_flags;
+       void NDECL((*restore_minit));
+       void FDECL((*restore_mread), (int,genericptr_t,unsigned int));
+       void FDECL((*restore_bclose), (int));
+};
+
 E NEARDATA struct savefile_info sfcap, sfrestinfo, sfsaveinfo;
 
 struct opvar {
index 97662eb76a41ab59cae5adcd32d6edff27165852..afa157acacfd6a69687bcbdebd3b410965cc8acc 100644 (file)
@@ -56,8 +56,8 @@ E int FDECL(unfixable_trouble_count, (BOOLEAN_P));
 /* ### artifact.c ### */
 
 E void NDECL(init_artifacts);
-E void FDECL(save_artifacts, (int));
-E void FDECL(restore_artifacts, (int));
+E void FDECL(save_artifacts, (NHFILE *));
+E void FDECL(restore_artifacts, (NHFILE *));
 E const char *FDECL(artiname, (int));
 E struct obj *FDECL(mk_artifact, (struct obj *, ALIGNTYP_P));
 E const char *FDECL(artifact_name, (const char *, short *));
@@ -596,8 +596,8 @@ E boolean FDECL(cursed_object_at, (int, int));
 
 /* ### dungeon.c ### */
 
-E void FDECL(save_dungeon, (int, BOOLEAN_P, BOOLEAN_P));
-E void FDECL(restore_dungeon, (int));
+E void FDECL(save_dungeon, (NHFILE *, BOOLEAN_P, BOOLEAN_P));
+E void FDECL(restore_dungeon, (NHFILE *));
 E void FDECL(insert_branch, (branch *, BOOLEAN_P));
 E void NDECL(init_dungeons);
 E s_level *FDECL(find_level, (const char *));
@@ -716,8 +716,8 @@ E int NDECL(num_genocides);
 E void FDECL(delayed_killer, (int, int, const char *));
 E struct kinfo *FDECL(find_delayed_killer, (int));
 E void FDECL(dealloc_killer, (struct kinfo *));
-E void FDECL(save_killers, (int, int));
-E void FDECL(restore_killers, (int));
+E void FDECL(save_killers, (NHFILE *));
+E void FDECL(restore_killers, (NHFILE *));
 E char *FDECL(build_english_list, (char *));
 #if defined(PANICTRACE) && !defined(NO_SIGNAL)
 E void FDECL(panictrace_setsignals, (BOOLEAN_P));
@@ -741,8 +741,8 @@ E void FDECL(del_engr_at, (int, int));
 E int NDECL(freehand);
 E int NDECL(doengrave);
 E void NDECL(sanitize_engravings);
-E void FDECL(save_engravings, (int, int));
-E void FDECL(rest_engravings, (int));
+E void FDECL(save_engravings, (NHFILE *));
+E void FDECL(rest_engravings, (NHFILE *));
 E void FDECL(engr_stats, (const char *, char *, long *, long *));
 E void FDECL(del_engr, (struct engr *));
 E void FDECL(rloc_engr, (struct engr *));
@@ -781,30 +781,33 @@ E FILE *FDECL(fopen_datafile, (const char *, const char *, int));
 #ifdef MFLOPPY
 E void NDECL(set_lock_and_bones);
 #endif
+E void FDECL(zero_nhfile, (NHFILE *));
+E void FDECL(close_nhfile, (NHFILE *));
+E void FDECL(rewind_nhfile, (NHFILE *));
 E void FDECL(set_levelfile_name, (char *, int));
-E int FDECL(create_levelfile, (int, char *));
-E int FDECL(open_levelfile, (int, char *));
+E NHFILE *FDECL(create_levelfile, (int, char *));
+E NHFILE *FDECL(open_levelfile, (int, char *));
 E void FDECL(delete_levelfile, (int));
 E void NDECL(clearlocks);
-E int FDECL(create_bonesfile, (d_level *, char **, char *));
+E NHFILE *FDECL(create_bonesfile, (d_level *, char **, char *));
 #ifdef MFLOPPY
 E void NDECL(cancel_bonesfile);
 #endif
 E void FDECL(commit_bonesfile, (d_level *));
-E int FDECL(open_bonesfile, (d_level *, char **));
+E NHFILE *FDECL(open_bonesfile, (d_level *, char **));
 E int FDECL(delete_bonesfile, (d_level *));
 E void NDECL(compress_bonesfile);
 E void FDECL(set_savefile_name, (BOOLEAN_P));
 #ifdef INSURANCE
-E void FDECL(save_savefile_name, (int));
+E void FDECL(save_savefile_name, (NHFILE *));
 #endif
 #ifndef MICRO
 E void NDECL(set_error_savefile);
 #endif
-E int NDECL(create_savefile);
-E int NDECL(open_savefile);
+E NHFILE *NDECL(create_savefile);
+E NHFILE *NDECL(open_savefile);
 E int NDECL(delete_savefile);
-E int NDECL(restore_saved_game);
+E NHFILE *NDECL(restore_saved_game);
 E void FDECL(nh_compress, (const char *));
 E void FDECL(nh_uncompress, (const char *));
 E boolean FDECL(lock_file, (const char *, int, int));
@@ -1070,8 +1073,8 @@ E void FDECL(do_light_sources, (char **));
 E void FDECL(show_transient_light, (struct obj *, int, int));
 E void NDECL(transient_light_cleanup);
 E struct monst *FDECL(find_mid, (unsigned, unsigned));
-E void FDECL(save_light_sources, (int, int, int));
-E void FDECL(restore_light_sources, (int));
+E void FDECL(save_light_sources, (NHFILE *, int));
+E void FDECL(restore_light_sources, (NHFILE *));
 E void FDECL(light_stats, (const char *, char *, long *, long *));
 E void FDECL(relink_light_sources, (BOOLEAN_P));
 E void NDECL(light_sources_sanity_check);
@@ -1300,8 +1303,8 @@ E void NDECL(fixup_special);
 E void NDECL(fumaroles);
 E void NDECL(movebubbles);
 E void NDECL(water_friction);
-E void FDECL(save_waterlevel, (int, int));
-E void FDECL(restore_waterlevel, (int));
+E void FDECL(save_waterlevel, (NHFILE *));
+E void FDECL(restore_waterlevel, (NHFILE *));
 E const char *FDECL(waterbody_name, (XCHAR_P, XCHAR_P));
 
 /* ### mkobj.c ### */
@@ -1388,8 +1391,8 @@ E boolean FDECL(inside_room, (struct mkroom *, XCHAR_P, XCHAR_P));
 E boolean FDECL(somexy, (struct mkroom *, coord *));
 E void FDECL(mkundead, (coord *, BOOLEAN_P, int));
 E struct permonst *NDECL(courtmon);
-E void FDECL(save_rooms, (int));
-E void FDECL(rest_rooms, (int));
+E void FDECL(save_rooms, (NHFILE *));
+E void FDECL(rest_rooms, (NHFILE *));
 E struct mkroom *FDECL(search_special, (SCHAR_P));
 E int FDECL(cmap_to_type, (int));
 
@@ -1674,8 +1677,8 @@ E void NDECL(init_objects);
 E void FDECL(obj_shuffle_range, (int, int *, int *));
 E int NDECL(find_skates);
 E void NDECL(oinit);
-E void FDECL(savenames, (int, int));
-E void FDECL(restnames, (int));
+E void FDECL(savenames, (NHFILE *));
+E void FDECL(restnames, (NHFILE *));
 E void FDECL(discover_object, (int, BOOLEAN_P, BOOLEAN_P));
 E void FDECL(undiscover_object, (int));
 E int NDECL(dodiscovered);
@@ -2098,8 +2101,8 @@ E void NDECL(update_player_regions);
 E void FDECL(update_monster_region, (struct monst *));
 E NhRegion *FDECL(visible_region_at, (XCHAR_P, XCHAR_P));
 E void FDECL(show_region, (NhRegion *, XCHAR_P, XCHAR_P));
-E void FDECL(save_regions, (int, int));
-E void FDECL(rest_regions, (int, BOOLEAN_P));
+E void FDECL(save_regions, (NHFILE *));
+E void FDECL(rest_regions, (NHFILE *, BOOLEAN_P));
 E void FDECL(region_stats, (const char *, char *, long *, long *));
 E NhRegion *FDECL(create_gas_cloud, (XCHAR_P, XCHAR_P, int, int));
 E boolean NDECL(region_danger);
@@ -2108,18 +2111,19 @@ E void NDECL(region_safety);
 /* ### restore.c ### */
 
 E void FDECL(inven_inuse, (BOOLEAN_P));
-E int FDECL(dorecover, (int));
-E void FDECL(restcemetery, (int, struct cemetery **));
+E int FDECL(dorecover, (NHFILE *));
+E void FDECL(restcemetery, (NHFILE *, struct cemetery **));
 E void FDECL(trickery, (char *));
-E void FDECL(getlev, (int, int, XCHAR_P, BOOLEAN_P));
-E void FDECL(get_plname_from_file, (int, char *));
+E void FDECL(getlev, (NHFILE *, int, XCHAR_P, BOOLEAN_P));
+E void FDECL(get_plname_from_file, (NHFILE *, char *));
 #ifdef SELECTSAVED
 E int FDECL(restore_menu, (winid));
 #endif
 E void NDECL(minit);
 E boolean FDECL(lookup_id_mapping, (unsigned, unsigned *));
 E void FDECL(mread, (int, genericptr_t, unsigned int));
-E int FDECL(validate, (int, const char *));
+E void FDECL(newread, (NHFILE *, int, int, genericptr_t, unsigned int));
+E int FDECL(validate, (NHFILE *, const char *));
 E void NDECL(reset_restpref);
 E void FDECL(set_restpref, (const char *));
 E void FDECL(set_savepref, (const char *));
@@ -2183,8 +2187,8 @@ E char *FDECL(getrumor, (int, char *, BOOLEAN_P));
 E char *FDECL(get_rnd_text, (const char *, char *, int FDECL((*), (int))));
 E void FDECL(outrumor, (int, int));
 E void FDECL(outoracle, (BOOLEAN_P, BOOLEAN_P));
-E void FDECL(save_oracles, (int, int));
-E void FDECL(restore_oracles, (int));
+E void FDECL(save_oracles, (NHFILE *));
+E void FDECL(restore_oracles, (NHFILE *));
 E int FDECL(doconsult, (struct monst *));
 E void NDECL(rumor_check);
 
@@ -2192,16 +2196,16 @@ E void NDECL(rumor_check);
 
 E int NDECL(dosave);
 E int NDECL(dosave0);
-E boolean FDECL(tricked_fileremoved, (int, char *));
+E boolean FDECL(tricked_fileremoved, (NHFILE *, char *));
 #ifdef INSURANCE
 E void NDECL(savestateinlock);
 #endif
 #ifdef MFLOPPY
-E boolean FDECL(savelev, (int, XCHAR_P, int));
+E boolean FDECL(savelev, (NHFILE *, XCHAR_P));
 E boolean FDECL(swapin_file, (int));
 E void NDECL(co_false);
 #else
-E void FDECL(savelev, (int, XCHAR_P, int));
+E void FDECL(savelev, (NHFILE *, XCHAR_P));
 #endif
 E genericptr_t FDECL(mon_to_buffer, (struct monst *, int *));
 E void FDECL(bufon, (int));
@@ -2210,15 +2214,22 @@ E void FDECL(bflush, (int));
 E void FDECL(bwrite, (int, genericptr_t, unsigned int));
 E void FDECL(bclose, (int));
 E void FDECL(def_bclose, (int));
+E void FDECL(newwrite, (NHFILE *, int, int, genericptr_t, unsigned int));
+E void FDECL(newclose, (NHFILE *));
 #if defined(ZEROCOMP)
 E void FDECL(zerocomp_bclose, (int));
 #endif
-E void FDECL(savecemetery, (int, int, struct cemetery **));
-E void FDECL(savefruitchn, (int, int));
-E void FDECL(store_plname_in_file, (int));
+E void FDECL(savecemetery, (NHFILE *, struct cemetery **));
+E void FDECL(savefruitchn, (NHFILE *));
+E void FDECL(store_plname_in_file, (NHFILE *));
 E void NDECL(free_dungeons);
 E void NDECL(freedynamicdata);
-E void FDECL(store_savefileinfo, (int));
+E void FDECL(store_savefileinfo, (NHFILE *));
+E void FDECL(store_savefileinfo, (NHFILE *));
+E int NDECL(nhdatatypes_size);
+E void FDECL(assignlog, (char *, char*, int));
+E FILE *FDECL(getlog, (NHFILE *));
+E void FDECL(closelog, (NHFILE *));
 
 /* ### shk.c ### */
 
@@ -2455,8 +2466,8 @@ E void FDECL(spot_stop_timers, (XCHAR_P, XCHAR_P, SHORT_P));
 E long FDECL(spot_time_expires, (XCHAR_P, XCHAR_P, SHORT_P));
 E long FDECL(spot_time_left, (XCHAR_P, XCHAR_P, SHORT_P));
 E boolean FDECL(obj_is_local, (struct obj *));
-E void FDECL(save_timers, (int, int, int));
-E void FDECL(restore_timers, (int, int, BOOLEAN_P, long));
+E void FDECL(save_timers, (NHFILE *, int));
+E void FDECL(restore_timers, (NHFILE *, int, BOOLEAN_P, long));
 E void FDECL(timer_stats, (const char *, char *, long *, long *));
 E void FDECL(relink_timers, (BOOLEAN_P));
 E int NDECL(wiz_timeout_queue);
@@ -2630,9 +2641,9 @@ E int NDECL(doextversion);
 E boolean FDECL(comp_times, (long));
 #endif
 E boolean
-FDECL(check_version, (struct version_info *, const char *, BOOLEAN_P));
-E boolean FDECL(uptodate, (int, const char *));
-E void FDECL(store_version, (int));
+FDECL(check_version, (struct version_info *, const char *, BOOLEAN_P, unsigned long));
+E boolean FDECL(uptodate, (NHFILE *, const char *, unsigned long));
+E void FDECL(store_version, (NHFILE *));
 E unsigned long FDECL(get_feature_notice_ver, (char *));
 E unsigned long NDECL(get_current_feature_ver);
 E const char *FDECL(copyright_banner_line, (int));
@@ -2882,8 +2893,8 @@ E void FDECL(wormhitu, (struct monst *));
 E void FDECL(cutworm, (struct monst *, XCHAR_P, XCHAR_P, BOOLEAN_P));
 E void FDECL(see_wsegs, (struct monst *));
 E void FDECL(detect_wsegs, (struct monst *, BOOLEAN_P));
-E void FDECL(save_worm, (int, int));
-E void FDECL(rest_worm, (int));
+E void FDECL(save_worm, (NHFILE *));
+E void FDECL(rest_worm, (NHFILE *));
 E void FDECL(place_wsegs, (struct monst *, struct monst *));
 E void FDECL(sanity_check_worm, (struct monst *));
 E void FDECL(remove_worm, (struct monst *));
index 8f65b975aba008648ccd6b0fe1baa86b3b7c89af..07928ddc65e0f131a0b8e98188a350f5edc14d09 100644 (file)
@@ -232,6 +232,13 @@ enum hmon_atkmode_types {
     HMON_DRAGGED = 4  /* attached iron ball, pulled into mon */
 };
 
+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) */
+};
+
 /* sortloot() return type; needed before extern.h */
 struct sortloot_item {
     struct obj *obj;
index 97fe8d660bf9f24a4571a00de4fa4375a0016a5c..731944702c533fadeea9a98c16ba8f8d0bf2743e 100644 (file)
@@ -8,12 +8,5 @@
 #ifndef LEV_H
 #define LEV_H
 
-#define COUNT_SAVE 0x1
-#define WRITE_SAVE 0x2
-#define FREE_SAVE 0x4
-
-/* operations of the various saveXXXchn & co. routines */
-#define perform_bwrite(mode) ((mode) & (COUNT_SAVE | WRITE_SAVE))
-#define release_data(mode) ((mode) &FREE_SAVE)
 
 #endif /* LEV_H */
index 142e269d16b5e58fc9b5ff7252031a2dca22751e..2647c243f49fa8791264c7ecf375f1ce044577e1 100644 (file)
@@ -80,6 +80,7 @@
                      * objects being thrown when the hangup occurs.    \
                      */
 
+#define MAIL
 /* Stuff to help the user with some common, yet significant errors */
 #define INTERJECT_PANIC 0
 #define INTERJECTION_TYPES (INTERJECT_PANIC + 1)
@@ -104,6 +105,7 @@ extern void NDECL(getlock);
 #endif
  
 #ifdef _MSC_VER
+#define HAS_STDINT
 #if (_MSC_VER > 1000)
 /* Visual C 8 warning elimination */
 #ifndef _CRT_SECURE_NO_DEPRECATE
diff --git a/include/sfprocs.h b/include/sfprocs.h
new file mode 100644 (file)
index 0000000..a3b3f5d
--- /dev/null
@@ -0,0 +1,192 @@
+/* NetHack 3.6 sfprocs.h       Tue Nov  6 19:38:48 2018 */
+/* Copyright (c) NetHack Development Team 2018.                   */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#ifndef SFPROCS_H
+#define SFPROCS_H
+
+#include "hack.h"
+#include "integer.h"
+#include "wintype.h"
+
+#define E extern
+
+/* output routines */
+E void FDECL(ascii_sfo_aligntyp, (NHFILE *, aligntyp *, const char *, const char *, int));
+E void FDECL(ascii_sfo_any, (NHFILE *, union any *d_any, const char *, const char *, int));
+E void FDECL(ascii_sfo_bitfield, (NHFILE *, uint8_t *, const char *, const char *, int));
+E void FDECL(ascii_sfo_boolean, (NHFILE *, boolean *, const char *, const char *, int));
+E void FDECL(ascii_sfo_char, (NHFILE *, char *, const char *, const char *, int));
+E void FDECL(ascii_sfo_genericptr, (NHFILE *, genericptr_t *, const char *, const char *, int));
+E void FDECL(ascii_sfo_int, (NHFILE *, int *, const char *, const char *, int));
+E void FDECL(ascii_sfo_long, (NHFILE *, long *, const char *, const char *, int));
+E void FDECL(ascii_sfo_schar, (NHFILE *, schar *, const char *, const char *, int));
+E void FDECL(ascii_sfo_short, (NHFILE *, short *, const char *, const char *, int));
+E void FDECL(ascii_sfo_size_t, (NHFILE *, size_t *, const char *, const char *, int));
+E void FDECL(ascii_sfo_time_t, (NHFILE *, time_t *, const char *, const char *, int));
+E void FDECL(ascii_sfo_unsigned, (NHFILE *, unsigned *, const char *, const char *, int));
+E void FDECL(ascii_sfo_uchar, (NHFILE *, unsigned char *, const char *, const char *, int));
+E void FDECL(ascii_sfo_uint, (NHFILE *, unsigned int *, const char *, const char *, int));
+E void FDECL(ascii_sfo_ulong, (NHFILE *, unsigned long *, const char *, const char *, int));
+E void FDECL(ascii_sfo_ushort, (NHFILE *, unsigned short *, const char *, const char *, int));
+E void FDECL(ascii_sfo_xchar, (NHFILE *, xchar *, const char *, const char *, int));
+E void FDECL(ascii_sfo_str, (NHFILE *, char *, const char *, const char *, int));
+E void FDECL(ascii_sfo_addinfo, (NHFILE *, const char *, const char *, const char *, int));
+
+/* input routines */
+E void FDECL(ascii_sfi_aligntyp, (NHFILE *, aligntyp *, const char *, const char *, int));
+E void FDECL(ascii_sfi_any, (NHFILE *, union any *d_any, const char *, const char *, int));
+E void FDECL(ascii_sfi_bitfield, (NHFILE *, uint8_t *, const char *, const char *, int));
+E void FDECL(ascii_sfi_boolean, (NHFILE *, boolean *, const char *, const char *, int));
+E void FDECL(ascii_sfi_char, (NHFILE *, char *, const char *, const char *, int));
+E void FDECL(ascii_sfi_genericptr, (NHFILE *, genericptr_t *, const char *, const char *, int));
+E void FDECL(ascii_sfi_int, (NHFILE *, int *, const char *, const char *, int));
+E void FDECL(ascii_sfi_long, (NHFILE *, long *, const char *, const char *, int));
+E void FDECL(ascii_sfi_schar, (NHFILE *, schar *, const char *, const char *, int));
+E void FDECL(ascii_sfi_short, (NHFILE *, short *, const char *, const char *, int));
+E void FDECL(ascii_sfi_size_t, (NHFILE *, size_t *, const char *, const char *, int));
+E void FDECL(ascii_sfi_time_t, (NHFILE *, time_t *, const char *, const char *, int));
+E void FDECL(ascii_sfi_unsigned, (NHFILE *, unsigned *, const char *, const char *, int));
+E void FDECL(ascii_sfi_uchar, (NHFILE *, unsigned char *, const char *, const char *, int));
+E void FDECL(ascii_sfi_uint, (NHFILE *, unsigned int *, const char *, const char *, int));
+E void FDECL(ascii_sfi_ulong, (NHFILE *, unsigned long *, const char *, const char *, int));
+E void FDECL(ascii_sfi_ushort, (NHFILE *, unsigned short *, const char *, const char *, int));
+E void FDECL(ascii_sfi_xchar, (NHFILE *, xchar *, const char *, const char *, int));
+E void FDECL(ascii_sfi_str, (NHFILE *, char *, const char *, const char *, int));
+E void FDECL(ascii_sfi_addinfo, (NHFILE *, const char *, const char *, const char *, int));
+
+/* output routines */
+E void FDECL(lendian_sfo_aligntyp, (NHFILE *, aligntyp *, const char *, const char *, int));
+E void FDECL(lendian_sfo_any, (NHFILE *, union any *d_any, const char *, const char *, int));
+E void FDECL(lendian_sfo_bitfield, (NHFILE *, uint8_t *, const char *, const char *, int));
+E void FDECL(lendian_sfo_boolean, (NHFILE *, boolean *, const char *, const char *, int));
+E void FDECL(lendian_sfo_char, (NHFILE *, char *, const char *, const char *, int));
+E void FDECL(lendian_sfo_genericptr, (NHFILE *, genericptr_t *, const char *, const char *, int));
+E void FDECL(lendian_sfo_int, (NHFILE *, int *, const char *, const char *, int));
+E void FDECL(lendian_sfo_long, (NHFILE *, long *, const char *, const char *, int));
+E void FDECL(lendian_sfo_schar, (NHFILE *, schar *, const char *, const char *, int));
+E void FDECL(lendian_sfo_short, (NHFILE *, short *, const char *, const char *, int));
+E void FDECL(lendian_sfo_size_t, (NHFILE *, size_t *, const char *, const char *, int));
+E void FDECL(lendian_sfo_time_t, (NHFILE *, time_t *, const char *, const char *, int));
+E void FDECL(lendian_sfo_unsigned, (NHFILE *, unsigned *, const char *, const char *, int));
+E void FDECL(lendian_sfo_uchar, (NHFILE *, unsigned char *, const char *, const char *, int));
+E void FDECL(lendian_sfo_uint, (NHFILE *, unsigned int *, const char *, const char *, int));
+E void FDECL(lendian_sfo_ulong, (NHFILE *, unsigned long *, const char *, const char *, int));
+E void FDECL(lendian_sfo_ushort, (NHFILE *, unsigned short *, const char *, const char *, int));
+E void FDECL(lendian_sfo_xchar, (NHFILE *, xchar *, const char *, const char *, int));
+E void FDECL(lendian_sfo_str, (NHFILE *, char *, const char *, const char *, int));
+E void FDECL(lendian_sfo_addinfo, (NHFILE *, const char *, const char *, const char *, int));
+
+/* input routines */
+E void FDECL(lendian_sfi_aligntyp, (NHFILE *, aligntyp *, const char *, const char *, int));
+E void FDECL(lendian_sfi_any, (NHFILE *, union any *d_any, const char *, const char *, int));
+E void FDECL(lendian_sfi_bitfield, (NHFILE *, uint8_t *, const char *, const char *, int));
+E void FDECL(lendian_sfi_boolean, (NHFILE *, boolean *, const char *, const char *, int));
+E void FDECL(lendian_sfi_char, (NHFILE *, char *, const char *, const char *, int));
+E void FDECL(lendian_sfi_genericptr, (NHFILE *, genericptr_t *, const char *, const char *, int));
+E void FDECL(lendian_sfi_int, (NHFILE *, int *, const char *, const char *, int));
+E void FDECL(lendian_sfi_long, (NHFILE *, long *, const char *, const char *, int));
+E void FDECL(lendian_sfi_schar, (NHFILE *, schar *, const char *, const char *, int));
+E void FDECL(lendian_sfi_short, (NHFILE *, short *, const char *, const char *, int));
+E void FDECL(lendian_sfi_size_t, (NHFILE *, size_t *, const char *, const char *, int));
+E void FDECL(lendian_sfi_time_t, (NHFILE *, time_t *, const char *, const char *, int));
+E void FDECL(lendian_sfi_unsigned, (NHFILE *, unsigned *, const char *, const char *, int));
+E void FDECL(lendian_sfi_uchar, (NHFILE *, unsigned char *, const char *, const char *, int));
+E void FDECL(lendian_sfi_uint, (NHFILE *, unsigned int *, const char *, const char *, int));
+E void FDECL(lendian_sfi_ulong, (NHFILE *, unsigned long *, const char *, const char *, int));
+E void FDECL(lendian_sfi_ushort, (NHFILE *, unsigned short *, const char *, const char *, int));
+E void FDECL(lendian_sfi_xchar, (NHFILE *, xchar *, const char *, const char *, int));
+E void FDECL(lendian_sfi_str, (NHFILE *, char *, const char *, const char *, int));
+E void FDECL(lendian_sfi_addinfo, (NHFILE *, const char *, const char *, const char *, int));
+
+#ifdef JSON_SUPPORT
+/* output routines */
+E void FDECL(json_sfo_aligntyp, (NHFILE *, aligntype *, const char *, const char *, int));
+E void FDECL(json_sfo_any, (NHFILE *, union any *d_any, const char *, const char *, int));
+E void FDECL(json_sfo_bitfield, (NHFILE *, uint8_t *, const char *, const char *, int));
+E void FDECL(json_sfo_boolean, (NHFILE *, boolean *, const char *, const char *, int));
+E void FDECL(json_sfo_char, (NHFILE *, char *, const char *, const char *, int));
+E void FDECL(json_sfo_genericptr, (NHFILE *, genericptr_t *, const char *, const char *, int));
+E void FDECL(json_sfo_int, (NHFILE *, int *, const char *, const char *, int));
+E void FDECL(json_sfo_long, (NHFILE *, long *, const char *, const char *, int));
+E void FDECL(json_sfo_schar, (NHFILE *, schar *, const char *, const char *, int));
+E void FDECL(json_sfo_short, (NHFILE *, short *, const char *, const char *, int));
+E void FDECL(json_sfo_size_t, (NHFILE *, size_t *, const char *, const char *, int));
+E void FDECL(json_sfo_time_t, (NHFILE *, time_t *, const char *, const char *, int));
+E void FDECL(json_sfo_unsigned, (NHFILE *, unsigned *, const char *, const char *, int));
+E void FDECL(json_sfo_uchar, (NHFILE *, unsigned char *, const char *, const char *, int));
+E void FDECL(json_sfo_uint, (NHFILE *, unsigned int *, const char *, const char *, int));
+E void FDECL(json_sfo_ulong, (NHFILE *, unsigned long *, const char *, const char *, int));
+E void FDECL(json_sfo_ushort, (NHFILE *, unsigned short *, const char *, const char *, int));
+E void FDECL(json_sfo_xchar, (NHFILE *, xchar *, const char *, const char *, int));
+E void FDECL(json_sfo_str, (NHFILE *, char *, const char *, const char *, int));
+E void FDECL(json_sfo_addinfo), (NHFILE *, const char *, const char *, const char *, int));
+
+/* input routines */
+E void FDECL(json_sfi_aligntyp, (NHFILE *, aligntype *, const char *, const char *, int));
+E void FDECL(json_sfi_any, (NHFILE *, union any *d_any, const char *, const char *, int));
+E void FDECL(json_sfi_bitfield, (NHFILE *, uint8_t *, const char *, const char *, int));
+E void FDECL(json_sfi_boolean, (NHFILE *, boolean *, const char *, const char *, int));
+E void FDECL(json_sfi_char, (NHFILE *, char *, const char *, const char *, int));
+E void FDECL(json_sfi_genericptr, (NHFILE *, genericptr_t *, const char *, const char *, int));
+E void FDECL(json_sfi_int, (NHFILE *, int *, const char *, const char *, int));
+E void FDECL(json_sfi_long, (NHFILE *, long *, const char *, const char *, int));
+E void FDECL(json_sfi_schar, (NHFILE *, schar *, const char *, const char *, int));
+E void FDECL(json_sfi_short, (NHFILE *, short *, const char *, const char *, int));
+E void FDECL(json_sfi_size_t, (NHFILE *, size_t *, const char *, const char *, int));
+E void FDECL(json_sfi_time_t, (NHFILE *, time_t *, const char *, const char *, int));
+E void FDECL(json_sfi_unsigned, (NHFILE *, unsigned *, const char *, const char *, int));
+E void FDECL(json_sfi_uchar, (NHFILE *, unsigned char *, const char *, const char *, int));
+E void FDECL(json_sfi_uint, (NHFILE *, unsigned int *, const char *, const char *, int));
+E void FDECL(json_sfi_ulong, (NHFILE *, unsigned long *, const char *, const char *, int));
+E void FDECL(json_sfi_ushort, (NHFILE *, unsigned short *, const char *, const char *, int));
+E void FDECL(json_sfi_xchar, (NHFILE *, xchar *, const char *, const char *, int));
+E void FDECL(json_sfi_str, (NHFILE *, char *, const char *, const char *, int));
+E void FDECL(json_sfi_addinfo), (NHFILE *, const char *, const char *, const char *, int));
+#endif /* JSON_SUPPORT */
+
+struct fieldlevel_procs {
+    void FDECL((*sf_aligntyp), (NHFILE *, aligntyp *, const char *, const char *, int));
+    void FDECL((*sf_any), (NHFILE *, union any *d_any, const char *, const char *, int));
+    void FDECL((*sf_bitfield), (NHFILE *, uint8_t *, const char *, const char *, int));
+    void FDECL((*sf_boolean), (NHFILE *, boolean *, const char *, const char *, int));
+    void FDECL((*sf_char), (NHFILE *, char *, const char *, const char *, int));
+    void FDECL((*sf_genericptr), (NHFILE *, genericptr_t *, const char *, const char *, int));
+    void FDECL((*sf_int), (NHFILE *, int *, const char *, const char *, int));
+    void FDECL((*sf_long), (NHFILE *, long *, const char *, const char *, int));
+    void FDECL((*sf_schar), (NHFILE *, schar *, const char *, const char *, int));
+    void FDECL((*sf_short), (NHFILE *, short *, const char *, const char *, int));
+    void FDECL((*sf_size_t), (NHFILE *, size_t *, const char *, const char *, int));
+    void FDECL((*sf_time_t), (NHFILE *, time_t *, const char *, const char *, int));
+    void FDECL((*sf_unsigned), (NHFILE *, unsigned *, const char *, const char *, int));
+    void FDECL((*sf_uchar), (NHFILE *, unsigned char *, const char *, const char *, int));
+    void FDECL((*sf_uint), (NHFILE *, unsigned int *, const char *, const char *, int));
+    void FDECL((*sf_ulong), (NHFILE *, unsigned long *, const char *, const char *, int));
+    void FDECL((*sf_ushort), (NHFILE *, unsigned short *, const char *, const char *, int));
+    void FDECL((*sf_xchar), (NHFILE *, xchar *, const char *, const char *, int));
+    void FDECL((*sf_str), (NHFILE *, char *, const char *, const char *, int));
+    void FDECL((*sf_addinfo), (NHFILE *, const char *, const char *, const char *, int));
+};
+
+struct sf_procs {
+    const char *ext;
+    struct fieldlevel_procs fn;
+};
+
+E void NDECL(sf_init);
+E struct sf_procs sfoprocs[4], sfiprocs[4];
+
+E struct sf_procs ascii_sfo_procs;
+E struct sf_procs ascii_sfi_procs;
+E struct sf_procs lendian_sfo_procs;
+E struct sf_procs lendian_sfi_procs;
+E struct sf_procs stub_sfo_procs;
+E struct sf_procs stub_sfi_procs;
+
+#ifdef JSON_SUPPORT
+E struct sf_procs json_sfo_procs;
+E struct sf_procs json_sfi_procs;
+#endif
+
+#undef E
+#endif /* SFPROCS_H */
diff --git a/include/sfproto.h b/include/sfproto.h
new file mode 100644 (file)
index 0000000..1e67337
--- /dev/null
@@ -0,0 +1,201 @@
+/* NetHack 3.7 sfproto.h       Sat Jun 22 23:55:47 2019 */
+/* Copyright (c) NetHack Development Team 2018.                   */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE!          */
+
+#ifndef SFPROTO_H
+#define SFPROTO_H
+
+#include "hack.h"
+#include "integer.h"
+#include "wintype.h"
+
+#define E extern
+
+E int NDECL(critical_members_count);
+/* sfbase.c output functions */
+E void FDECL(sfo_addinfo, (NHFILE *, const char *, const char *, const char *, int));
+E void FDECL(sfo_aligntyp, (NHFILE *, aligntyp *, const char *, const char *, int));
+E void FDECL(sfo_any, (NHFILE *, anything *, const char *, const char *, int));
+E void FDECL(sfo_bitfield, (NHFILE *, uint8_t *, const char *, const char *, int));
+E void FDECL(sfo_boolean, (NHFILE *, boolean *, const char *, const char *, int));
+E void FDECL(sfo_char, (NHFILE *, const char *, const char *, const char *, int));
+E void FDECL(sfo_genericptr, (NHFILE *, genericptr_t *, const char *, const char *, int));
+E void FDECL(sfo_int, (NHFILE *, int *, const char *, const char *, int));
+E void FDECL(sfo_long, (NHFILE *, long *, const char *, const char *, int));
+E void FDECL(sfo_schar, (NHFILE *, schar *, const char *, const char *, int));
+E void FDECL(sfo_short, (NHFILE *, short *, const char *, const char *, int));
+E void FDECL(sfo_size_t, (NHFILE *, size_t *, const char *, const char *, int));
+E void FDECL(sfo_time_t, (NHFILE *, time_t *, const char *, const char *, int));
+E void FDECL(sfo_uchar, (NHFILE *, uchar *, const char *, const char *, int));
+E void FDECL(sfo_unsigned, (NHFILE *, unsigned *, const char *, const char *, int));
+E void FDECL(sfo_uchar, (NHFILE *, unsigned char *, const char *, const char *, int));
+E void FDECL(sfo_uint, (NHFILE *, unsigned int *, const char *, const char *, int));
+E void FDECL(sfo_ulong, (NHFILE *, unsigned long *, const char *, const char *, int));
+E void FDECL(sfo_ushort, (NHFILE *, unsigned short *, const char *, const char *, int));
+E void FDECL(sfo_xchar, (NHFILE *, xchar *, const char *, const char *, int));
+E void FDECL(sfo_str, (NHFILE *, const char *, const char *, const char *, int));
+/* sfbase.c input functions */
+E void FDECL(sfi_addinfo, (NHFILE *, const char *, const char *, const char *, int));
+E void FDECL(sfi_aligntyp, (NHFILE *, aligntyp *, const char *, const char *, int));
+E void FDECL(sfi_any, (NHFILE *, anything *, const char *, const char *, int));
+E void FDECL(sfi_bitfield, (NHFILE *, uint8_t *, const char *, const char *, int));
+E void FDECL(sfi_boolean, (NHFILE *, boolean *, const char *, const char *, int));
+E void FDECL(sfi_char, (NHFILE *, const char *, const char *, const char *, int));
+E void FDECL(sfi_genericptr, (NHFILE *, genericptr_t *, const char *, const char *, int));
+E void FDECL(sfi_int, (NHFILE *, int *, const char *, const char *, int));
+E void FDECL(sfi_long, (NHFILE *, long *, const char *, const char *, int));
+E void FDECL(sfi_schar, (NHFILE *, schar *, const char *, const char *, int));
+E void FDECL(sfi_short, (NHFILE *, short *, const char *, const char *, int));
+E void FDECL(sfi_size_t, (NHFILE *, size_t *, const char *, const char *, int));
+E void FDECL(sfi_time_t, (NHFILE *, time_t *, const char *, const char *, int));
+E void FDECL(sfi_uchar, (NHFILE *, uchar *, const char *, const char *, int));
+E void FDECL(sfi_unsigned, (NHFILE *, unsigned *, const char *, const char *, int));
+E void FDECL(sfi_uchar, (NHFILE *, unsigned char *, const char *, const char *, int));
+E void FDECL(sfi_uint, (NHFILE *, unsigned int *, const char *, const char *, int));
+E void FDECL(sfi_ulong, (NHFILE *, unsigned long *, const char *, const char *, int));
+E void FDECL(sfi_ushort, (NHFILE *, unsigned short *, const char *, const char *, int));
+E void FDECL(sfi_xchar, (NHFILE *, xchar *, const char *, const char *, int));
+E void FDECL(sfi_str, (NHFILE *, const char *, const char *, const char *, int));
+/* generated output functions */
+E void FDECL(sfo_align, (NHFILE *, struct align *, const char *, const char *, int));
+E void FDECL(sfo_attribs, (NHFILE *, struct attribs *, const char *, const char *, int));
+E void FDECL(sfo_bill_x, (NHFILE *, struct bill_x *, const char *, const char *, int));
+E void FDECL(sfo_book_info, (NHFILE *, struct book_info *, const char *, const char *, int));
+E void FDECL(sfo_branch, (NHFILE *, struct branch *, const char *, const char *, int));
+E void FDECL(sfo_bubble, (NHFILE *, struct bubble *, const char *, const char *, int));
+E void FDECL(sfo_cemetery, (NHFILE *, struct cemetery *, const char *, const char *, int));
+E void FDECL(sfo_context_info, (NHFILE *, struct context_info *, const char *, const char *, int));
+E void FDECL(sfo_d_flags, (NHFILE *, struct d_flags *, const char *, const char *, int));
+E void FDECL(sfo_d_level, (NHFILE *, struct d_level *, const char *, const char *, int));
+E void FDECL(sfo_damage, (NHFILE *, struct damage *, const char *, const char *, int));
+E void FDECL(sfo_dest_area, (NHFILE *, struct dest_area *, const char *, const char *, int));
+E void FDECL(sfo_dgn_topology, (NHFILE *, struct dgn_topology *, const char *, const char *, int));
+E void FDECL(sfo_dig_info, (NHFILE *, struct dig_info *, const char *, const char *, int));
+E void FDECL(sfo_dungeon, (NHFILE *, struct dungeon *, const char *, const char *, int));
+E void FDECL(sfo_edog, (NHFILE *, struct edog *, const char *, const char *, int));
+E void FDECL(sfo_egd, (NHFILE *, struct egd *, const char *, const char *, int));
+E void FDECL(sfo_emin, (NHFILE *, struct emin *, const char *, const char *, int));
+E void FDECL(sfo_engr, (NHFILE *, struct engr *, const char *, const char *, int));
+E void FDECL(sfo_epri, (NHFILE *, struct epri *, const char *, const char *, int));
+E void FDECL(sfo_eshk, (NHFILE *, struct eshk *, const char *, const char *, int));
+E void FDECL(sfo_fakecorridor, (NHFILE *, struct fakecorridor *, const char *, const char *, int));
+E void FDECL(sfo_fe, (NHFILE *, struct fe *, const char *, const char *, int));
+E void FDECL(sfo_flag, (NHFILE *, struct flag *, const char *, const char *, int));
+E void FDECL(sfo_fruit, (NHFILE *, struct fruit *, const char *, const char *, int));
+E void FDECL(sfo_kinfo, (NHFILE *, struct kinfo *, const char *, const char *, int));
+E void FDECL(sfo_levelflags, (NHFILE *, struct levelflags *, const char *, const char *, int));
+E void FDECL(sfo_linfo, (NHFILE *, struct linfo *, const char *, const char *, int));
+E void FDECL(sfo_ls_t, (NHFILE *, struct ls_t *, const char *, const char *, int));
+E void FDECL(sfo_mapseen_feat, (NHFILE *, struct mapseen_feat *, const char *, const char *, int));
+E void FDECL(sfo_mapseen_flags, (NHFILE *, struct mapseen_flags *, const char *, const char *, int));
+E void FDECL(sfo_mapseen_rooms, (NHFILE *, struct mapseen_rooms *, const char *, const char *, int));
+E void FDECL(sfo_mapseen, (NHFILE *, struct mapseen *, const char *, const char *, int));
+E void FDECL(sfo_mextra, (NHFILE *, struct mextra *, const char *, const char *, int));
+E void FDECL(sfo_mkroom, (NHFILE *, struct mkroom *, const char *, const char *, int));
+E void FDECL(sfo_monst, (NHFILE *, struct monst *, const char *, const char *, int));
+E void FDECL(sfo_mvitals, (NHFILE *, struct mvitals *, const char *, const char *, int));
+E void FDECL(sfo_nhcoord, (NHFILE *, struct nhcoord *, const char *, const char *, int));
+E void FDECL(sfo_nhrect, (NHFILE *, struct nhrect *, const char *, const char *, int));
+E void FDECL(sfo_novel_tracking, (NHFILE *, struct novel_tracking *, const char *, const char *, int));
+E void FDECL(sfo_obj, (NHFILE *, struct obj *, const char *, const char *, int));
+E void FDECL(sfo_objclass, (NHFILE *, struct objclass *, const char *, const char *, int));
+E void FDECL(sfo_obj_split, (NHFILE *, struct obj_split *, const char *, const char *, int));
+E void FDECL(sfo_oextra, (NHFILE *, struct oextra *, const char *, const char *, int));
+E void FDECL(sfo_polearm_info, (NHFILE *, struct polearm_info *, const char *, const char *, int));
+E void FDECL(sfo_prop, (NHFILE *, struct prop *, const char *, const char *, int));
+E void FDECL(sfo_q_score, (NHFILE *, struct q_score *, const char *, const char *, int));
+E void FDECL(sfo_rm, (NHFILE *, struct rm *, const char *, const char *, int));
+E void FDECL(sfo_s_level, (NHFILE *, struct s_level *, const char *, const char *, int));
+E void FDECL(sfo_savefile_info, (NHFILE *, struct savefile_info *, const char *, const char *, int));
+E void FDECL(sfo_skills, (NHFILE *, struct skills *, const char *, const char *, int));
+E void FDECL(sfo_spell, (NHFILE *, struct spell *, const char *, const char *, int));
+E void FDECL(sfo_stairway, (NHFILE *, struct stairway *, const char *, const char *, int));
+E void FDECL(sfo_takeoff_info, (NHFILE *, struct takeoff_info *, const char *, const char *, int));
+E void FDECL(sfo_tin_info, (NHFILE *, struct tin_info *, const char *, const char *, int));
+E void FDECL(sfo_trap, (NHFILE *, struct trap *, const char *, const char *, int));
+E void FDECL(sfo_tribute_info, (NHFILE *, struct tribute_info *, const char *, const char *, int));
+E void FDECL(sfo_u_achieve, (NHFILE *, struct u_achieve *, const char *, const char *, int));
+E void FDECL(sfo_u_conduct, (NHFILE *, struct u_conduct *, const char *, const char *, int));
+E void FDECL(sfo_u_event, (NHFILE *, struct u_event *, const char *, const char *, int));
+E void FDECL(sfo_u_have, (NHFILE *, struct u_have *, const char *, const char *, int));
+E void FDECL(sfo_u_realtime, (NHFILE *, struct u_realtime *, const char *, const char *, int));
+E void FDECL(sfo_u_roleplay, (NHFILE *, struct u_roleplay *, const char *, const char *, int));
+E void FDECL(sfo_version_info, (NHFILE *, struct version_info *, const char *, const char *, int));
+E void FDECL(sfo_victual_info, (NHFILE *, struct victual_info *, const char *, const char *, int));
+E void FDECL(sfo_vlaunchinfo, (NHFILE *, union vlaunchinfo *, const char *, const char *, int));
+E void FDECL(sfo_vptrs, (NHFILE *, union vptrs *, const char *, const char *, int));
+E void FDECL(sfo_warntype_info, (NHFILE *, struct warntype_info *, const char *, const char *, int));
+E void FDECL(sfo_you, (NHFILE *, struct you *, const char *, const char *, int));
+/* generated input functions */
+E void FDECL(sfi_align, (NHFILE *, struct align *, const char *, const char *, int));
+E void FDECL(sfi_attribs, (NHFILE *, struct attribs *, const char *, const char *, int));
+E void FDECL(sfi_bill_x, (NHFILE *, struct bill_x *, const char *, const char *, int));
+E void FDECL(sfi_book_info, (NHFILE *, struct book_info *, const char *, const char *, int));
+E void FDECL(sfi_branch, (NHFILE *, struct branch *, const char *, const char *, int));
+E void FDECL(sfi_bubble, (NHFILE *, struct bubble *, const char *, const char *, int));
+E void FDECL(sfi_cemetery, (NHFILE *, struct cemetery *, const char *, const char *, int));
+E void FDECL(sfi_context_info, (NHFILE *, struct context_info *, const char *, const char *, int));
+E void FDECL(sfi_d_flags, (NHFILE *, struct d_flags *, const char *, const char *, int));
+E void FDECL(sfi_d_level, (NHFILE *, struct d_level *, const char *, const char *, int));
+E void FDECL(sfi_damage, (NHFILE *, struct damage *, const char *, const char *, int));
+E void FDECL(sfi_dest_area, (NHFILE *, struct dest_area *, const char *, const char *, int));
+E void FDECL(sfi_dgn_topology, (NHFILE *, struct dgn_topology *, const char *, const char *, int));
+E void FDECL(sfi_dig_info, (NHFILE *, struct dig_info *, const char *, const char *, int));
+E void FDECL(sfi_dungeon, (NHFILE *, struct dungeon *, const char *, const char *, int));
+E void FDECL(sfi_edog, (NHFILE *, struct edog *, const char *, const char *, int));
+E void FDECL(sfi_egd, (NHFILE *, struct egd *, const char *, const char *, int));
+E void FDECL(sfi_emin, (NHFILE *, struct emin *, const char *, const char *, int));
+E void FDECL(sfi_engr, (NHFILE *, struct engr *, const char *, const char *, int));
+E void FDECL(sfi_epri, (NHFILE *, struct epri *, const char *, const char *, int));
+E void FDECL(sfi_eshk, (NHFILE *, struct eshk *, const char *, const char *, int));
+E void FDECL(sfi_fakecorridor, (NHFILE *, struct fakecorridor *, const char *, const char *, int));
+E void FDECL(sfi_fe, (NHFILE *, struct fe *, const char *, const char *, int));
+E void FDECL(sfi_flag, (NHFILE *, struct flag *, const char *, const char *, int));
+E void FDECL(sfi_fruit, (NHFILE *, struct fruit *, const char *, const char *, int));
+E void FDECL(sfi_kinfo, (NHFILE *, struct kinfo *, const char *, const char *, int));
+E void FDECL(sfi_levelflags, (NHFILE *, struct levelflags *, const char *, const char *, int));
+E void FDECL(sfi_linfo, (NHFILE *, struct linfo *, const char *, const char *, int));
+E void FDECL(sfi_ls_t, (NHFILE *, struct ls_t *, const char *, const char *, int));
+E void FDECL(sfi_mapseen_feat, (NHFILE *, struct mapseen_feat *, const char *, const char *, int));
+E void FDECL(sfi_mapseen_flags, (NHFILE *, struct mapseen_flags *, const char *, const char *, int));
+E void FDECL(sfi_mapseen_rooms, (NHFILE *, struct mapseen_rooms *, const char *, const char *, int));
+E void FDECL(sfi_mapseen, (NHFILE *, struct mapseen *, const char *, const char *, int));
+E void FDECL(sfi_mextra, (NHFILE *, struct mextra *, const char *, const char *, int));
+E void FDECL(sfi_mkroom, (NHFILE *, struct mkroom *, const char *, const char *, int));
+E void FDECL(sfi_monst, (NHFILE *, struct monst *, const char *, const char *, int));
+E void FDECL(sfi_mvitals, (NHFILE *, struct mvitals *, const char *, const char *, int));
+E void FDECL(sfi_nhcoord, (NHFILE *, struct nhcoord *, const char *, const char *, int));
+E void FDECL(sfi_nhrect, (NHFILE *, struct nhrect *, const char *, const char *, int));
+E void FDECL(sfi_novel_tracking, (NHFILE *, struct novel_tracking *, const char *, const char *, int));
+E void FDECL(sfi_obj, (NHFILE *, struct obj *, const char *, const char *, int));
+E void FDECL(sfi_objclass, (NHFILE *, struct objclass *, const char *, const char *, int));
+E void FDECL(sfi_obj_split, (NHFILE *, struct obj_split *, const char *, const char *, int));
+E void FDECL(sfi_oextra, (NHFILE *, struct oextra *, const char *, const char *, int));
+E void FDECL(sfi_polearm_info, (NHFILE *, struct polearm_info *, const char *, const char *, int));
+E void FDECL(sfi_prop, (NHFILE *, struct prop *, const char *, const char *, int));
+E void FDECL(sfi_q_score, (NHFILE *, struct q_score *, const char *, const char *, int));
+E void FDECL(sfi_rm, (NHFILE *, struct rm *, const char *, const char *, int));
+E void FDECL(sfi_s_level, (NHFILE *, struct s_level *, const char *, const char *, int));
+E void FDECL(sfi_savefile_info, (NHFILE *, struct savefile_info *, const char *, const char *, int));
+E void FDECL(sfi_skills, (NHFILE *, struct skills *, const char *, const char *, int));
+E void FDECL(sfi_spell, (NHFILE *, struct spell *, const char *, const char *, int));
+E void FDECL(sfi_stairway, (NHFILE *, struct stairway *, const char *, const char *, int));
+E void FDECL(sfi_takeoff_info, (NHFILE *, struct takeoff_info *, const char *, const char *, int));
+E void FDECL(sfi_tin_info, (NHFILE *, struct tin_info *, const char *, const char *, int));
+E void FDECL(sfi_trap, (NHFILE *, struct trap *, const char *, const char *, int));
+E void FDECL(sfi_tribute_info, (NHFILE *, struct tribute_info *, const char *, const char *, int));
+E void FDECL(sfi_u_achieve, (NHFILE *, struct u_achieve *, const char *, const char *, int));
+E void FDECL(sfi_u_conduct, (NHFILE *, struct u_conduct *, const char *, const char *, int));
+E void FDECL(sfi_u_event, (NHFILE *, struct u_event *, const char *, const char *, int));
+E void FDECL(sfi_u_have, (NHFILE *, struct u_have *, const char *, const char *, int));
+E void FDECL(sfi_u_realtime, (NHFILE *, struct u_realtime *, const char *, const char *, int));
+E void FDECL(sfi_u_roleplay, (NHFILE *, struct u_roleplay *, const char *, const char *, int));
+E void FDECL(sfi_version_info, (NHFILE *, struct version_info *, const char *, const char *, int));
+E void FDECL(sfi_victual_info, (NHFILE *, struct victual_info *, const char *, const char *, int));
+E void FDECL(sfi_vlaunchinfo, (NHFILE *, union vlaunchinfo *, const char *, const char *, int));
+E void FDECL(sfi_vptrs, (NHFILE *, union vptrs *, const char *, const char *, int));
+E void FDECL(sfi_warntype_info, (NHFILE *, struct warntype_info *, const char *, const char *, int));
+E void FDECL(sfi_you, (NHFILE *, struct you *, const char *, const char *, int));
+#endif /* SFPROTO_H */
index 17bbadb85f871a2d0859e40377cee7347eb29dbd..f7bd0b4699eae242fc2ba571a8a4d5aa923d688d 100644 (file)
@@ -41,6 +41,10 @@ struct sysopt {
     char *greppath;
     int panictrace_gdb;
     int panictrace_libc;
+
+    /* save and bones format */
+    int saveformat[2];    /* primary and onetime conversion */
+    int bonesformat[2];   /* primary and onetime conversion */
 };
 
 extern struct sysopt sysopt;
index 25b60f73b46b60d7f323a2f43e17e0c48320e17c..657b9c3e7b6dc6f8787043d52deab83a2c28c889 100644 (file)
@@ -59,8 +59,7 @@ struct u_achieve {
     Bitfield(bell, 1);    /* touched Bell */
     Bitfield(book, 1);    /* touched Book */
     Bitfield(menorah, 1); /* touched Candelabrum */
-    Bitfield(enter_gehennom,
-             1);           /* entered Gehennom (or Valley) by any means */
+    Bitfield(enter_gehennom,1); /* entered Gehennom (or Valley) by any means */
     Bitfield(ascended, 1); /* not quite the same as u.uevent.ascended */
     Bitfield(mines_luckstone, 1); /* got a luckstone at end of mines */
     Bitfield(finish_sokoban, 1);  /* obtained the sokoban prize */
index 621f557383a5c14bf32878aff311adeaf2cbb016..03df78062120d24d956c5b60f5ca0597515463c0 100644 (file)
@@ -6,6 +6,8 @@
 #include "hack.h"
 #include "artifact.h"
 #include "artilist.h"
+#include "sfproto.h"
+
 
 /*
  * Note:  both artilist[] and artiexist[] have a dummy element #0,
@@ -76,20 +78,42 @@ init_artifacts()
 }
 
 void
-save_artifacts(fd)
-int fd;
+save_artifacts(nhfp)
+NHFILE *nhfp;
 {
-    bwrite(fd, (genericptr_t) g.artiexist, sizeof g.artiexist);
-    bwrite(fd, (genericptr_t) g.artidisco, sizeof g.artidisco);
+    if (nhfp->structlevel) {
+        bwrite(nhfp->fd, (genericptr_t) g.artiexist, sizeof g.artiexist);
+        bwrite(nhfp->fd, (genericptr_t) g.artidisco, sizeof g.artidisco);
+    }
+    if (nhfp->fieldlevel) {
+        int i;
+
+        for (i = 0; i < (1 + NROFARTIFACTS + 1); ++i)
+            sfo_boolean(nhfp, &g.artiexist[i], "artifacts", "g.artiexist", 1);
+
+        for (i = 0; i < NROFARTIFACTS; ++i)
+            sfo_xchar(nhfp, &g.artidisco[i], "artifacts", "g.artidisco", 1);
+    }
 }
 
 void
-restore_artifacts(fd)
-int fd;
+restore_artifacts(nhfp)
+NHFILE *nhfp;
 {
-    mread(fd, (genericptr_t) g.artiexist, sizeof g.artiexist);
-    mread(fd, (genericptr_t) g.artidisco, sizeof g.artidisco);
-    hack_artifacts(); /* redo non-saved special cases */
+    if (nhfp->structlevel) {
+        mread(nhfp->fd, (genericptr_t) g.artiexist, sizeof g.artiexist);
+        mread(nhfp->fd, (genericptr_t) g.artidisco, sizeof g.artidisco);
+    }
+    if (nhfp->fieldlevel) {
+        int i;
+
+        for (i = 0; i < (1 + NROFARTIFACTS + 1); ++i)
+            sfi_boolean(nhfp, &g.artiexist[i], "artifacts", "g.artiexist", 1);
+
+        for (i = 0; i < NROFARTIFACTS; ++i)
+            sfi_xchar(nhfp, &g.artidisco[i], "artifacts", "g.artidisco", 1);
+    }
+    hack_artifacts();  /* redo non-saved special cases */
 }
 
 const char *
index d1ad4750fca3a557111c6c1e2bc7a46aef358ba7..0d9e28b379dd89fe94f57fd0179cb2ab91c32cce 100644 (file)
@@ -5,6 +5,8 @@
 
 #include "hack.h"
 #include "lev.h"
+#include "sfproto.h"
+
 
 #ifdef MFLOPPY
 extern long bytes_counted;
@@ -338,7 +340,7 @@ int how;
 time_t when;
 struct obj *corpse;
 {
-    int fd, x, y;
+    int x, y;
     struct trap *ttmp;
     struct monst *mtmp;
     struct permonst *mptr;
@@ -346,13 +348,14 @@ struct obj *corpse;
     struct cemetery *newbones;
     char c, *bonesid;
     char whynot[BUFSZ];
+    NHFILE *nhfp;
 
     /* caller has already checked `can_make_bones()' */
 
     clear_bypasses();
-    fd = open_bonesfile(&u.uz, &bonesid);
-    if (fd >= 0) {
-        (void) nhclose(fd);
+    nhfp = open_bonesfile(&u.uz, &bonesid);
+    if (nhfp) {
+        close_nhfile(nhfp);
         if (wizard) {
             if (yn("Bones file already exists.  Replace it?") == 'y') {
                 if (delete_bonesfile(&u.uz))
@@ -500,8 +503,8 @@ struct obj *corpse;
     if (wizard)
         g.level.flags.wizard_bones = 1;
 
-    fd = create_bonesfile(&u.uz, &bonesid, whynot);
-    if (fd < 0) {
+    nhfp = create_bonesfile(&u.uz, &bonesid, whynot);
+    if (!nhfp) {
         if (wizard)
             pline1(whynot);
         /* bones file creation problems are silent to the player.
@@ -514,7 +517,10 @@ struct obj *corpse;
 
 #ifdef MFLOPPY /* check whether there is room */
     if (iflags.checkspace) {
-        savelev(fd, ledger_no(&u.uz), COUNT_SAVE);
+        int savemode = nhfp->mode;
+
+        nhfp->mode = COUNTING;
+        savelev(nhfp, ledger_no(&u.uz));
         /* savelev() initializes bytes_counted to 0, so it must come
          * first here even though it does not in the real save.  the
          * resulting extra bflush() at the end of savelev() may increase
@@ -525,31 +531,47 @@ struct obj *corpse;
          * this code would have to know the size of the version
          * information itself.
          */
-        store_version(fd);
-        store_savefileinfo(fd);
-        bwrite(fd, (genericptr_t) &c, sizeof c);
-        bwrite(fd, (genericptr_t) bonesid, (unsigned) c); /* DD.nnn */
-        savefruitchn(fd, COUNT_SAVE);
-        bflush(fd);
+        store_version(nhfp);
+        store_savefileinfo(nhfp);
+       if (nhfp->structlevel) {
+            bwrite(nhfp->fd, (genericptr_t) &c, sizeof c);
+            bwrite(nhfp->fd, (genericptr_t) bonesid, (unsigned) c); /* DD.nnn */
+        }
+        if (nhfp->fieldlevel) {
+            sfo_char(nhfp, &c, "bones", "bones_count", 1);
+            sfo_char(nhfp, bonesid, "bones", "bonesid", (int) c);
+        }
+        savefruitchn(nhfp);
+        if (nhfp->structlevel)
+            bflush(nhfp->fd);
         if (bytes_counted > freediskspace(bones)) { /* not enough room */
             if (wizard)
                 pline("Insufficient space to create bones file.");
-            (void) nhclose(fd);
+           close_nhfile(nhfp);
             cancel_bonesfile();
             return;
         }
         co_false(); /* make sure stuff before savelev() gets written */
+        nhfp->mode = savemode;
     }
 #endif /* MFLOPPY */
 
-    store_version(fd);
-    store_savefileinfo(fd);
-    bwrite(fd, (genericptr_t) &c, sizeof c);
-    bwrite(fd, (genericptr_t) bonesid, (unsigned) c); /* DD.nnn */
-    savefruitchn(fd, WRITE_SAVE | FREE_SAVE);
+    nhfp->mode = WRITING | FREEING;
+    store_version(nhfp);
+    store_savefileinfo(nhfp);
+    if (nhfp->structlevel) {
+        bwrite(nhfp->fd, (genericptr_t) &c, sizeof c);
+        bwrite(nhfp->fd, (genericptr_t) bonesid, (unsigned) c);        /* DD.nnn */
+        savefruitchn(nhfp);
+    }
+    if (nhfp->fieldlevel) {
+        sfo_char(nhfp, &c, "bones", "bones_count", 1);
+        sfo_char(nhfp, bonesid, "bones", "bonesid", (int) c);  /* DD.nnn */
+        savefruitchn(nhfp);
+    }
     update_mlstmv(); /* update monsters for eventual restoration */
-    savelev(fd, ledger_no(&u.uz), WRITE_SAVE | FREE_SAVE);
-    bclose(fd);
+    savelev(nhfp, ledger_no(&u.uz));
+    close_nhfile(nhfp);
     commit_bonesfile(&u.uz);
     compress_bonesfile();
 }
@@ -557,8 +579,8 @@ struct obj *corpse;
 int
 getbones()
 {
-    register int fd;
-    register int ok;
+    int ok, i;
+    NHFILE *nhfp = (NHFILE *) 0;
     char c, *bonesid, oldbonesid[40]; /* was [10]; more should be safer */
 
     if (discover) /* save bones files for real games */
@@ -572,11 +594,18 @@ getbones()
         return 0;
     if (no_bones_level(&u.uz))
         return 0;
-    fd = open_bonesfile(&u.uz, &bonesid);
-    if (fd < 0)
+
+    nhfp = open_bonesfile(&u.uz, &bonesid);
+    if (!nhfp)
+        return 0;
+    if (nhfp && nhfp->structlevel && nhfp->fd < 0)
+        return 0;
+    if (nhfp && nhfp->fieldlevel) {
+        if (nhfp->style.deflt && !nhfp->fpdef)
         return 0;
+    }
 
-    if (validate(fd, g.bones) != 0) {
+    if (validate(nhfp, g.bones) != 0) {
         if (!wizard)
             pline("Discarding unuseable bones; no need to panic...");
         ok = FALSE;
@@ -584,13 +613,20 @@ getbones()
         ok = TRUE;
         if (wizard) {
             if (yn("Get bones?") == 'n') {
-                (void) nhclose(fd);
+                close_nhfile(nhfp);
                 compress_bonesfile();
                 return 0;
             }
         }
-        mread(fd, (genericptr_t) &c, sizeof c); /* length incl. '\0' */
-        mread(fd, (genericptr_t) oldbonesid, (unsigned) c); /* DD.nnn */
+        if (nhfp->structlevel) {
+            mread(nhfp->fd, (genericptr_t) &c, sizeof c); /* length incl. '\0' */
+            mread(nhfp->fd, (genericptr_t) oldbonesid, (unsigned) c); /* DD.nnn */
+        }
+        if (nhfp->fieldlevel) {
+            sfi_char(nhfp, &c, "bones", "bones_count", 1); /* length incl. '\0' */
+            for (i = 0; i < (int) c; ++i)
+                sfi_char(nhfp, &oldbonesid[i], "bones", "bonesid", 1);
+       }
         if (strcmp(bonesid, oldbonesid) != 0
             /* from 3.3.0 through 3.6.0, bones in the quest branch stored
                a bogus bonesid in the file; 3.6.1 fixed that, but for
@@ -612,7 +648,7 @@ getbones()
         } else {
             register struct monst *mtmp;
 
-            getlev(fd, 0, 0, TRUE);
+            getlev(nhfp, 0, 0, TRUE);
 
             /* Note that getlev() now keeps tabs on unique
              * monsters such as demon lords, and tracks the
@@ -638,7 +674,7 @@ getbones()
             resetobjs(g.level.buriedobjlist, TRUE);
         }
     }
-    (void) nhclose(fd);
+    close_nhfile(nhfp);
     sanitize_engravings();
     u.uroleplay.numbones++;
 
index 09b9e86983b2ec9e739a1f20c8df79b80c90ca77..6cfd4275aae24d4488c0f00a22d5075b6d1520ce 100644 (file)
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -789,6 +789,8 @@ wiz_identify(VOID_ARGS)
 STATIC_PTR int
 wiz_makemap(VOID_ARGS)
 {
+    NHFILE tmpnhfp;
+
     if (wizard) {
         struct monst *mtmp;
         boolean was_in_W_tower = In_W_tower(u.ux, u.uy, &u.uz);
@@ -835,7 +837,9 @@ wiz_makemap(VOID_ARGS)
         keepdogs(TRUE); /* (pets-only; normally we'd be using 'FALSE' here) */
 
         /* discard current level; "saving" is used to release dynamic data */
-        savelev(-1, ledger_no(&u.uz), FREE_SAVE);
+        zero_nhfile(&tmpnhfp);  /* also sets fd to -1 as desired */
+        tmpnhfp.mode = FREEING;
+        savelev(&tmpnhfp, ledger_no(&u.uz));
         /* create a new level; various things like bestowing a guardian
            angel on Astral or setting off alarm on Ft.Ludios are handled
            by goto_level(do.c) so won't occur for replacement levels */
index 1c9f9ad344fc830aeef15f19238b989d63c336ff..b294828f68d6fc50dccf07ce2b8220d2877b9a80 100644 (file)
--- a/src/do.c
+++ b/src/do.c
@@ -15,7 +15,7 @@ STATIC_DCL void FDECL(dosinkring, (struct obj *));
 STATIC_PTR int FDECL(drop, (struct obj *));
 STATIC_PTR int NDECL(wipeoff);
 STATIC_DCL int FDECL(menu_drop, (int));
-STATIC_DCL int NDECL(currentlevel_rewrite);
+STATIC_DCL NHFILE *NDECL(currentlevel_rewrite);
 STATIC_DCL void NDECL(final_level);
 /* static boolean FDECL(badspot, (XCHAR_P,XCHAR_P)); */
 
@@ -1114,18 +1114,21 @@ doup()
 }
 
 /* check that we can write out the current level */
-STATIC_OVL int
+STATIC_OVL NHFILE *
 currentlevel_rewrite()
 {
-    register int fd;
+    NHFILE *nhfp;
     char whynot[BUFSZ];
+#ifdef MFLOPPY
+    int savemode;
+#endif
 
     /* since level change might be a bit slow, flush any buffered screen
      *  output (like "you fall through a trap door") */
     mark_synch();
 
-    fd = create_levelfile(ledger_no(&u.uz), whynot);
-    if (fd < 0) {
+    nhfp = create_levelfile(ledger_no(&u.uz), whynot);
+    if (!nhfp) {
         /*
          * This is not quite impossible: e.g., we may have
          * exceeded our quota. If that is the case then we
@@ -1134,35 +1137,39 @@ currentlevel_rewrite()
          * writable.
          */
         pline1(whynot);
-        return -1;
+        return (NHFILE *) 0;
     }
 
 #ifdef MFLOPPY
-    if (!savelev(fd, ledger_no(&u.uz), COUNT_SAVE)) {
-        (void) nhclose(fd);
+    savemode = nhfp->mode;
+    nhfp->mode = COUNTING;
+    if (!savelev(nhfp, ledger_no(&u.uz))) {
+        close_nhfile(nhfp);
         delete_levelfile(ledger_no(&u.uz));
         pline("NetHack is out of disk space for making levels!");
         You("can save, quit, or continue playing.");
         return -1;
     }
+    nhfp->mode = savemode;
 #endif
-    return fd;
+    return nhfp;
 }
 
 #ifdef INSURANCE
 void
 save_currentstate()
 {
-    int fd;
+    NHFILE *nhfp;
 
     if (flags.ins_chkpt) {
         /* write out just-attained level, with pets and everything */
-        fd = currentlevel_rewrite();
-        if (fd < 0)
+        nhfp = currentlevel_rewrite();
+        if (!nhfp)
             return;
-        bufon(fd);
-        savelev(fd, ledger_no(&u.uz), WRITE_SAVE);
-        bclose(fd);
+        bufon(nhfp->fd);
+        nhfp->mode = WRITING;
+        savelev(nhfp,ledger_no(&u.uz));
+        close_nhfile(nhfp);
     }
 
     /* write out non-level state */
@@ -1226,7 +1233,8 @@ goto_level(newlevel, at_stairs, falling, portal)
 d_level *newlevel;
 boolean at_stairs, falling, portal;
 {
-    int fd, l_idx;
+    int l_idx, save_mode;
+    NHFILE *nhfp;
     xchar new_ledger;
     boolean cant_go_back, great_effort,
             up = (depth(newlevel) < depth(&u.uz)),
@@ -1307,8 +1315,8 @@ boolean at_stairs, falling, portal;
     if (u.utrap && u.utraptype == TT_BURIEDBALL)
         buried_ball_to_punishment(); /* (before we save/leave old level) */
 
-    fd = currentlevel_rewrite();
-    if (fd < 0)
+    nhfp = currentlevel_rewrite();
+    if (!nhfp)
         return;
 
     /* discard context which applies to the level we're leaving;
@@ -1354,10 +1362,12 @@ boolean at_stairs, falling, portal;
     cant_go_back = (newdungeon && In_endgame(newlevel));
     if (!cant_go_back) {
         update_mlstmv(); /* current monsters are becoming inactive */
-        bufon(fd);       /* use buffered output */
+        bufon(nhfp->fd);       /* use buffered output */
     }
-    savelev(fd, ledger_no(&u.uz),
-            cant_go_back ? FREE_SAVE : (WRITE_SAVE | FREE_SAVE));
+    save_mode = nhfp->mode;
+    nhfp->mode = cant_go_back ? FREEING : (WRITING | FREEING);
+    savelev(nhfp, ledger_no(&u.uz));
+    nhfp->mode = save_mode;
     /* air bubbles and clouds are saved in game-state rather than with the
        level they're used on; in normal play, you can't leave and return
        to any endgame level--bubbles aren't needed once you move to the
@@ -1366,9 +1376,15 @@ boolean at_stairs, falling, portal;
        aren't saved with the level and restored upon return (new ones are
        created instead), we need to discard them to avoid a memory leak;
        so bubbles are now discarded as we leave the level they're used on */
-    if (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz))
-        save_waterlevel(-1, FREE_SAVE);
-    bclose(fd);
+    if (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz)) {
+        NHFILE tmpnhfp;
+
+        zero_nhfile(&tmpnhfp);
+        tmpnhfp.fd = -1;
+        tmpnhfp.mode = FREEING;
+        save_waterlevel(&tmpnhfp);
+    }
+    close_nhfile(nhfp);
     if (cant_go_back) {
         /* discard unreachable levels; keep #0 */
         for (l_idx = maxledgerno(); l_idx > 0; --l_idx)
@@ -1418,21 +1434,26 @@ boolean at_stairs, falling, portal;
         new = TRUE; /* made the level */
     } else {
         /* returning to previously visited level; reload it */
-        fd = open_levelfile(new_ledger, whynot);
-        if (tricked_fileremoved(fd, whynot)) {
+        nhfp = open_levelfile(new_ledger, whynot);
+        if (tricked_fileremoved(nhfp, whynot)) {
             /* we'll reach here if running in wizard mode */
             error("Cannot continue this game.");
         }
         reseed_random(rn2);
         reseed_random(rn2_on_display_rng);
         minit(); /* ZEROCOMP */
-        getlev(fd, g.hackpid, new_ledger, FALSE);
+        getlev(nhfp, g.hackpid, new_ledger, FALSE);
         /* when in wizard mode, it is possible to leave from and return to
            any level in the endgame; above, we discarded bubble/cloud info
            when leaving Plane of Water or Air so recreate some now */
-        if (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz))
-            restore_waterlevel(-1);
-        (void) nhclose(fd);
+        if (Is_waterlevel(&u.uz) || Is_airlevel(&u.uz)) {
+            NHFILE tmpnhfp;
+
+            zero_nhfile(&tmpnhfp);
+            tmpnhfp.fd = -1;
+            restore_waterlevel(&tmpnhfp);
+        }
+        close_nhfile(nhfp);
         oinit(); /* reassign level dependent obj probabilities */
     }
     reglyph_darkroom();
index 2701731efe05b7363853e1ad2c489a9b8bdf31df..95c4a6cdb4977807fed43038a756f718cea9ac38 100644 (file)
@@ -7,6 +7,8 @@
 #include "dgn_file.h"
 #include "dlb.h"
 #include "lev.h"
+#include "sfproto.h"
+
 
 #define DUNGEON_FILE "dungeon"
 
@@ -56,8 +58,9 @@ STATIC_DCL const char *FDECL(br_string, (int));
 STATIC_DCL char FDECL(chr_u_on_lvl, (d_level *));
 STATIC_DCL void FDECL(print_branch, (winid, int, int, int, BOOLEAN_P,
                                      struct lchoice *));
-STATIC_DCL mapseen *FDECL(load_mapseen, (int));
-STATIC_DCL void FDECL(save_mapseen, (int, mapseen *));
+/* SAVE2018 */
+STATIC_DCL mapseen *FDECL(load_mapseen, (NHFILE *));
+STATIC_DCL void FDECL(save_mapseen, (NHFILE *, mapseen *));
 STATIC_DCL mapseen *FDECL(find_mapseen, (d_level *));
 STATIC_DCL mapseen *FDECL(find_mapseen_by_str, (const char *));
 STATIC_DCL void FDECL(print_mapseen, (winid, mapseen *, int, int, BOOLEAN_P));
@@ -129,41 +132,68 @@ dumpit()
 
 /* Save the dungeon structures. */
 void
-save_dungeon(fd, perform_write, free_data)
-int fd;
+save_dungeon(nhfp, perform_write, free_data)
+NHFILE *nhfp;
 boolean perform_write, free_data;
 {
+    int i, count;
     branch *curr, *next;
     mapseen *curr_ms, *next_ms;
-    int count;
 
     if (perform_write) {
-        bwrite(fd, (genericptr_t) &g.n_dgns, sizeof g.n_dgns);
-        bwrite(fd, (genericptr_t) g.dungeons,
-               sizeof(dungeon) * (unsigned) g.n_dgns);
-        bwrite(fd, (genericptr_t) &g.dungeon_topology, sizeof g.dungeon_topology);
-        bwrite(fd, (genericptr_t) g.tune, sizeof tune);
-
+        if(nhfp->structlevel) {
+            bwrite(nhfp->fd, (genericptr_t) &g.n_dgns, sizeof g.n_dgns);
+            bwrite(nhfp->fd, (genericptr_t) g.dungeons,
+                   sizeof(dungeon) * (unsigned) g.n_dgns);
+            bwrite(nhfp->fd, (genericptr_t) &g.dungeon_topology, sizeof g.dungeon_topology);
+            bwrite(nhfp->fd, (genericptr_t) g.tune, sizeof tune);
+        }
+        if (nhfp->fieldlevel) {
+            sfo_int(nhfp, &g.n_dgns, "dungeon", "dungeon_count", 1);
+            for (i = 0; i < g.n_dgns; ++i)
+                sfo_dungeon(nhfp, &g.dungeons[i], "dungeon", "dungeon", 1);
+            sfo_dgn_topology(nhfp, &g.dungeon_topology, "dungeon", "g.dungeon_topology", 1);
+            for (i = 0; i < sizeof tune; ++i)
+                sfo_char(nhfp, &g.tune[i], "dungeon", "tune", 1);
+        }
         for (count = 0, curr = g.branches; curr; curr = curr->next)
             count++;
-        bwrite(fd, (genericptr_t) &count, sizeof(count));
-
-        for (curr = g.branches; curr; curr = curr->next)
-            bwrite(fd, (genericptr_t) curr, sizeof(branch));
-
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &count, sizeof(count));
+        if (nhfp->fieldlevel)
+            sfo_int(nhfp, &count, "dungeon", "branch_count", 1);
+
+        for (curr = g.branches; curr; curr = curr->next) {
+          if (nhfp->structlevel)
+              bwrite(nhfp->fd, (genericptr_t) curr, sizeof(branch));
+          if (nhfp->fieldlevel)
+              sfo_branch(nhfp, curr, "dungeon", "branch", 1);
+        }
         count = maxledgerno();
-        bwrite(fd, (genericptr_t) &count, sizeof count);
-        bwrite(fd, (genericptr_t) g.level_info,
-               (unsigned) count * sizeof(struct linfo));
-        bwrite(fd, (genericptr_t) &g.inv_pos, sizeof g.inv_pos);
-
+        if (nhfp->structlevel) { 
+            bwrite(nhfp->fd, (genericptr_t) &count, sizeof count);
+            bwrite(nhfp->fd, (genericptr_t) g.level_info,
+                   (unsigned) count * sizeof(struct linfo));
+            bwrite(nhfp->fd, (genericptr_t) &g.inv_pos, sizeof g.inv_pos);
+        }
+        if (nhfp->fieldlevel) {
+            sfo_int(nhfp, &count, "dungeon", "level_info_count", 1);
+            for (i = 0; i < count; ++i)
+                sfo_linfo(nhfp, &g.level_info[i], "dungeon", "g.level_info", 1);
+            sfo_nhcoord(nhfp, &g.inv_pos, "dungeon", "g.inv_pos", 1);
+        }
         for (count = 0, curr_ms = g.mapseenchn; curr_ms;
              curr_ms = curr_ms->next)
             count++;
-        bwrite(fd, (genericptr_t) &count, sizeof(count));
 
-        for (curr_ms = g.mapseenchn; curr_ms; curr_ms = curr_ms->next)
-            save_mapseen(fd, curr_ms);
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &count, sizeof(count));
+        if (nhfp->fieldlevel)
+            sfo_int(nhfp, &count, "dungeon", "mapseen_count", 1);
+
+        for (curr_ms = g.mapseenchn; curr_ms; curr_ms = curr_ms->next) {
+            save_mapseen(nhfp, curr_ms);
+        }    
     }
 
     if (free_data) {
@@ -177,7 +207,7 @@ boolean perform_write, free_data;
             if (curr_ms->custom)
                 free((genericptr_t) curr_ms->custom);
             if (curr_ms->final_resting_place)
-                savecemetery(fd, FREE_SAVE, &curr_ms->final_resting_place);
+                savecemetery(nhfp, &curr_ms->final_resting_place);
             free((genericptr_t) curr_ms);
         }
         g.mapseenchn = 0;
@@ -186,24 +216,40 @@ boolean perform_write, free_data;
 
 /* Restore the dungeon structures. */
 void
-restore_dungeon(fd)
-int fd;
+restore_dungeon(nhfp)
+NHFILE *nhfp;
 {
     branch *curr, *last;
     int count, i;
     mapseen *curr_ms, *last_ms;
 
-    mread(fd, (genericptr_t) &g.n_dgns, sizeof(g.n_dgns));
-    mread(fd, (genericptr_t) g.dungeons, sizeof(dungeon) * (unsigned) g.n_dgns);
-    mread(fd, (genericptr_t) &g.dungeon_topology, sizeof g.dungeon_topology);
-    mread(fd, (genericptr_t) g.tune, sizeof tune);
-
+    if (nhfp->structlevel) {
+        mread(nhfp->fd, (genericptr_t) &g.n_dgns, sizeof(g.n_dgns));
+        mread(nhfp->fd, (genericptr_t) g.dungeons, sizeof(dungeon) * (unsigned) g.n_dgns);
+        mread(nhfp->fd, (genericptr_t) &g.dungeon_topology, sizeof g.dungeon_topology);
+        mread(nhfp->fd, (genericptr_t) g.tune, sizeof tune);
+    }
+    if (nhfp->fieldlevel) {
+        sfi_int(nhfp, &g.n_dgns, "dungeon", "dungeon_count", 1);
+        for (i = 0; i < g.n_dgns; ++i)
+            sfi_dungeon(nhfp, &g.dungeons[i], "dungeon", "dungeon", 1);
+        sfi_dgn_topology(nhfp, &g.dungeon_topology, "dungeon", "g.dungeon_topology", 1);
+        for (i = 0; i < sizeof tune; ++i)
+            sfi_char(nhfp, &g.tune[i], "dungeon", "tune", 1);
+    }
     last = g.branches = (branch *) 0;
 
-    mread(fd, (genericptr_t) &count, sizeof(count));
+    if (nhfp->structlevel)
+        mread(nhfp->fd, (genericptr_t) &count, sizeof(count));
+    if (nhfp->fieldlevel)
+        sfi_int(nhfp, &count, "dungeon", "branch_count", 1);
+
     for (i = 0; i < count; i++) {
         curr = (branch *) alloc(sizeof(branch));
-        mread(fd, (genericptr_t) curr, sizeof(branch));
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) curr, sizeof(branch));
+        if (nhfp->fieldlevel)
+            sfi_branch(nhfp, curr, "dungeon", "branch", 1);
         curr->next = (branch *) 0;
         if (last)
             last->next = curr;
@@ -212,18 +258,33 @@ int fd;
         last = curr;
     }
 
-    mread(fd, (genericptr_t) &count, sizeof(count));
+    if (nhfp->structlevel)
+        mread(nhfp->fd, (genericptr_t) &count, sizeof(count));
+    if (nhfp->fieldlevel)
+        sfi_int(nhfp, &count, "dungeon", "level_info_count", 1);
+
     if (count >= MAXLINFO)
         panic("level information count larger (%d) than allocated size",
               count);
-    mread(fd, (genericptr_t) g.level_info,
-          (unsigned) count * sizeof(struct linfo));
-    mread(fd, (genericptr_t) &g.inv_pos, sizeof g.inv_pos);
+    if (nhfp->structlevel)
+        mread(nhfp->fd, (genericptr_t) g.level_info,
+              (unsigned) count * sizeof(struct linfo));
+    if (nhfp->fieldlevel)
+        for (i = 0; i < count; ++i)
+            sfi_linfo(nhfp, &g.level_info[i], "dungeon", "g.level_info", 1);
+
+    if (nhfp->structlevel) {
+        mread(nhfp->fd, (genericptr_t) &g.inv_pos, sizeof g.inv_pos);
+        mread(nhfp->fd, (genericptr_t) &count, sizeof(count));
+    }
+    if (nhfp->fieldlevel) {
+        sfi_nhcoord(nhfp, &g.inv_pos, "dungeon", "inv_pos", 1);
+        sfi_int(nhfp, &count, "dungeon", "mapseen_count", 1);
+    }
 
-    mread(fd, (genericptr_t) &count, sizeof(count));
     last_ms = (mapseen *) 0;
     for (i = 0; i < count; i++) {
-        curr_ms = load_mapseen(fd);
+        curr_ms = load_mapseen(nhfp);
         curr_ms->next = (mapseen *) 0;
         if (last_ms)
             last_ms->next = curr_ms;
@@ -752,7 +813,7 @@ init_dungeons()
      */
     if (iflags.window_inited)
         clear_nhwindow(WIN_MAP);
-    if (!check_version(&vers_info, DUNGEON_FILE, TRUE))
+    if (!check_version(&vers_info, DUNGEON_FILE, TRUE, UTD_CHECKSIZES))
         panic("Dungeon description not valid.");
 
     /*
@@ -2187,58 +2248,106 @@ int ledger_num;
 }
 
 STATIC_OVL void
-save_mapseen(fd, mptr)
-int fd;
+save_mapseen(nhfp, mptr)
+NHFILE *nhfp;
 mapseen *mptr;
 {
     branch *curr;
-    int brindx;
+    int i, brindx;
 
     for (brindx = 0, curr = g.branches; curr; curr = curr->next, ++brindx)
         if (curr == mptr->br)
             break;
-    bwrite(fd, (genericptr_t) &brindx, sizeof brindx);
-
-    bwrite(fd, (genericptr_t) &mptr->lev, sizeof mptr->lev);
-    bwrite(fd, (genericptr_t) &mptr->feat, sizeof mptr->feat);
-    bwrite(fd, (genericptr_t) &mptr->flags, sizeof mptr->flags);
-    bwrite(fd, (genericptr_t) &mptr->custom_lth, sizeof mptr->custom_lth);
-    if (mptr->custom_lth)
-        bwrite(fd, (genericptr_t) mptr->custom, mptr->custom_lth);
-    bwrite(fd, (genericptr_t) mptr->msrooms, sizeof mptr->msrooms);
-    savecemetery(fd, WRITE_SAVE, &mptr->final_resting_place);
+    if (nhfp->structlevel)
+        bwrite(nhfp->fd, (genericptr_t) &brindx, sizeof brindx);
+    if (nhfp->fieldlevel)
+        sfo_int(nhfp, &brindx, "mapseen", "branch_index", 1);
+
+    if (nhfp->structlevel) {
+        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);
+    }
+    if (nhfp->fieldlevel) {
+        sfo_d_level(nhfp, &mptr->lev, "mapseen", "d_level", 1);
+        sfo_mapseen_feat(nhfp, &mptr->feat, "mapseen", "feat", 1);
+        sfo_mapseen_flags(nhfp, &mptr->flags, "mapseen", "flags", 1);
+        sfo_unsigned(nhfp, &mptr->custom_lth, "mapseen", "custom_lth", 1);
+    }
+
+    if (mptr->custom_lth) {
+        if (nhfp->structlevel) {
+            bwrite(nhfp->fd, (genericptr_t) mptr->custom, mptr->custom_lth);
+        }
+        if (nhfp->fieldlevel) {
+            for (i = 0; i < (int) mptr->custom_lth; ++i)
+                sfo_char(nhfp, &mptr->custom[i], "mapseen", "custom", 1);
+        }
+    }
+    if (nhfp->structlevel) {
+        bwrite(nhfp->fd, (genericptr_t) &mptr->msrooms, sizeof mptr->msrooms);
+    }
+    if (nhfp->fieldlevel) {
+        for (i = 0; i < ((MAXNROFROOMS + 1) * 2); ++i)
+            sfo_mapseen_rooms(nhfp, &mptr->msrooms[i], "mapseen", "msrooms", 1);
+    }
+    savecemetery(nhfp, &mptr->final_resting_place);
 }
 
 STATIC_OVL mapseen *
-load_mapseen(fd)
-int fd;
+load_mapseen(nhfp)
+NHFILE *nhfp;
 {
-    int branchnum, brindx;
+    int i, branchnum, brindx;
     mapseen *load;
     branch *curr;
 
     load = (mapseen *) alloc(sizeof *load);
 
-    mread(fd, (genericptr_t) &branchnum, sizeof branchnum);
+    if (nhfp->structlevel)
+        mread(nhfp->fd, (genericptr_t) &branchnum, sizeof branchnum);
+    if (nhfp->fieldlevel)
+        sfi_int(nhfp, &branchnum, "mapseen", "branch_index", 1);
     for (brindx = 0, curr = g.branches; curr; curr = curr->next, ++brindx)
         if (brindx == branchnum)
             break;
     load->br = curr;
 
-    mread(fd, (genericptr_t) &load->lev, sizeof load->lev);
-    mread(fd, (genericptr_t) &load->feat, sizeof load->feat);
-    mread(fd, (genericptr_t) &load->flags, sizeof load->flags);
-    mread(fd, (genericptr_t) &load->custom_lth, sizeof load->custom_lth);
+    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);
+    }
+    if (nhfp->fieldlevel) {
+        sfi_d_level(nhfp, &load->lev, "mapseen", "d_level", 1);
+        sfi_mapseen_feat(nhfp, &load->feat, "mapseen", "feat", 1);
+        sfi_mapseen_flags(nhfp, &load->flags, "mapseen", "flags", 1);
+        sfi_unsigned(nhfp, &load->custom_lth, "mapseen", "custom_lth", 1);
+    }
+
     if (load->custom_lth) {
         /* length doesn't include terminator (which isn't saved & restored) */
         load->custom = (char *) alloc(load->custom_lth + 1);
-        mread(fd, (genericptr_t) load->custom, load->custom_lth);
+        if (nhfp->structlevel) {
+            mread(nhfp->fd, (genericptr_t) load->custom, load->custom_lth);
+        }
+        if (nhfp->fieldlevel) {
+            for (i = 0; i < (int) load->custom_lth; ++i)
+                sfi_char(nhfp, &load->custom[i], "mapseen", "custom", 1);
+        }
         load->custom[load->custom_lth] = '\0';
     } else
         load->custom = 0;
-    mread(fd, (genericptr_t) load->msrooms, sizeof load->msrooms);
-    restcemetery(fd, &load->final_resting_place);
-
+    if (nhfp->structlevel) {
+        mread(nhfp->fd, (genericptr_t) &load->msrooms, sizeof load->msrooms);
+    }
+    if (nhfp->fieldlevel) {
+        for (i = 0; i < ((MAXNROFROOMS + 1) * 2); ++i)
+            sfi_mapseen_rooms(nhfp, &load->msrooms[i], "mapseen", "msrooms", 1);
+    }
+    restcemetery(nhfp, &load->final_resting_place);
     return load;
 }
 
index 059ba74ce5fc877ce235303879485857649afefe..43699f3686da604b670c48d9d6217150ae5838b0 100644 (file)
--- a/src/end.c
+++ b/src/end.c
@@ -15,6 +15,8 @@
 #include <limits.h>
 #endif
 #include "dlb.h"
+#include "sfproto.h"
+
 
 /* add b to long a, convert wraparound to max value */
 #define nowrap_add(a, b) (a = ((a + b) < 0 ? LONG_MAX : (a + b)))
@@ -2131,18 +2133,20 @@ struct kinfo *kptr;
 }
 
 void
-save_killers(fd, mode)
-int fd;
-int mode;
+save_killers(nhfp)
+NHFILE *nhfp;
 {
     struct kinfo *kptr;
 
-    if (perform_bwrite(mode)) {
+    if (perform_bwrite(nhfp)) {
         for (kptr = &g.killer; kptr != (struct kinfo *) 0; kptr = kptr->next) {
-            bwrite(fd, (genericptr_t) kptr, sizeof (struct kinfo));
+            if (nhfp->structlevel)
+               bwrite(nhfp->fd, (genericptr_t)kptr, sizeof(struct kinfo));
+            if (nhfp->fieldlevel)
+               sfo_kinfo(nhfp, kptr, "killers", "kinfo", 1);
         }
     }
-    if (release_data(mode)) {
+    if (release_data(nhfp)) {
         while (g.killer.next) {
             kptr = g.killer.next->next;
             free((genericptr_t) g.killer.next);
@@ -2152,13 +2156,16 @@ int mode;
 }
 
 void
-restore_killers(fd)
-int fd;
+restore_killers(nhfp)
+NHFILE *nhfp;
 {
     struct kinfo *kptr;
 
     for (kptr = &g.killer; kptr != (struct kinfo *) 0; kptr = kptr->next) {
-        mread(fd, (genericptr_t) kptr, sizeof (struct kinfo));
+        if (nhfp->structlevel)
+           mread(nhfp->fd, (genericptr_t)kptr, sizeof(struct kinfo));
+        if (nhfp->fieldlevel)
+            sfi_kinfo(nhfp, kptr, "killers", "kinfo", 1);
         if (kptr->next) {
             kptr->next = (struct kinfo *) alloc(sizeof (struct kinfo));
         }
index 460414a7d8076cbc5f1c89409785759b8167b668..6826198162b695df99d3f547f1217f435b354e3c 100644 (file)
@@ -5,6 +5,8 @@
 
 #include "hack.h"
 #include "lev.h"
+#include "sfproto.h"
+
 
 STATIC_VAR NEARDATA struct engr *head_engr;
 STATIC_DCL const char *NDECL(blengr);
@@ -1173,48 +1175,69 @@ sanitize_engravings()
 }
 
 void
-save_engravings(fd, mode)
-int fd, mode;
+save_engravings(nhfp)
+NHFILE *nhfp;
 {
     struct engr *ep, *ep2;
     unsigned no_more_engr = 0;
 
     for (ep = head_engr; ep; ep = ep2) {
         ep2 = ep->nxt_engr;
-        if (ep->engr_lth && ep->engr_txt[0] && perform_bwrite(mode)) {
-            bwrite(fd, (genericptr_t) &ep->engr_lth, sizeof ep->engr_lth);
-            bwrite(fd, (genericptr_t) ep, sizeof (struct engr) + ep->engr_lth);
+        if (ep->engr_lth && ep->engr_txt[0] && perform_bwrite(nhfp)) {
+            if (nhfp->structlevel) {
+                bwrite(nhfp->fd, (genericptr_t)&(ep->engr_lth), sizeof(ep->engr_lth));
+                bwrite(nhfp->fd, (genericptr_t)ep, sizeof(struct engr) + ep->engr_lth);
+            }
+            if (nhfp->fieldlevel) {
+                sfo_unsigned(nhfp, &(ep->engr_lth), "engravings", "engr_lth", 1);
+                sfo_engr(nhfp, ep, "engravings", "engr", 1);
+                sfo_str(nhfp, ep->engr_txt, "engravings", "engr_txt", ep->engr_lth);
+            }
         }
-        if (release_data(mode))
+        if (release_data(nhfp))
             dealloc_engr(ep);
     }
-    if (perform_bwrite(mode))
-        bwrite(fd, (genericptr_t) &no_more_engr, sizeof no_more_engr);
-    if (release_data(mode))
+    if (perform_bwrite(nhfp)) {
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t)&no_more_engr, sizeof no_more_engr);
+        if (nhfp->fieldlevel)
+           sfo_unsigned(nhfp, &no_more_engr, "engravings", "engr_lth", 1);
+    }
+    if (release_data(nhfp))
         head_engr = 0;
 }
 
 void
-rest_engravings(fd)
-int fd;
+rest_engravings(nhfp)
+NHFILE *nhfp;
 {
     struct engr *ep;
     unsigned lth;
 
     head_engr = 0;
     while (1) {
-        mread(fd, (genericptr_t) &lth, sizeof lth);
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) &lth, sizeof(unsigned));
+        if (nhfp->fieldlevel)
+            sfi_unsigned(nhfp, &lth, "engravings", "engr_lth", 1);
+
         if (lth == 0)
             return;
         ep = newengr(lth);
-        mread(fd, (genericptr_t) ep, sizeof (struct engr) + lth);
+        if (nhfp->structlevel) {
+            mread(nhfp->fd, (genericptr_t) ep, sizeof(struct engr) + lth);
+        }
+        if (nhfp->fieldlevel) {
+            sfi_engr(nhfp, ep, "engravings", "engr", 1);
+            ep->engr_txt = (char *) (ep + 1);
+            sfi_str(nhfp, ep->engr_txt, "engravings", "engr_txt", lth);
+        }
         ep->nxt_engr = head_engr;
         head_engr = ep;
-        ep->engr_txt = (char *) (ep + 1); /* Andreas Bormann */
-        /* Mark as finished for bones levels -- no problem for
+        ep->engr_txt = (char *) (ep + 1);      /* Andreas Bormann */
+        /* mark as finished for bones levels -- no problem for
          * normal levels as the player must have finished engraving
-         * to be able to move again.
-         */
+         * to be able to move again */
         ep->engr_time = g.moves;
     }
 }
index 7b2e8af7cccd96f4ea9e4f94d7ac1d0a185f693b..ba3128924f709ef073e8003e93a6a541da8af823 100644 (file)
@@ -7,6 +7,10 @@
 
 #include "hack.h"
 #include "dlb.h"
+#include <ctype.h>
+#include "sfproto.h"
+#include "sfprocs.h"
+#include "lev.h"
 
 #ifdef TTY_GRAPHICS
 #include "wintty.h" /* more() */
@@ -63,7 +67,7 @@ const
 #endif
 
 #ifdef PREFIXES_IN_USE
-#define FQN_NUMBUF 4
+#define FQN_NUMBUF 8
 static char fqn_filename_buffer[FQN_NUMBUF][FQN_MAX_FILENAME];
 #endif
 
@@ -160,13 +164,15 @@ STATIC_DCL void NDECL(free_config_sections);
 STATIC_DCL char *FDECL(choose_random_part, (char *, CHAR_P));
 STATIC_DCL boolean FDECL(is_config_section, (const char *));
 STATIC_DCL boolean FDECL(handle_config_section, (char *));
+STATIC_DCL void FDECL(parseformat, (int *, char *));
+
 #ifdef SELF_RECOVER
 STATIC_DCL boolean FDECL(copy_bytes, (int, int));
 #endif
 #ifdef HOLD_LOCKFILE_OPEN
 STATIC_DCL int FDECL(open_levelfile_exclusively, (const char *, int, int));
 #endif
-
+STATIC_DCL NHFILE *FDECL(viable_nhfile, (NHFILE *));
 
 /*
  * fname_encode()
@@ -383,6 +389,150 @@ int prefix;
     return fp;
 }
 
+/* ----------  EXTERNAL FILE SUPPORT ----------- */
+
+/* determine byte order */
+const int bei = 1;
+#define IS_BIGENDIAN() ( (*(char*)&bei) == 0 )
+
+void
+zero_nhfile(nhfp)
+NHFILE *nhfp;
+{
+    if (nhfp) {
+        nhfp->fd = -1;
+        nhfp->mode = COUNTING;
+        nhfp->structlevel = FALSE;
+        nhfp->fieldlevel = FALSE;
+        nhfp->addinfo = FALSE;
+        nhfp->bendian = IS_BIGENDIAN();
+        nhfp->fpdef = (FILE *)0;
+        nhfp->fplog = (FILE *)0;
+        nhfp->fpdebug = (FILE *)0;
+        nhfp->count = 0;
+        nhfp->eof = FALSE;
+        nhfp->fnidx = 0;
+    }
+}
+
+#if 0
+E void FDECL(sfi_init, (struct sf_procs *));
+E void FDECL(sfo_init, (struct sf_procs *));
+E struct sf_procs sfoprocs, sfiprocs;
+#ifdef SYSCF
+    if (sysopt.saveformat[0] > 1) {
+        /* initialize the function pointers for fieldlevel saves */
+        if (sysopt.saveformat[0] == lendian) {
+            sfi_init(&lendian_sfi_procs);
+            sfo_init(&lendian_sfo_procs);
+        }
+        if (sysopt.saveformat[0] == ascii) {
+            sfi_init(&ascii_sfi_procs);
+            sfo_init(&ascii_sfo_procs);
+        }
+    }
+#endif
+#endif
+
+NHFILE *
+new_nhfile()
+{
+    NHFILE *nhfp = (NHFILE *)alloc(sizeof(NHFILE));
+
+    zero_nhfile(nhfp);
+    return nhfp;
+}
+
+void
+free_nhfile(nhfp)
+NHFILE *nhfp;
+{
+    if (nhfp) {
+        zero_nhfile(nhfp);
+        free(nhfp);
+    }
+}
+
+void
+close_nhfile(nhfp)
+NHFILE *nhfp;
+{
+    if (nhfp) {
+        if (nhfp->structlevel && nhfp->fd != -1)
+            (void) nhclose(nhfp->fd), nhfp->fd = -1;
+        if (nhfp->fieldlevel) {
+            if (nhfp->fpdef) {
+                (void) fclose(nhfp->fpdef);
+                nhfp->fpdef = (FILE *) 0;
+            }
+       }
+        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);
+    }
+}
+
+void
+rewind_nhfile(nhfp)
+NHFILE *nhfp;
+{
+    if (nhfp->structlevel) {
+#ifdef BSD
+        (void) lseek(nhfp->fd, 0L, 0);
+#else
+        (void) lseek(nhfp->fd, (off_t) 0, 0);
+#endif
+    }
+    if (nhfp->fieldlevel) {
+        if (nhfp->fpdef) {
+            rewind(nhfp->fpdef);
+            nhfp->count = 0L;
+            nhfp->eof = FALSE;
+       }
+    }
+}
+
+static
+NHFILE *
+viable_nhfile(nhfp)
+NHFILE *nhfp;
+{
+    /* perform some sanity checks before returning
+       the pointer to the nethack file descriptor */
+    if (nhfp) {
+         /* check for no open file at all,
+          * not a structlevel legacy file,
+          * nor a fieldlevel file.
+          */
+         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;
+        }
+    }
+    return nhfp;
+}
+
 /* ----------  BEGIN LEVEL FILE HANDLING ----------- */
 
 #ifdef MFLOPPY
@@ -432,54 +582,66 @@ int lev;
     return;
 }
 
-int
+NHFILE *
 create_levelfile(lev, errbuf)
 int lev;
 char errbuf[];
 {
-    int fd;
     const char *fq_lock;
+    NHFILE *nhfp = (NHFILE *) 0;
 
     if (errbuf)
         *errbuf = '\0';
     set_levelfile_name(g.lock, lev);
     fq_lock = fqname(g.lock, LEVELPREFIX, 0);
 
+    nhfp = new_nhfile();
+    if (nhfp) {
+        nhfp->ftype = NHF_LEVELFILE;
+        nhfp->mode = WRITING;
+        nhfp->structlevel = TRUE;       /* do set this TRUE for levelfiles */
+        nhfp->fieldlevel = FALSE;       /* don't set this TRUE for levelfiles */
+        nhfp->addinfo = FALSE;
+        nhfp->style.deflt = FALSE;
+        nhfp->style.binary = TRUE;
+        nhfp->fd = -1;
+        nhfp->fpdef = (FILE *) 0;
 #if defined(MICRO) || defined(WIN32)
-/* Use O_TRUNC to force the file to be shortened if it already
- * exists and is currently longer.
- */
+        /* Use O_TRUNC to force the file to be shortened if it already
        * exists and is currently longer.
        */
 #ifdef HOLD_LOCKFILE_OPEN
-    if (lev == 0)
-        fd = open_levelfile_exclusively(
-            fq_lock, lev, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY);
-    else
+        if (lev == 0)
+            nhfp->fd = open_levelfile_exclusively(
+                fq_lock, lev, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY);
+        else
 #endif
-        fd = open(fq_lock, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, FCMASK);
+            nhfp->fd = open(fq_lock, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, FCMASK);
 #else
 #ifdef MAC
-    fd = maccreat(fq_lock, LEVL_TYPE);
+        nhfp->fd = maccreat(fq_lock, LEVL_TYPE);
 #else
-    fd = creat(fq_lock, FCMASK);
+        nhfp->fd = creat(fq_lock, FCMASK);
 #endif
 #endif /* MICRO || WIN32 */
 
-    if (fd >= 0)
-        g.level_info[lev].flags |= LFILE_EXISTS;
-    else if (errbuf) /* failure explanation */
-        Sprintf(errbuf, "Cannot create file \"%s\" for level %d (errno %d).",
-                g.lock, lev, errno);
-
-    return fd;
+        if (nhfp->fd >= 0)
+            g.level_info[lev].flags |= LFILE_EXISTS;
+        else if (errbuf) /* failure explanation */
+            Sprintf(errbuf, "Cannot create file \"%s\" for level %d (errno %d).",
+                    g.lock, lev, errno);
+    }
+    nhfp = viable_nhfile(nhfp);
+    return nhfp;
 }
 
-int
+NHFILE *
 open_levelfile(lev, errbuf)
 int lev;
 char errbuf[];
 {
-    int fd;
     const char *fq_lock;
+    NHFILE *nhfp = (NHFILE *) 0;
 
     if (errbuf)
         *errbuf = '\0';
@@ -490,25 +652,39 @@ char errbuf[];
     if (g.level_info[lev].where != ACTIVE)
         swapin_file(lev);
 #endif
+    nhfp = new_nhfile();
+    if (nhfp) {
+        nhfp->mode = READING;
+        nhfp->structlevel = TRUE;       /* do set this TRUE for levelfiles */
+        nhfp->fieldlevel = FALSE;       /* do not set this TRUE for levelfiles */
+        nhfp->addinfo = FALSE;
+        nhfp->style.deflt = FALSE;
+        nhfp->style.binary = TRUE;
+        nhfp->ftype = NHF_LEVELFILE;
+        nhfp->fd = -1;
+        nhfp->fpdef = (FILE *) 0;
+    }
+    if (nhfp && nhfp->structlevel) {
 #ifdef MAC
-    fd = macopen(fq_lock, O_RDONLY | O_BINARY, LEVL_TYPE);
+        nhfp->fd = macopen(fq_lock, O_RDONLY | O_BINARY, LEVL_TYPE);
 #else
 #ifdef HOLD_LOCKFILE_OPEN
-    if (lev == 0)
-        fd = open_levelfile_exclusively(fq_lock, lev, O_RDONLY | O_BINARY);
-    else
+        if (lev == 0)
+            nhfp->fd = open_levelfile_exclusively(fq_lock, lev, O_RDONLY | O_BINARY);
+        else
 #endif
-        fd = open(fq_lock, O_RDONLY | O_BINARY, 0);
+            nhfp->fd = open(fq_lock, O_RDONLY | O_BINARY, 0);
 #endif
 
-    /* for failure, return an explanation that our caller can use;
-       settle for `lock' instead of `fq_lock' because the latter
-       might end up being too big for nethack's BUFSZ */
-    if (fd < 0 && errbuf)
-        Sprintf(errbuf, "Cannot open file \"%s\" for level %d (errno %d).",
-                g.lock, lev, errno);
-
-    return fd;
+        /* for failure, return an explanation that our caller can use;
+           settle for `lock' instead of `fq_lock' because the latter
+           might end up being too big for nethack's BUFSZ */
+        if (nhfp->fd < 0 && errbuf)
+            Sprintf(errbuf, "Cannot open file \"%s\" for level %d (errno %d).",
+                    g.lock, lev, errno);
+    }
+    nhfp = viable_nhfile(nhfp);
+    return nhfp;
 }
 
 void
@@ -631,9 +807,16 @@ int
 nhclose(fd)
 int fd;
 {
+    NHFILE *nhfp, tnhfp;
+
     if (g.lftrack.fd == fd) {
         really_close(); /* close it, but reopen it to hold it */
-        fd = open_levelfile(0, (char *) 0);
+        nhfp = open_levelfile(0, (char *) 0);
+        if (nhfp) {
+            tnhfp = *nhfp;
+            free(nhfp);
+            g.lftrack.fd = tnhfp.fd;
+        }
         g.lftrack.nethack_thinks_it_is_open = FALSE;
         return 0;
     }
@@ -661,6 +844,7 @@ set_bonesfile_name(file, lev)
 char *file;
 d_level *lev;
 {
+    int idx = 0;
     s_level *sptr;
     char *dptr;
 
@@ -701,6 +885,11 @@ d_level *lev;
         Sprintf(eos(dptr), ".%c", sptr->boneid);
     else
         Sprintf(eos(dptr), ".%d", lev->dlevel);
+#ifdef SYSCF
+    idx = sysopt.bonesformat[0];
+    if (idx > historical && idx <= ascii)
+        Strcat(dptr, sfoprocs[idx].ext);
+#endif
 #ifdef VMS
     Strcat(dptr, ";1");
 #endif
@@ -728,14 +917,15 @@ set_bonestemp_name()
     return g.lock;
 }
 
-int
+NHFILE *
 create_bonesfile(lev, bonesid, errbuf)
 d_level *lev;
 char **bonesid;
 char errbuf[];
 {
     const char *file;
-    int fd;
+    NHFILE *nhfp = (NHFILE *) 0;
+    int failed = 0;
 
     if (errbuf)
         *errbuf = '\0';
@@ -743,22 +933,52 @@ char errbuf[];
     file = set_bonestemp_name();
     file = fqname(file, BONESPREFIX, 0);
 
+    nhfp = new_nhfile();
+    if (nhfp) {
+        nhfp->structlevel = TRUE;
+        nhfp->fieldlevel = FALSE;
+        nhfp->ftype = NHF_BONESFILE;
+        nhfp->mode = WRITING;
+#ifdef SYSCF
+        if (sysopt.bonesformat[0] > historical &&
+            sysopt.bonesformat[0] <= ascii) {
+            nhfp->structlevel = FALSE;
+            nhfp->fieldlevel = TRUE;
+            nhfp->addinfo = TRUE;
+            nhfp->style.deflt = TRUE;
+            nhfp->style.binary = (sysopt.bonesformat[0] != ascii);
+            nhfp->fnidx = sysopt.bonesformat[0];
+            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;
+            }
+        }
+#endif      /* SYSCF */
+        if (nhfp->structlevel) {
 #if defined(MICRO) || defined(WIN32)
-    /* Use O_TRUNC to force the file to be shortened if it already
-     * exists and is currently longer.
-     */
-    fd = open(file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, FCMASK);
+            /* Use O_TRUNC to force the file to be shortened if it already
+             * exists and is currently longer.
+             */
+            nhfp->fd = open(file, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, FCMASK);
 #else
 #ifdef MAC
-    fd = maccreat(file, BONE_TYPE);
+            nhfp->fd = maccreat(file, BONE_TYPE);
 #else
-    fd = creat(file, FCMASK);
+            nhfp->fd = creat(file, FCMASK);
 #endif
 #endif
-    if (fd < 0 && errbuf) /* failure explanation */
-        Sprintf(errbuf, "Cannot create bones \"%s\", id %s (errno %d).", g.lock,
-                *bonesid, errno);
-
+            if (nhfp->fd < 0)
+                failed = errno;
+       }
+        if (failed && errbuf)  /* failure explanation */
+            Sprintf(errbuf, "Cannot create bones \"%s\", id %s (errno %d).",
+                    g.lock, *bonesid, errno);
+    }
 #if defined(VMS) && !defined(SECURE)
     /*
        Re-protect bones file with world:read+write+execute+delete access.
@@ -771,7 +991,8 @@ char errbuf[];
     (void) chmod(file, FCMASK | 007); /* allow other users full access */
 #endif /* VMS && !SECURE */
 
-    return fd;
+    nhfp = viable_nhfile(nhfp);
+    return nhfp;
 }
 
 #ifdef MFLOPPY
@@ -814,23 +1035,57 @@ d_level *lev;
         pline("couldn't rename %s to %s.", tempname, fq_bones);
 }
 
-int
+NHFILE *
 open_bonesfile(lev, bonesid)
 d_level *lev;
 char **bonesid;
 {
     const char *fq_bones;
-    int fd;
+    int failed = 0;
+    NHFILE *nhfp = (NHFILE *) 0;
 
     *bonesid = set_bonesfile_name(g.bones, lev);
     fq_bones = fqname(g.bones, BONESPREFIX, 0);
-    nh_uncompress(fq_bones); /* no effect if nonexistent */
+    nh_uncompress(fq_bones);  /* no effect if nonexistent */
+
+    nhfp = new_nhfile();
+    if (nhfp) {
+        nhfp->structlevel = TRUE;
+        nhfp->fieldlevel = FALSE;
+        nhfp->ftype = NHF_BONESFILE;
+        nhfp->mode = READING;
+#ifdef SYSCF
+        if (sysopt.bonesformat[0] > historical &&
+            sysopt.bonesformat[0] <= ascii) {
+            nhfp->structlevel = FALSE;
+            nhfp->fieldlevel = TRUE;
+            nhfp->addinfo = TRUE;
+            nhfp->style.deflt = TRUE;
+            nhfp->style.binary = (sysopt.bonesformat[0] != ascii);
+            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
+            } else {
+                failed = errno;
+            }
+        }
+#endif  /* SYSCF */
+        if (nhfp->structlevel) {
 #ifdef MAC
-    fd = macopen(fq_bones, O_RDONLY | O_BINARY, BONE_TYPE);
+            nhfp->fd = macopen(fq_bones, O_RDONLY | O_BINARY, BONE_TYPE);
 #else
-    fd = open(fq_bones, O_RDONLY | O_BINARY, 0);
+            nhfp->fd = open(fq_bones, O_RDONLY | O_BINARY, 0);
 #endif
-    return fd;
+            if (nhfp->fd < 0)
+                failed = errno;
+        }
+    }
+    nhfp = viable_nhfile(nhfp);
+    return nhfp;
 }
 
 int
@@ -859,8 +1114,15 @@ void
 set_savefile_name(regularize_it)
 boolean regularize_it;
 {
+    int idx = 0;
+
 #ifdef VMS
     Sprintf(g.SAVEF, "[.save]%d%s", getuid(), g.plname);
+#ifdef SYSCF
+    idx = sysopt.saveformat[0];
+    if (idx > historical && idx <= ascii)
+        Strcat(g.SAVEF, sfoprocs[idx].ext);
+#endif
     if (regularize_it)
         regularize(g.SAVEF + 7);
     Strcat(g.SAVEF, ";1");
@@ -877,6 +1139,11 @@ boolean regularize_it;
         (void) strncat(g.SAVEF, g.plname, FILENAME - i - 4);
 #else
         (void) strncat(g.SAVEF, g.plname, 8);
+#endif
+#ifdef SYSCF
+        idx = sysopt.saveformat[0];
+        if (idx > historical && idx <= ascii)
+            Strcat(g.SAVEF, sfoprocs[idx].ext);
 #endif
         if (regularize_it)
             regularize(g.SAVEF + i);
@@ -888,18 +1155,24 @@ boolean regularize_it;
         static const char okchars[] =
             "*ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-.";
         const char *legal = okchars;
-        char fnamebuf[BUFSZ], encodedfnamebuf[BUFSZ];
 
-        /* Obtain the name of the logged on user and incorporate
-         * it into the name. */
-        Sprintf(fnamebuf, "%s-%s", get_username(0), g.plname);
         if (regularize_it)
             ++legal; /* skip '*' wildcard character */
-        (void) fname_encode(legal, '%', fnamebuf, encodedfnamebuf, BUFSZ);
-        Sprintf(g.SAVEF, "%s%s", encodedfnamebuf, SAVE_EXTENSION);
+        (void) fname_encode(legal, '%', g.plname, g.SAVEF, sizeof g.SAVEF);
+        Strcat(g.SAVEF, SAVE_EXTENSION);
+#ifdef SYSCF
+        idx = sysopt.saveformat[0];
+        if (idx > historical && idx <= ascii)
+            Strcat(g.SAVEF, sfoprocs[idx].ext);
+#endif
     }
 #else  /* not VMS or MICRO or WIN32 */
     Sprintf(g.SAVEF, "save/%d%s", (int) getuid(), g.plname);
+#ifdef SYSCF
+    idx = sysopt.saveformat[0];
+    if (idx > historical && idx <= ascii)
+        Strcat(g.SAVEF, sfoprocs[idx].ext);
+#endif
     if (regularize_it)
         regularize(g.SAVEF + 5); /* avoid . or / in name */
 #endif /* WIN32 */
@@ -909,10 +1182,13 @@ boolean regularize_it;
 
 #ifdef INSURANCE
 void
-save_savefile_name(fd)
-int fd;
+save_savefile_name(nhfp)
+NHFILE *nhfp;
 {
-    (void) write(fd, (genericptr_t) g.SAVEF, sizeof(g.SAVEF));
+    if (nhfp->structlevel)
+        (void) write(nhfp->fd, (genericptr_t) g.SAVEF, sizeof(g.SAVEF));
+    if (nhfp->fieldlevel)
+        sfo_str(nhfp, g.SAVEF, "savefile_name", "g.savef", sizeof(g.SAVEF)); 
 }
 #endif
 
@@ -940,21 +1216,54 @@ set_error_savefile()
 #endif
 
 /* create save file, overwriting one if it already exists */
-int
+NHFILE *
 create_savefile()
 {
+    int failed = 0;
     const char *fq_save;
-    int fd;
+    NHFILE *nhfp = (NHFILE *) 0;
 
     fq_save = fqname(g.SAVEF, SAVEPREFIX, 0);
+    nhfp = new_nhfile();
+    if (nhfp) {
+        nhfp->structlevel = TRUE;
+        nhfp->fieldlevel = FALSE;
+        nhfp->ftype = NHF_SAVEFILE;
+#ifdef SYSCF
+        if (sysopt.saveformat[0] > historical &&
+            sysopt.saveformat[0] <= ascii) {
+            nhfp->mode = WRITING;
+            nhfp->structlevel = FALSE;
+            nhfp->fieldlevel = TRUE;
+            nhfp->addinfo = TRUE;
+            nhfp->style.deflt = TRUE;
+            nhfp->style.binary = (sysopt.saveformat[0] != ascii);
+            nhfp->fnidx = sysopt.saveformat[0];
+            nhfp->fd = -1;
+            nhfp->fpdef = fopen(fq_save, nhfp->style.binary ? WRBMODE : WRTMODE);
+            if (nhfp->fpdef) {
+#ifdef SAVEFILE_DEBUGGING
+                nhfp->fpdebug = fopen("create_savefile-debug.log", "a");
+#endif
+            } else {
+                failed = errno;
+            }
+       }
+#endif /* SYSCF */
+        if (nhfp->structlevel) {
 #if defined(MICRO) || defined(WIN32)
-    fd = open(fq_save, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK);
+            nhfp->fd = open(fq_save, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK);
 #else
 #ifdef MAC
-    fd = maccreat(fq_save, SAVE_TYPE);
+            nhfp->fd = maccreat(fq_save, SAVE_TYPE);
 #else
-    fd = creat(fq_save, FCMASK);
+            nhfp->fd = creat(fq_save, FCMASK);
 #endif
+#endif /* MICRO || WIN32 */
+            if (nhfp->fd < 0)
+                failed = errno;
+       }
+    }
 #if defined(VMS) && !defined(SECURE)
     /*
        Make sure the save file is owned by the current process.  That's
@@ -965,25 +1274,58 @@ create_savefile()
     (void) chown(fq_save, getuid(), getgid());
 #define getuid() vms_getuid()
 #endif /* VMS && !SECURE */
-#endif /* MICRO */
 
-    return fd;
+    nhfp = viable_nhfile(nhfp);
+    return nhfp;
 }
 
 /* open savefile for reading */
-int
+NHFILE *
 open_savefile()
 {
+    int failed = 0;
     const char *fq_save;
-    int fd;
+    NHFILE *nhfp = (NHFILE *) 0;
 
     fq_save = fqname(g.SAVEF, SAVEPREFIX, 0);
+    nhfp = new_nhfile();
+    if (nhfp) {
+        nhfp->structlevel = TRUE;
+        nhfp->fieldlevel = FALSE;
+        nhfp->ftype = NHF_SAVEFILE;
+#ifdef SYSCF
+        if (sysopt.saveformat[0] > historical &&
+            sysopt.saveformat[0] <= ascii) {
+            nhfp->mode = READING;
+            nhfp->structlevel = FALSE;
+            nhfp->fieldlevel = TRUE;
+            nhfp->addinfo = TRUE;
+            nhfp->style.deflt = TRUE;
+            nhfp->style.binary = (sysopt.saveformat[0] < ascii);
+            nhfp->fnidx = sysopt.saveformat[0];
+            nhfp->fd = -1;
+            nhfp->fpdef = fopen(fq_save, nhfp->style.binary ? RDBMODE : RDTMODE);
+            if (nhfp->fpdef) {
+#ifdef SAVEFILE_DEBUGGING
+                nhfp->fpdebug = fopen("open_savefile-debug.log", "a");
+#endif
+            } else {
+                failed = errno;
+            }
+        }
+#endif /* SYSCF */
+        if (nhfp->structlevel) {
 #ifdef MAC
-    fd = macopen(fq_save, O_RDONLY | O_BINARY, SAVE_TYPE);
+            nhfp->fd = macopen(fq_save, O_RDONLY | O_BINARY, SAVE_TYPE);
 #else
-    fd = open(fq_save, O_RDONLY | O_BINARY, 0);
+            nhfp->fd = open(fq_save, O_RDONLY | O_BINARY, 0);
 #endif
-    return fd;
+            if (nhfp->fd < 0)
+                failed = errno;
+        }
+    }
+    nhfp = viable_nhfile(nhfp);
+    return nhfp;
 }
 
 /* delete savefile */
@@ -995,11 +1337,11 @@ delete_savefile()
 }
 
 /* try to open up a save file and prepare to restore it */
-int
+NHFILE *
 restore_saved_game()
 {
     const char *fq_save;
-    int fd;
+    NHFILE *nhfp = (NHFILE *) 0;
 
     reset_restpref();
     set_savefile_name(TRUE);
@@ -1010,14 +1352,18 @@ restore_saved_game()
     fq_save = fqname(g.SAVEF, SAVEPREFIX, 0);
 
     nh_uncompress(fq_save);
-    if ((fd = open_savefile()) < 0)
-        return fd;
-
-    if (validate(fd, fq_save) != 0) {
-        (void) nhclose(fd), fd = -1;
-        (void) delete_savefile();
+    if ((nhfp = open_savefile()) != 0) {
+        if (nhfp && nhfp->fieldlevel && nhfp->fplog)
+            (void) fprintf(nhfp->fplog, "# just opened\n");
+        if (nhfp->fieldlevel && nhfp->addinfo)
+            sfi_addinfo(nhfp, "NetHack", "start", "savefile", 0);
+        if (validate(nhfp, fq_save) != 0) {
+            close_nhfile(nhfp);
+            nhfp = (NHFILE *)0;
+            (void) delete_savefile();
+        }
     }
-    return fd;
+    return nhfp;
 }
 
 #if defined(SELECTSAVED)
@@ -1025,7 +1371,7 @@ char *
 plname_from_file(filename)
 const char *filename;
 {
-    int fd;
+    NHFILE *nhfp = (NHFILE *) 0;
     char *result = 0;
 
     Strcpy(g.SAVEF, filename);
@@ -1033,13 +1379,14 @@ const char *filename;
     g.SAVEF[strlen(g.SAVEF) - strlen(COMPRESS_EXTENSION)] = '\0';
 #endif
     nh_uncompress(g.SAVEF);
-    if ((fd = open_savefile()) >= 0) {
-        if (validate(fd, filename) == 0) {
+    if ((nhfp = open_savefile()) != 0) {
+        if (validate(nhfp, filename) == 0) {
             char tplname[PL_NSIZ];
-            get_plname_from_file(fd, tplname);
+
+            get_plname_from_file(nhfp, tplname);
             result = dupstr(tplname);
         }
-        (void) nhclose(fd);
+        close_nhfile(nhfp);
     }
     nh_compress(g.SAVEF);
 
@@ -2483,6 +2830,13 @@ char *origbuf;
         if (sysopt.greppath)
             free((genericptr_t) sysopt.greppath);
         sysopt.greppath = dupstr(bufp);
+    /* SYSCF SAVE and BONES format options */
+    } else if (src == SET_IN_SYS
+               && match_varname(buf, "SAVEFORMAT", 10)) {
+        parseformat(sysopt.saveformat, bufp);
+    } else if (src == SET_IN_SYS
+               && match_varname(buf, "BONESFORMAT", 11)) {
+        parseformat(sysopt.bonesformat, bufp);
 #endif /* SYSCF */
 
     } else if (match_varname(buf, "BOULDER", 3)) {
@@ -3341,6 +3695,41 @@ int which_set;
     }
 }
 
+void
+parseformat(arr, str)
+int *arr;
+char *str;
+{
+    const char *legal[] = {"historical", "lendian", "ascii"};
+    int i, kwi = 0, words = 0;
+    char *p = str, *keywords[2];
+
+    while (*p) {
+        while (*p && isspace((uchar) *p)) {
+            *p = '\0';
+            p++;
+       }
+        if (*p) {
+            words++;
+            if (kwi < 2)
+                keywords[kwi++] = p;
+        }
+        while (*p && !isspace((uchar) *p))
+            p++;
+    }
+    if (!words) {
+        impossible("missing format list");
+        return;
+    }
+    while (--kwi >= 0)
+        if (kwi < 2) {
+            for (i = 0; i < SIZE(legal); ++i) {
+               if (!strcmpi(keywords[kwi], legal[i]))
+                   arr[kwi] = i + 1;
+           }
+        }
+}
+
 /* ----------  END CONFIG FILE HANDLING ----------- */
 
 /* ----------  BEGIN SCOREBOARD CREATION ----------- */
@@ -3531,7 +3920,7 @@ const char *reason;   /* explanation */
 boolean
 recover_savefile()
 {
-    int gfd, lfd, sfd;
+    NHFILE *gnhfp, *lnhfp, *snhfp;
     int lev, savelev, hpid, pltmpsiz;
     xchar levc;
     struct version_info version_data;
@@ -3551,36 +3940,37 @@ recover_savefile()
      *  player name
      *  and game state
      */
-    gfd = open_levelfile(0, errbuf);
-    if (gfd < 0) {
+
+    gnhfp = open_levelfile(0, errbuf);
+    if (!gnhfp) {
         raw_printf("%s\n", errbuf);
         return FALSE;
     }
-    if (read(gfd, (genericptr_t) &hpid, sizeof hpid) != sizeof hpid) {
+    if (read(gnhfp->fd, (genericptr_t) &hpid, sizeof hpid) != sizeof hpid) {
         raw_printf("\n%s\n%s\n",
             "Checkpoint data incompletely written or subsequently clobbered.",
                    "Recovery impossible.");
-        (void) nhclose(gfd);
+        close_nhfile(gnhfp);
         return FALSE;
     }
-    if (read(gfd, (genericptr_t) &savelev, sizeof(savelev))
+    if (read(gnhfp->fd, (genericptr_t) &savelev, sizeof(savelev))
         != sizeof(savelev)) {
         raw_printf(
          "\nCheckpointing was not in effect for %s -- recovery impossible.\n",
                    g.lock);
-        (void) nhclose(gfd);
+        close_nhfile(gnhfp);
         return FALSE;
     }
-    if ((read(gfd, (genericptr_t) savename, sizeof savename)
+    if ((read(gnhfp->fd, (genericptr_t) savename, sizeof savename)
          != sizeof savename)
-        || (read(gfd, (genericptr_t) &version_data, sizeof version_data)
+        || (read(gnhfp->fd, (genericptr_t) &version_data, sizeof version_data)
             != sizeof version_data)
-        || (read(gfd, (genericptr_t) &sfi, sizeof sfi) != sizeof sfi)
-        || (read(gfd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz)
+        || (read(gnhfp->fd, (genericptr_t) &sfi, sizeof sfi) != sizeof sfi)
+        || (read(gnhfp->fd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz)
             != sizeof pltmpsiz) || (pltmpsiz > PL_NSIZ)
-        || (read(gfd, (genericptr_t) &tmpplbuf, pltmpsiz) != pltmpsiz)) {
+        || (read(gnhfp->fd, (genericptr_t) &tmpplbuf, pltmpsiz) != pltmpsiz)) {
         raw_printf("\nError reading %s -- can't recover.\n", g.lock);
-        (void) nhclose(gfd);
+        close_nhfile(gnhfp);
         return FALSE;
     }
 
@@ -3593,80 +3983,80 @@ recover_savefile()
      *  other levels
      */
     set_savefile_name(TRUE);
-    sfd = create_savefile();
-    if (sfd < 0) {
+    snhfp = create_savefile();
+    if (!snhfp) {
         raw_printf("\nCannot recover savefile %s.\n", g.SAVEF);
-        (void) nhclose(gfd);
+        close_nhfile(gnhfp);
         return FALSE;
     }
 
-    lfd = open_levelfile(savelev, errbuf);
-    if (lfd < 0) {
+    lnhfp = open_levelfile(savelev, errbuf);
+    if (!lnhfp) {
         raw_printf("\n%s\n", errbuf);
-        (void) nhclose(gfd);
-        (void) nhclose(sfd);
+        close_nhfile(gnhfp);
+        close_nhfile(snhfp);
         delete_savefile();
         return FALSE;
     }
 
-    if (write(sfd, (genericptr_t) &version_data, sizeof version_data)
+    if (write(snhfp->fd, (genericptr_t) &version_data, sizeof version_data)
         != sizeof version_data) {
         raw_printf("\nError writing %s; recovery failed.", g.SAVEF);
-        (void) nhclose(gfd);
-        (void) nhclose(sfd);
-        (void) nhclose(lfd);
+        close_nhfile(gnhfp);
+        close_nhfile(snhfp);
+        close_nhfile(lnhfp);
         delete_savefile();
         return FALSE;
     }
 
-    if (write(sfd, (genericptr_t) &sfi, sizeof sfi) != sizeof sfi) {
+    if (write(snhfp->fd, (genericptr_t) &sfi, sizeof sfi) != sizeof sfi) {
         raw_printf("\nError writing %s; recovery failed (savefile_info).\n",
                    g.SAVEF);
-        (void) nhclose(gfd);
-        (void) nhclose(sfd);
-        (void) nhclose(lfd);
+        close_nhfile(gnhfp);
+        close_nhfile(snhfp);
+        close_nhfile(lnhfp);
         delete_savefile();
         return FALSE;
     }
 
-    if (write(sfd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz)
+    if (write(snhfp->fd, (genericptr_t) &pltmpsiz, sizeof pltmpsiz)
         != sizeof pltmpsiz) {
         raw_printf("Error writing %s; recovery failed (player name size).\n",
                    g.SAVEF);
-        (void) nhclose(gfd);
-        (void) nhclose(sfd);
-        (void) nhclose(lfd);
+        close_nhfile(gnhfp);
+        close_nhfile(snhfp);
+        close_nhfile(lnhfp);
         delete_savefile();
         return FALSE;
     }
 
-    if (write(sfd, (genericptr_t) &tmpplbuf, pltmpsiz) != pltmpsiz) {
+    if (write(snhfp->fd, (genericptr_t) &tmpplbuf, pltmpsiz) != pltmpsiz) {
         raw_printf("Error writing %s; recovery failed (player name).\n",
                    g.SAVEF);
-        (void) nhclose(gfd);
-        (void) nhclose(sfd);
-        (void) nhclose(lfd);
+        close_nhfile(gnhfp);
+        close_nhfile(snhfp);
+        close_nhfile(lnhfp);
         delete_savefile();
         return FALSE;
     }
 
-    if (!copy_bytes(lfd, sfd)) {
-        (void) nhclose(gfd);
-        (void) nhclose(sfd);
-        (void) nhclose(lfd);
+    if (!copy_bytes(lnhfp->fd, snhfp->fd)) {
+        close_nhfile(gnhfp);
+        close_nhfile(snhfp);
+        close_nhfile(lnhfp);
         delete_savefile();
         return FALSE;
     }
-    (void) nhclose(lfd);
+    close_nhfile(lnhfp);
     processed[savelev] = 1;
 
-    if (!copy_bytes(gfd, sfd)) {
-        (void) nhclose(gfd);
-        (void) nhclose(sfd);
+    if (!copy_bytes(gnhfp->fd, snhfp->fd)) {
+        close_nhfile(gnhfp);
+        close_nhfile(snhfp);
         delete_savefile();
         return FALSE;
     }
-    (void) nhclose(gfd);
+    close_nhfile(gnhfp);
     processed[0] = 1;
 
     for (lev = 1; lev < 256; lev++) {
@@ -3674,23 +4064,23 @@ recover_savefile()
          * maximum level number (for the endlevel) must be < 256
          */
         if (lev != savelev) {
-            lfd = open_levelfile(lev, (char *) 0);
-            if (lfd >= 0) {
+            lnhfp = open_levelfile(lev, (char *) 0);
+            if (lnhfp) {
                 /* any or all of these may not exist */
                 levc = (xchar) lev;
-                write(sfd, (genericptr_t) &levc, sizeof(levc));
-                if (!copy_bytes(lfd, sfd)) {
-                    (void) nhclose(lfd);
-                    (void) nhclose(sfd);
+                write(snhfp->fd, (genericptr_t) &levc, sizeof(levc));
+                if (!copy_bytes(lnhfp->fd, snhfp->fd)) {
+                    close_nhfile(lnhfp);
+                    close_nhfile(snhfp);
                     delete_savefile();
                     return FALSE;
                 }
-                (void) nhclose(lfd);
+                close_nhfile(lnhfp);
                 processed[lev] = 1;
             }
         }
     }
-    (void) nhclose(sfd);
+    close_nhfile(snhfp);
 
 #ifdef HOLD_LOCKFILE_OPEN
     really_close();
index ab0e619f45fd3e8df4bf151e5d7e0cb3627ca7d2..f4c8dcd60636383826457349fe3fde1dd327c933 100644 (file)
@@ -4,6 +4,8 @@
 
 #include "hack.h"
 #include "lev.h" /* for checking save modes */
+#include "sfproto.h"
+
 
 /*
  * Mobile light sources.
 #define LSF_SHOW 0x1        /* display the light source */
 #define LSF_NEEDS_FIXUP 0x2 /* need oid fixup */
 
-STATIC_DCL void FDECL(write_ls, (int, light_source *));
-STATIC_DCL int FDECL(maybe_write_ls, (int, int, BOOLEAN_P));
+/* SAVE2018 */
+STATIC_DCL void FDECL(write_ls, (NHFILE *, light_source *));
+STATIC_DCL int FDECL(maybe_write_ls, (NHFILE *, int, BOOLEAN_P));
 
 /* imported from vision.c, for small circles */
 extern char circle_data[];
 extern char circle_start[];
 
+
 /* Create a new light source.  */
 void
 new_light_source(x, y, range, type, id)
-xchar x, y;
-int range, type;
-anything *id;
+    xchar x, y;
+    int range, type;
+    anything *id;
 {
     light_source *ls;
 
     if (range > MAX_RADIUS || range < 1) {
-        impossible("new_light_source:  illegal range %d", range);
-        return;
+       impossible("new_light_source:  illegal range %d", range);
+       return;
     }
 
     ls = (light_source *) alloc(sizeof *ls);
@@ -311,22 +315,28 @@ unsigned fmflags;
 
 /* Save all light sources of the given range. */
 void
-save_light_sources(fd, mode, range)
-int fd, mode, range;
+save_light_sources(nhfp, range)
+NHFILE *nhfp;
+int range;
 {
     int count, actual, is_global;
     light_source **prev, *curr;
 
-    if (perform_bwrite(mode)) {
-        count = maybe_write_ls(fd, range, FALSE);
-        bwrite(fd, (genericptr_t) &count, sizeof count);
-        actual = maybe_write_ls(fd, range, TRUE);
+    if (perform_bwrite(nhfp)) {
+        count = maybe_write_ls(nhfp, range, FALSE);
+        if (nhfp->structlevel) {
+            bwrite(nhfp->fd, (genericptr_t) &count, sizeof count);
+        }
+        if (nhfp->fieldlevel) {
+            sfo_int(nhfp, &count, "lightsources", "lightsource_count", 1);
+        }
+        actual = maybe_write_ls(nhfp, range, TRUE);
         if (actual != count)
             panic("counted %d light sources, wrote %d! [range=%d]", count,
                   actual, range);
     }
-
-    if (release_data(mode)) {
+    
+     if (release_data(nhfp)) {
         for (prev = &g.light_base; (curr = *prev) != 0;) {
             if (!curr->id.a_monst) {
                 impossible("save_light_sources: no id! [range=%d]", range);
@@ -361,18 +371,24 @@ int fd, mode, range;
  * pointers.
  */
 void
-restore_light_sources(fd)
-int fd;
+restore_light_sources(nhfp)
+NHFILE *nhfp;
 {
     int count;
     light_source *ls;
 
     /* restore elements */
-    mread(fd, (genericptr_t) &count, sizeof count);
+    if (nhfp->structlevel)
+        mread(nhfp->fd, (genericptr_t) &count, sizeof count);
+    if (nhfp->fieldlevel)
+        sfi_int(nhfp, &count, "lightsources", "lightsource_count", 1);
 
     while (count-- > 0) {
         ls = (light_source *) alloc(sizeof(light_source));
-        mread(fd, (genericptr_t) ls, sizeof(light_source));
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) ls, sizeof(light_source));
+        if (nhfp->fieldlevel)
+            sfi_ls_t(nhfp, ls, "lightsources", "lightsource", 1);
         ls->next = g.light_base;
         g.light_base = ls;
     }
@@ -430,14 +446,17 @@ boolean ghostly;
     }
 }
 
+/* SAVE2018 */
+
 /*
  * Part of the light source save routine.  Count up the number of light
  * sources that would be written.  If write_it is true, actually write
  * the light source out.
  */
 STATIC_OVL int
-maybe_write_ls(fd, range, write_it)
-int fd, range;
+maybe_write_ls(nhfp, range, write_it)
+NHFILE *nhfp;
+int range;
 boolean write_it;
 {
     int count = 0, is_global;
@@ -465,7 +484,7 @@ boolean write_it;
         if (is_global ^ (range == RANGE_LEVEL)) {
             count++;
             if (write_it)
-                write_ls(fd, ls);
+                write_ls(nhfp, ls);
         }
     }
 
@@ -499,11 +518,19 @@ light_sources_sanity_check()
     }
 }
 
-/* Write a light source structure to disk. */
+/* SAVE2018 */
+#if 0
 STATIC_OVL void
 write_ls(fd, ls)
 int fd;
 light_source *ls;
+#endif /* 0 */
+
+/* Write a light source structure to disk. */
+STATIC_OVL void
+write_ls(nhfp, ls)
+NHFILE *nhfp;
+light_source *ls;
 {
     anything arg_save;
     struct obj *otmp;
@@ -511,7 +538,10 @@ light_source *ls;
 
     if (ls->type == LS_OBJECT || ls->type == LS_MONSTER) {
         if (ls->flags & LSF_NEEDS_FIXUP) {
-            bwrite(fd, (genericptr_t) ls, sizeof(light_source));
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t) ls, sizeof(light_source));
+            if (nhfp->fieldlevel)
+                sfo_ls_t(nhfp, ls, "lightsources", "lightsource", 1);
         } else {
             /* replace object pointer with id for write, then put back */
             arg_save = ls->id;
@@ -531,7 +561,10 @@ light_source *ls;
                                ls->id.a_uint);
             }
             ls->flags |= LSF_NEEDS_FIXUP;
-            bwrite(fd, (genericptr_t) ls, sizeof(light_source));
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t) ls, sizeof(light_source));
+            if (nhfp->fieldlevel)
+                sfo_ls_t(nhfp, ls, "lightsources", "lightsource", 1);
             ls->id = arg_save;
             ls->flags &= ~LSF_NEEDS_FIXUP;
         }
index 5f09d1bb37de01c0a68f80cb55d5cc7e23d0d730..b41560318ff1de6015d1abac65d2694bee76ab37 100644 (file)
@@ -6,6 +6,8 @@
 #include "hack.h"
 #include "sp_lev.h"
 #include "lev.h" /* save & restore info */
+#include "sfproto.h"
+
 
 STATIC_DCL int FDECL(iswall, (int, int));
 STATIC_DCL int FDECL(iswall_or_stone, (int, int));
@@ -1558,33 +1560,46 @@ water_friction()
 }
 
 void
-save_waterlevel(fd, mode)
-int fd, mode;
+save_waterlevel(nhfp)
+NHFILE *nhfp;
 {
     struct bubble *b;
 
     if (!Is_waterlevel(&u.uz) && !Is_airlevel(&u.uz))
         return;
 
-    if (perform_bwrite(mode)) {
+    if (perform_bwrite(nhfp)) {
         int n = 0;
         for (b = g.bbubbles; b; b = b->next)
             ++n;
-        bwrite(fd, (genericptr_t) &n, sizeof n);
-        bwrite(fd, (genericptr_t) &g.xmin, sizeof g.xmin);
-        bwrite(fd, (genericptr_t) &g.ymin, sizeof g.ymin);
-        bwrite(fd, (genericptr_t) &g.xmax, sizeof g.xmax);
-        bwrite(fd, (genericptr_t) &g.ymax, sizeof g.ymax);
-        for (b = g.bbubbles; b; b = b->next)
-            bwrite(fd, (genericptr_t) b, sizeof *b);
+        if (nhfp->structlevel) {
+            bwrite(nhfp->fd, (genericptr_t) &n, sizeof(int));
+            bwrite(nhfp->fd, (genericptr_t) &g.xmin, sizeof(int));
+            bwrite(nhfp->fd, (genericptr_t) &g.ymin, sizeof(int));
+            bwrite(nhfp->fd, (genericptr_t) &g.xmax, sizeof(int));
+            bwrite(nhfp->fd, (genericptr_t) &g.ymax, sizeof(int));
+        }
+        if (nhfp->fieldlevel) {
+            sfo_int(nhfp, &n, "waterlevel", "bubble_count", 1);
+            sfo_int(nhfp, &g.xmin, "waterlevel", "g.xmin", 1);
+            sfo_int(nhfp, &g.ymin, "waterlevel", "g.ymin", 1);
+            sfo_int(nhfp, &g.xmax, "waterlevel", "g.xmax", 1);
+            sfo_int(nhfp, &g.ymax, "waterlevel", "g.ymax", 1);
+        }
+        for (b = g.bbubbles; b; b = b->next) {
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t) b, sizeof(struct bubble));
+            if (nhfp->fieldlevel)
+                sfo_bubble(nhfp, b, "waterlevel", "bubble", 1);
+        }
     }
-    if (release_data(mode))
+    if (release_data(nhfp))
         unsetup_waterlevel();
 }
 
 void
-restore_waterlevel(fd)
-int fd;
+restore_waterlevel(nhfp)
+NHFILE *nhfp;
 {
     struct bubble *b = (struct bubble *) 0, *btmp;
     int i, n;
@@ -1592,7 +1607,7 @@ int fd;
     if (!Is_waterlevel(&u.uz) && !Is_airlevel(&u.uz))
         return;
 
-    if (fd == -1) { /* special handling for restore in goto_level() */
+    if (nhfp->fd == -1) { /* special handling for restore in goto_level() */
         if (!wizard)
             impossible("restore_waterlevel: returning to %s?",
                        Is_waterlevel(&u.uz) ? "Water" : "Air");
@@ -1601,23 +1616,35 @@ int fd;
     }
 
     set_wportal();
-    mread(fd, (genericptr_t) &n, sizeof n);
-    mread(fd, (genericptr_t) &g.xmin, sizeof g.xmin);
-    mread(fd, (genericptr_t) &g.ymin, sizeof g.ymin);
-    mread(fd, (genericptr_t) &g.xmax, sizeof g.xmax);
-    mread(fd, (genericptr_t) &g.ymax, sizeof g.ymax);
+    if (nhfp->structlevel) {
+        mread(nhfp->fd,(genericptr_t)&n,sizeof(int));
+        mread(nhfp->fd,(genericptr_t)&g.xmin,sizeof(int));
+        mread(nhfp->fd,(genericptr_t)&g.ymin,sizeof(int));
+        mread(nhfp->fd,(genericptr_t)&g.xmax,sizeof(int));
+        mread(nhfp->fd,(genericptr_t)&g.ymax,sizeof(int));
+    }
+    if (nhfp->fieldlevel) {
+        sfi_int(nhfp, &n, "waterlevel", "bubble_count", 1);
+        sfi_int(nhfp, &g.xmin, "waterlevel", "g.xmin", 1);
+        sfi_int(nhfp, &g.ymin, "waterlevel", "g.ymin", 1);
+        sfi_int(nhfp, &g.xmax, "waterlevel", "g.xmax", 1);
+        sfi_int(nhfp, &g.ymax, "waterlevel", "g.ymax", 1);
+    }
     for (i = 0; i < n; i++) {
         btmp = b;
-        b = (struct bubble *) alloc(sizeof *b);
-        mread(fd, (genericptr_t) b, sizeof *b);
-        if (g.bbubbles) {
-            btmp->next = b;
-            b->prev = btmp;
-        } else {
-            g.bbubbles = b;
-            b->prev = (struct bubble *) 0;
-        }
-        mv_bubble(b, 0, 0, TRUE);
+        b = (struct bubble *) alloc(sizeof(struct bubble));
+        if (nhfp->structlevel)
+            mread(nhfp->fd,(genericptr_t) b, sizeof(struct bubble));
+        if (nhfp->fieldlevel)
+            sfi_bubble(nhfp, b, "waterlevel", "bubble", 1);
+      if (g.bbubbles) {
+          btmp->next = b;
+          b->prev = btmp;
+      } else {
+          g.bbubbles = b;
+          b->prev = (struct bubble *) 0;
+      }
+      mv_bubble(b, 0, 0, TRUE);
     }
     g.ebubbles = b;
     b->next = (struct bubble *) 0;
index 626fff172c36dffb3234ea40d94fdd656510d9c5..4ed3d134890766cdce008fe0d0a77168374c4c94 100644 (file)
@@ -16,6 +16,8 @@
  */
 
 #include "hack.h"
+#include "sfproto.h"
+
 
 STATIC_DCL boolean FDECL(isbig, (struct mkroom *));
 STATIC_DCL struct mkroom *FDECL(pick_room, (BOOLEAN_P));
@@ -24,8 +26,11 @@ STATIC_DCL void NDECL(mktemple);
 STATIC_DCL coord *FDECL(shrine_pos, (int));
 STATIC_DCL struct permonst *NDECL(morguemon);
 STATIC_DCL struct permonst *NDECL(squadmon);
-STATIC_DCL void FDECL(save_room, (int, struct mkroom *));
-STATIC_DCL void FDECL(rest_room, (int, struct mkroom *));
+/* SAVE2018 */
+/* STATIC_DCL void FDECL(save_room, (int,struct mkroom *)); */
+/* STATIC_DCL void FDECL(rest_room, (int,struct mkroom *)); */
+STATIC_DCL void FDECL(save_room, (NHFILE *, struct mkroom *));
+STATIC_DCL void FDECL(rest_room, (NHFILE *, struct mkroom *));
 
 #define sq(x) ((x) * (x))
 
@@ -796,8 +801,8 @@ gotone:
  * (if any).
  */
 STATIC_OVL void
-save_room(fd, r)
-int fd;
+save_room(nhfp, r)
+NHFILE *nhfp;
 struct mkroom *r;
 {
     short i;
@@ -807,37 +812,48 @@ struct mkroom *r;
      * of writing the whole structure. That is I should not write
      * the g.subrooms pointers, but who cares ?
      */
-    bwrite(fd, (genericptr_t) r, sizeof (struct mkroom));
-    for (i = 0; i < r->nsubrooms; i++)
-        save_room(fd, r->sbrooms[i]);
+    if (nhfp->structlevel)
+        bwrite(nhfp->fd, (genericptr_t) r, sizeof (struct mkroom));
+    if (nhfp->fieldlevel)
+        sfo_mkroom(nhfp, r, "room", "mkroom", 1);
+    for (i = 0; i < r->nsubrooms; i++) {
+        save_room(nhfp, r->sbrooms[i]);
+    }
 }
 
 /*
  * save_rooms : Save all the rooms on disk!
  */
 void
-save_rooms(fd)
-int fd;
+save_rooms(nhfp)
+NHFILE *nhfp;
 {
     short i;
 
     /* First, write the number of rooms */
-    bwrite(fd, (genericptr_t) &g.nroom, sizeof(g.nroom));
+    if (nhfp->structlevel)
+        bwrite(nhfp->fd, (genericptr_t) &g.nroom, sizeof(g.nroom));
+    if (nhfp->fieldlevel)
+        sfo_int(nhfp, &g.nroom, "room", "g.nroom", 1);
     for (i = 0; i < g.nroom; i++)
-        save_room(fd, &g.rooms[i]);
+        save_room(nhfp, &g.rooms[i]);
 }
 
 STATIC_OVL void
-rest_room(fd, r)
-int fd;
+rest_room(nhfp, r)
+NHFILE *nhfp;
 struct mkroom *r;
 {
     short i;
 
-    mread(fd, (genericptr_t) r, sizeof(struct mkroom));
+    if (nhfp->structlevel)
+        mread(nhfp->fd, (genericptr_t) r, sizeof(struct mkroom));
+    if (nhfp->fieldlevel)
+        sfi_mkroom(nhfp, r, "room", "mkroom", 1);
+
     for (i = 0; i < r->nsubrooms; i++) {
         r->sbrooms[i] = &g.subrooms[g.nsubroom];
-        rest_room(fd, &g.subrooms[g.nsubroom]);
+        rest_room(nhfp, &g.subrooms[g.nsubroom]);
         g.subrooms[g.nsubroom++].resident = (struct monst *) 0;
     }
 }
@@ -847,15 +863,19 @@ struct mkroom *r;
  * the disk.
  */
 void
-rest_rooms(fd)
-int fd;
+rest_rooms(nhfp)
+NHFILE *nhfp;
 {
     short i;
 
-    mread(fd, (genericptr_t) &g.nroom, sizeof(g.nroom));
+    if (nhfp->structlevel)
+        mread(nhfp->fd, (genericptr_t) &g.nroom, sizeof(g.nroom));
+    if (nhfp->fieldlevel)
+        sfi_int(nhfp, &g.nroom, "room", "g.nroom", 1);
+
     g.nsubroom = 0;
     for (i = 0; i < g.nroom; i++) {
-        rest_room(fd, &g.rooms[i]);
+        rest_room(nhfp, &g.rooms[i]);
         g.rooms[i].resident = (struct monst *) 0;
     }
     g.rooms[g.nroom].hx = -1; /* restore ending flags */
index d6ae37cc2946e26e6bfaaa1fc35acfdb2be63805..df6714eb4a745958c0e53f1202a1f066b390697b 100644 (file)
@@ -5,6 +5,8 @@
 
 #include "hack.h"
 #include "lev.h" /* save & restore info */
+#include "sfproto.h"
+
 
 STATIC_DCL void FDECL(setgemprobs, (d_level *));
 STATIC_DCL void FDECL(shuffle, (int, int, BOOLEAN_P));
@@ -286,29 +288,46 @@ oinit()
 }
 
 void
-savenames(fd, mode)
-int fd, mode;
+savenames(nhfp)
+NHFILE *nhfp;
 {
-    register int i;
+    int i, j;
     unsigned int len;
 
-    if (perform_bwrite(mode)) {
-        bwrite(fd, (genericptr_t) g.bases, sizeof g.bases);
-        bwrite(fd, (genericptr_t) g.disco, sizeof g.disco);
-        bwrite(fd, (genericptr_t) objects,
-               sizeof(struct objclass) * NUM_OBJECTS);
+    if (perform_bwrite(nhfp)) {
+        if (nhfp->structlevel) {
+            bwrite(nhfp->fd, (genericptr_t)g.bases, sizeof g.bases);
+            bwrite(nhfp->fd, (genericptr_t)g.disco, sizeof g.disco);
+            bwrite(nhfp->fd, (genericptr_t)objects,
+                   sizeof(struct objclass) * NUM_OBJECTS);
+        }
+        if (nhfp->fieldlevel) {
+            for (i = 0; i < MAXOCLASSES; ++i)
+                sfo_int(nhfp, &g.bases[i], "names", "g.bases", 1);
+            for (i = 0; i < NUM_OBJECTS; ++i)
+                sfo_short(nhfp, &g.disco[i], "names", "g.disco", 1);
+            for (i = 0; i < NUM_OBJECTS; ++i)
+                sfo_objclass(nhfp, &objects[i], "names", "objclass", 1);
+        }
     }
     /* as long as we use only one version of Hack we
        need not save oc_name and oc_descr, but we must save
        oc_uname for all objects */
     for (i = 0; i < NUM_OBJECTS; i++)
         if (objects[i].oc_uname) {
-            if (perform_bwrite(mode)) {
+            if (perform_bwrite(nhfp)) {
                 len = strlen(objects[i].oc_uname) + 1;
-                bwrite(fd, (genericptr_t) &len, sizeof len);
-                bwrite(fd, (genericptr_t) objects[i].oc_uname, len);
+                if (nhfp->structlevel) {
+                    bwrite(nhfp->fd, (genericptr_t)&len, sizeof len);
+                    bwrite(nhfp->fd, (genericptr_t)objects[i].oc_uname, len);
+                }
+                if (nhfp->fieldlevel) {
+                    sfo_unsigned(nhfp, &len, "names", "len", 1);
+                    for (j = 0; (unsigned) j < len; ++j)
+                        sfo_char(nhfp, &objects[i].oc_uname[j], "names", "oc_uname", 1);
+                }
             }
-            if (release_data(mode)) {
+            if (release_data(nhfp)) {
                 free((genericptr_t) objects[i].oc_uname);
                 objects[i].oc_uname = 0;
             }
@@ -316,21 +335,45 @@ int fd, mode;
 }
 
 void
-restnames(fd)
-register int fd;
+restnames(nhfp)
+NHFILE *nhfp;
 {
-    register int i;
+    int i, j;
     unsigned int len;
 
-    mread(fd, (genericptr_t)g.bases, sizeof g.bases);
-    mread(fd, (genericptr_t) g.disco, sizeof g.disco);
-    mread(fd, (genericptr_t) objects, sizeof(struct objclass) * NUM_OBJECTS);
-    for (i = 0; i < NUM_OBJECTS; i++)
+    if (nhfp->structlevel) {
+        mread(nhfp->fd, (genericptr_t) g.bases, sizeof g.bases);
+        mread(nhfp->fd, (genericptr_t) g.disco, sizeof g.disco);
+        mread(nhfp->fd, (genericptr_t) objects,
+                sizeof(struct objclass) * NUM_OBJECTS);
+    }
+    if (nhfp->fieldlevel) {
+        for (i = 0; i < MAXOCLASSES; ++i)
+            sfi_int(nhfp, &g.bases[i], "names", "g.bases", 1);
+        for (i = 0; i < NUM_OBJECTS; ++i)
+            sfi_short(nhfp, &g.disco[i], "names", "g.disco", 1);
+        for (i = 0; i < NUM_OBJECTS; ++i)
+            sfi_objclass(nhfp, &objects[i], "names", "objclass", 1);
+    }
+    for (i = 0; i < NUM_OBJECTS; i++) {
         if (objects[i].oc_uname) {
-            mread(fd, (genericptr_t) &len, sizeof len);
+            if (nhfp->structlevel) {
+                mread(nhfp->fd, (genericptr_t) &len, sizeof len);
+            }
+            if (nhfp->fieldlevel) {
+                sfi_unsigned(nhfp, &len, "names", "len", 1);
+            }
             objects[i].oc_uname = (char *) alloc(len);
-            mread(fd, (genericptr_t) objects[i].oc_uname, len);
-        }
+            if (nhfp->structlevel) {
+                mread(nhfp->fd, (genericptr_t)objects[i].oc_uname, len);
+            }
+            if (nhfp->fieldlevel) {
+                for (j = 0; (unsigned) j < len; ++j)
+                    sfi_char(nhfp, &objects[i].oc_uname[j],
+                                "names", "oc_uname", 1);
+            }
+       }
+    }
 #ifdef USE_TILES
     shuffle_tiles();
 #endif
index d4ef29116a38e398860872d5dde908f25455d45f..ed4396c673dede1eb8972c78ef1404d7e70cb04a 100644 (file)
@@ -18,6 +18,7 @@ NEARDATA struct instance_flags iflags; /* provide linkage */
 #include "tcap.h"
 #include <ctype.h>
 #endif
+#include "sfprocs.h"
 
 #define BACKWARD_COMPAT
 
@@ -698,6 +699,9 @@ initoptions_init()
         if (boolopt[i].addr)
             *(boolopt[i].addr) = boolopt[i].initvalue;
     }
+    /* initialize the function pointers for fieldlevel saves */
+    sf_init();
+
 #if defined(COMPRESS) || defined(ZLIB_COMP)
     set_savepref("externalcomp");
     set_restpref("externalcomp");
index 87e167724faa2672f0c4ced50d660f20b4b38b81..057d58bf65d96fbe95b3fbf83a2289d4ccf84b9c 100644 (file)
@@ -4,6 +4,8 @@
 
 #include "hack.h"
 #include "lev.h"
+#include "sfproto.h"
+
 
 /*
  * This should really go into the level structure, but
@@ -613,64 +615,126 @@ xchar x, y;
  * save_regions :
  */
 void
-save_regions(fd, mode)
-int fd;
-int mode;
+save_regions(nhfp)
+NHFILE *nhfp;
 {
     int i, j;
     unsigned n;
 
-    if (!perform_bwrite(mode))
+    if (!perform_bwrite(nhfp))
         goto skip_lots;
-
-    bwrite(fd, (genericptr_t) &g.moves, sizeof(g.moves)); /* timestamp */
-    bwrite(fd, (genericptr_t) &g.n_regions, sizeof(g.n_regions));
+    if (nhfp->structlevel) {
+        bwrite(nhfp->fd, (genericptr_t) &g.moves, sizeof (g.moves));   /* timestamp */
+        bwrite(nhfp->fd, (genericptr_t) &g.n_regions, sizeof (g.n_regions));
+    }
+    if (nhfp->fieldlevel) {
+        sfo_long(nhfp, &g.moves, "regions", "tmstamp", 1);
+        sfo_int(nhfp, &g.n_regions, "regions", "region_count", 1);
+    }
     for (i = 0; i < g.n_regions; i++) {
-        bwrite(fd, (genericptr_t) &g.regions[i]->bounding_box, sizeof(NhRect));
-        bwrite(fd, (genericptr_t) &g.regions[i]->nrects, sizeof(short));
-        for (j = 0; j < g.regions[i]->nrects; j++)
-            bwrite(fd, (genericptr_t) &g.regions[i]->rects[j], sizeof(NhRect));
-        bwrite(fd, (genericptr_t) &g.regions[i]->attach_2_u, sizeof(boolean));
+        if (nhfp->structlevel) {
+            bwrite(nhfp->fd, (genericptr_t) &g.regions[i]->bounding_box, sizeof (NhRect));
+            bwrite(nhfp->fd, (genericptr_t) &g.regions[i]->nrects, sizeof (short));
+        }
+        if (nhfp->fieldlevel) {
+            sfo_nhrect(nhfp, &g.regions[i]->bounding_box, "g.regions", "bounding_box", 1);
+            sfo_short(nhfp, &g.regions[i]->nrects, "g.regions", "nrects", 1);
+        }
+        for (j = 0; j < g.regions[i]->nrects; j++) {
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t) &g.regions[i]->rects[j], sizeof (NhRect));
+            if (nhfp->fieldlevel)
+                sfo_nhrect(nhfp, &g.regions[i]->rects[j], "g.regions", "rect", 1);
+        }
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &g.regions[i]->attach_2_u, sizeof (boolean));
+        if (nhfp->fieldlevel)
+            sfo_boolean(nhfp, &g.regions[i]->attach_2_u, "g.regions", "attach_2_u", 1);
         n = 0;
-        bwrite(fd, (genericptr_t) &g.regions[i]->attach_2_m, sizeof(unsigned));
-        n = g.regions[i]->enter_msg != (const char *) 0
-                ? strlen(g.regions[i]->enter_msg)
-                : 0;
-        bwrite(fd, (genericptr_t) &n, sizeof n);
-        if (n > 0)
-            bwrite(fd, (genericptr_t) g.regions[i]->enter_msg, n);
-        n = g.regions[i]->leave_msg != (const char *) 0
-                ? strlen(g.regions[i]->leave_msg)
-                : 0;
-        bwrite(fd, (genericptr_t) &n, sizeof n);
-        if (n > 0)
-            bwrite(fd, (genericptr_t) g.regions[i]->leave_msg, n);
-        bwrite(fd, (genericptr_t) &g.regions[i]->ttl, sizeof(long));
-        bwrite(fd, (genericptr_t) &g.regions[i]->expire_f, sizeof(short));
-        bwrite(fd, (genericptr_t) &g.regions[i]->can_enter_f, sizeof(short));
-        bwrite(fd, (genericptr_t) &g.regions[i]->enter_f, sizeof(short));
-        bwrite(fd, (genericptr_t) &g.regions[i]->can_leave_f, sizeof(short));
-        bwrite(fd, (genericptr_t) &g.regions[i]->leave_f, sizeof(short));
-        bwrite(fd, (genericptr_t) &g.regions[i]->inside_f, sizeof(short));
-        bwrite(fd, (genericptr_t) &g.regions[i]->player_flags,
-               sizeof(unsigned int));
-        bwrite(fd, (genericptr_t) &g.regions[i]->n_monst, sizeof(short));
-        for (j = 0; j < g.regions[i]->n_monst; j++)
-            bwrite(fd, (genericptr_t) &g.regions[i]->monsters[j],
-                   sizeof(unsigned));
-        bwrite(fd, (genericptr_t) &g.regions[i]->visible, sizeof(boolean));
-        bwrite(fd, (genericptr_t) &g.regions[i]->glyph, sizeof(int));
-        bwrite(fd, (genericptr_t) &g.regions[i]->arg, sizeof(anything));
-    }
 
-skip_lots:
-    if (release_data(mode))
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &g.regions[i]->attach_2_m, sizeof (unsigned));
+        if (nhfp->fieldlevel)
+            sfo_unsigned(nhfp, &g.regions[i]->attach_2_m, "g.regions", "attach_2_m", 1);
+
+        n = g.regions[i]->enter_msg != (const char *)0 ?
+                                        strlen(g.regions[i]->enter_msg) : 0;
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &n, sizeof n);
+        if (nhfp->fieldlevel)
+            sfo_unsigned(nhfp, &n, "g.regions", "enter_msg_length", 1);
+
+        if (n > 0) {
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t) g.regions[i]->enter_msg, n);
+            if (nhfp->fieldlevel)
+                sfo_char(nhfp, g.regions[i]->enter_msg, "g.regions", "enter_msg", 1);
+        }
+        n = g.regions[i]->leave_msg != (const char *)0 ?
+                                        strlen(g.regions[i]->leave_msg) : 0;
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &n, sizeof n);
+        if (nhfp->fieldlevel)
+            sfo_unsigned(nhfp, &n, "g.regions", "leave_msg_length", 1);
+
+        if (n > 0) {
+            if (nhfp->structlevel) {
+                bwrite(nhfp->fd, (genericptr_t) g.regions[i]->leave_msg, n);
+            }
+            if (nhfp->fieldlevel) {
+                for (j = 0; j < (int) n; ++j)
+                    sfo_char(nhfp, &g.regions[i]->leave_msg[j], "g.regions", "leave_msg", 1);
+            }
+        }
+        if (nhfp->structlevel) {
+            bwrite(nhfp->fd, (genericptr_t) &g.regions[i]->ttl, sizeof (long));
+            bwrite(nhfp->fd, (genericptr_t) &g.regions[i]->expire_f, sizeof (short));
+            bwrite(nhfp->fd, (genericptr_t) &g.regions[i]->can_enter_f, sizeof (short));
+            bwrite(nhfp->fd, (genericptr_t) &g.regions[i]->enter_f, sizeof (short));
+            bwrite(nhfp->fd, (genericptr_t) &g.regions[i]->can_leave_f, sizeof (short));
+            bwrite(nhfp->fd, (genericptr_t) &g.regions[i]->leave_f, sizeof (short));
+            bwrite(nhfp->fd, (genericptr_t) &g.regions[i]->inside_f, sizeof (short));
+            bwrite(nhfp->fd, (genericptr_t) &g.regions[i]->player_flags, sizeof (unsigned int));
+            bwrite(nhfp->fd, (genericptr_t) &g.regions[i]->n_monst, sizeof (short));
+        }
+        if (nhfp->fieldlevel) {
+            sfo_long(nhfp, &g.regions[i]->ttl, "g.regions", "ttl", 1);
+            sfo_short(nhfp, &g.regions[i]->expire_f, "g.regions", "expire_f", 1);
+            sfo_short(nhfp, &g.regions[i]->can_enter_f, "g.regions", "can_enter_f", 1);
+            sfo_short(nhfp, &g.regions[i]->enter_f, "g.regions", "enter_f", 1);
+            sfo_short(nhfp, &g.regions[i]->can_leave_f, "g.regions", "can_leave_f", 1);
+            sfo_short(nhfp, &g.regions[i]->leave_f, "g.regions", "leave_f", 1);
+            sfo_short(nhfp, &g.regions[i]->inside_f, "g.regions", "inside_f", 1);
+            sfo_unsigned(nhfp, &g.regions[i]->player_flags, "g.regions", "player_flags", 1);
+            sfo_short(nhfp, &g.regions[i]->n_monst, "g.regions", "monster_count", 1);
+        }
+        for (j = 0; j < g.regions[i]->n_monst; j++) {
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t) &g.regions[i]->monsters[j],
+                        sizeof (unsigned));
+            if (nhfp->fieldlevel)
+                sfo_unsigned(nhfp, &g.regions[i]->monsters[j], "g.regions", "monster", 1);
+        }
+        if (nhfp->structlevel) {
+            bwrite(nhfp->fd, (genericptr_t) &g.regions[i]->visible, sizeof (boolean));
+            bwrite(nhfp->fd, (genericptr_t) &g.regions[i]->glyph, sizeof (int));
+            bwrite(nhfp->fd, (genericptr_t) &g.regions[i]->arg, sizeof (anything));
+        }
+        if (nhfp->fieldlevel) {
+            sfo_boolean(nhfp, &g.regions[i]->visible, "g.regions", "visible", 1);
+            sfo_int(nhfp, &g.regions[i]->glyph, "g.regions", "glyph", 1);
+            sfo_any(nhfp, &g.regions[i]->arg, "g.regions", "arg", 1);
+        }
+    }
+  
+  skip_lots:
+    if (release_data(nhfp))
         clear_regions();
 }
 
 void
-rest_regions(fd, ghostly)
-int fd;
+rest_regions(nhfp, ghostly)
+NHFILE *nhfp;
 boolean ghostly; /* If a bones file restore */
 {
     int i, j;
@@ -678,77 +742,152 @@ boolean ghostly; /* If a bones file restore */
     long tmstamp;
     char *msg_buf;
 
-    clear_regions(); /* Just for security */
-    mread(fd, (genericptr_t) &tmstamp, sizeof(tmstamp));
+    clear_regions();           /* Just for security */
+    if (nhfp->structlevel)
+        mread(nhfp->fd, (genericptr_t) &tmstamp, sizeof (tmstamp));
+    if (nhfp->fieldlevel)
+        sfi_long(nhfp, &tmstamp, "regions", "tmstamp", 1);
     if (ghostly)
         tmstamp = 0;
     else
         tmstamp = (g.moves - tmstamp);
-    mread(fd, (genericptr_t) &g.n_regions, sizeof(g.n_regions));
+
+    if (nhfp->structlevel)
+        mread(nhfp->fd, (genericptr_t) &g.n_regions, sizeof (g.n_regions));
+    if (nhfp->fieldlevel)
+        sfi_int(nhfp, &g.n_regions, "regions", "region_count", 1);
+
     g.max_regions = g.n_regions;
     if (g.n_regions > 0)
-        g.regions = (NhRegion **) alloc(sizeof(NhRegion *) * g.n_regions);
+        g.regions = (NhRegion **) alloc(sizeof (NhRegion *) * g.n_regions);
     for (i = 0; i < g.n_regions; i++) {
-        g.regions[i] = (NhRegion *) alloc(sizeof(NhRegion));
-        mread(fd, (genericptr_t) &g.regions[i]->bounding_box, sizeof(NhRect));
-        mread(fd, (genericptr_t) &g.regions[i]->nrects, sizeof(short));
-
+        g.regions[i] = (NhRegion *) alloc(sizeof (NhRegion));
+        if (nhfp->structlevel) {
+            mread(nhfp->fd, (genericptr_t) &g.regions[i]->bounding_box, sizeof (NhRect));
+            mread(nhfp->fd, (genericptr_t) &g.regions[i]->nrects, sizeof (short));
+        }
+        if (nhfp->fieldlevel) {
+            sfi_nhrect(nhfp, &g.regions[i]->bounding_box, "g.regions", "bounding box", 1);
+            sfi_short(nhfp, &g.regions[i]->nrects, "g.regions", "nrects", 1);
+        }
         if (g.regions[i]->nrects > 0)
-            g.regions[i]->rects =
-                (NhRect *) alloc(sizeof(NhRect) * g.regions[i]->nrects);
-        for (j = 0; j < g.regions[i]->nrects; j++)
-            mread(fd, (genericptr_t) &g.regions[i]->rects[j], sizeof(NhRect));
-        mread(fd, (genericptr_t) &g.regions[i]->attach_2_u, sizeof(boolean));
-        mread(fd, (genericptr_t) &g.regions[i]->attach_2_m, sizeof(unsigned));
-
-        mread(fd, (genericptr_t) &n, sizeof n);
+            g.regions[i]->rects = (NhRect *)
+                                 alloc(sizeof (NhRect) * g.regions[i]->nrects);
+        for (j = 0; j < g.regions[i]->nrects; j++) {
+            if (nhfp->structlevel)
+                mread(nhfp->fd, (genericptr_t) &g.regions[i]->rects[j], sizeof (NhRect));
+            if (nhfp->fieldlevel)
+                sfi_nhrect(nhfp, &g.regions[i]->rects[j], "g.regions", "rect", 1);
+        }
+        if (nhfp->structlevel) {
+            mread(nhfp->fd, (genericptr_t) &g.regions[i]->attach_2_u, sizeof (boolean));
+            mread(nhfp->fd, (genericptr_t) &g.regions[i]->attach_2_m, sizeof (unsigned));
+        }
+        if (nhfp->fieldlevel) {
+            sfi_boolean(nhfp, &g.regions[i]->attach_2_u, "g.regions", "attach_2_u", 1);
+            sfi_unsigned(nhfp, &g.regions[i]->attach_2_m, "g.regions", "attach_2_m", 1);
+        }
+
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) &n, sizeof n);
+        if (nhfp->fieldlevel)
+            sfi_unsigned(nhfp, &n, "g.regions", "enter_msg_length", 1);
         if (n > 0) {
             msg_buf = (char *) alloc(n + 1);
-            mread(fd, (genericptr_t) msg_buf, n);
+            if (nhfp->structlevel) {
+                mread(nhfp->fd, (genericptr_t) msg_buf, n);
+            }
+            if (nhfp->fieldlevel) {
+                for (j = 0; (unsigned) j < n; ++j)
+                    sfi_char(nhfp, &msg_buf[j], "g.regions", "enter_msg", 1);
+            }
             msg_buf[n] = '\0';
             g.regions[i]->enter_msg = (const char *) msg_buf;
         } else
-            g.regions[i]->enter_msg = (const char *) 0;
+            g.regions[i]->enter_msg = (const char *)0;
 
-        mread(fd, (genericptr_t) &n, sizeof n);
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) &n, sizeof n);
+        if (nhfp->fieldlevel)
+            sfi_unsigned(nhfp, &n, "g.regions", "leave_msg_length", 1);
         if (n > 0) {
             msg_buf = (char *) alloc(n + 1);
-            mread(fd, (genericptr_t) msg_buf, n);
+            if (nhfp->structlevel) {
+                mread(nhfp->fd, (genericptr_t) msg_buf, n);
+            }
+            if (nhfp->fieldlevel) {
+                for (j = 0; (unsigned) j < n; ++j)
+                    sfi_char(nhfp, &msg_buf[j], "g.regions", "leave_msg", 1);
+            }
             msg_buf[n] = '\0';
-            g.regions[i]->leave_msg = (const char *) msg_buf;
+           g.regions[i]->leave_msg = (const char *) msg_buf;
         } else
-            g.regions[i]->leave_msg = (const char *) 0;
+            g.regions[i]->leave_msg = (const char *)0;
 
-        mread(fd, (genericptr_t) &g.regions[i]->ttl, sizeof(long));
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) &g.regions[i]->ttl, sizeof (long));
+        if (nhfp->fieldlevel)
+            sfi_long(nhfp, &g.regions[i]->ttl, "g.regions", "ttl", 1);
         /* check for expired region */
         if (g.regions[i]->ttl >= 0L)
             g.regions[i]->ttl =
-                (g.regions[i]->ttl > tmstamp) ? g.regions[i]->ttl - tmstamp : 0L;
-        mread(fd, (genericptr_t) &g.regions[i]->expire_f, sizeof(short));
-        mread(fd, (genericptr_t) &g.regions[i]->can_enter_f, sizeof(short));
-        mread(fd, (genericptr_t) &g.regions[i]->enter_f, sizeof(short));
-        mread(fd, (genericptr_t) &g.regions[i]->can_leave_f, sizeof(short));
-        mread(fd, (genericptr_t) &g.regions[i]->leave_f, sizeof(short));
-        mread(fd, (genericptr_t) &g.regions[i]->inside_f, sizeof(short));
-        mread(fd, (genericptr_t) &g.regions[i]->player_flags,
-              sizeof(unsigned int));
-        if (ghostly) { /* settings pertained to old player */
+               (g.regions[i]->ttl > tmstamp) ? g.regions[i]->ttl - tmstamp : 0L;
+        if (nhfp->structlevel) {
+            mread(nhfp->fd, (genericptr_t) &g.regions[i]->expire_f,
+                    sizeof (short));
+            mread(nhfp->fd, (genericptr_t) &g.regions[i]->can_enter_f,
+                    sizeof (short));
+            mread(nhfp->fd, (genericptr_t) &g.regions[i]->enter_f,
+                    sizeof (short));
+            mread(nhfp->fd, (genericptr_t) &g.regions[i]->can_leave_f,
+                    sizeof (short));
+            mread(nhfp->fd, (genericptr_t) &g.regions[i]->leave_f,
+                    sizeof (short));
+            mread(nhfp->fd, (genericptr_t) &g.regions[i]->inside_f,
+                    sizeof (short));
+            mread(nhfp->fd, (genericptr_t) &g.regions[i]->player_flags,
+                    sizeof (unsigned int));
+        }
+        if (nhfp->fieldlevel) {
+            sfi_short(nhfp, &g.regions[i]->expire_f, "g.regions", "expire_f", 1);
+            sfi_short(nhfp, &g.regions[i]->can_enter_f, "g.regions", "can_enter_f", 1);
+            sfi_short(nhfp, &g.regions[i]->enter_f, "g.regions", "enter_f", 1);
+            sfi_short(nhfp, &g.regions[i]->can_leave_f, "g.regions", "can_leave_f", 1);
+            sfi_short(nhfp, &g.regions[i]->leave_f, "g.regions", "leave_f", 1);
+            sfi_short(nhfp, &g.regions[i]->inside_f, "g.regions", "inside_f", 1);
+            sfi_unsigned(nhfp, &g.regions[i]->player_flags, "g.regions", "player_flags", 1);
+        }
+        if (ghostly) { /* settings pertained to old player */
             clear_hero_inside(g.regions[i]);
             clear_heros_fault(g.regions[i]);
         }
-        mread(fd, (genericptr_t) &g.regions[i]->n_monst, sizeof(short));
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) &g.regions[i]->n_monst, sizeof (short));
+        if (nhfp->fieldlevel)
+            sfi_short(nhfp, &g.regions[i]->n_monst, "g.regions", "monster_count", 1);
         if (g.regions[i]->n_monst > 0)
             g.regions[i]->monsters =
-                (unsigned *) alloc(sizeof(unsigned) * g.regions[i]->n_monst);
+                        (unsigned *) alloc(sizeof (unsigned) * g.regions[i]->n_monst);
         else
-            g.regions[i]->monsters = (unsigned int *) 0;
+            g.regions[i]->monsters = (unsigned int *)0;
         g.regions[i]->max_monst = g.regions[i]->n_monst;
-        for (j = 0; j < g.regions[i]->n_monst; j++)
-            mread(fd, (genericptr_t) &g.regions[i]->monsters[j],
-                  sizeof(unsigned));
-        mread(fd, (genericptr_t) &g.regions[i]->visible, sizeof(boolean));
-        mread(fd, (genericptr_t) &g.regions[i]->glyph, sizeof(int));
-        mread(fd, (genericptr_t) &g.regions[i]->arg, sizeof(anything));
+        for (j = 0; j < g.regions[i]->n_monst; j++) {
+            if (nhfp->structlevel)
+                mread(nhfp->fd, (genericptr_t) &g.regions[i]->monsters[j],
+                        sizeof (unsigned));
+            if (nhfp->fieldlevel)
+                sfi_unsigned(nhfp, &g.regions[i]->monsters[j], "g.regions", "monster", 1);
+        }
+        if (nhfp->structlevel) {
+            mread(nhfp->fd, (genericptr_t) &g.regions[i]->visible, sizeof (boolean));
+            mread(nhfp->fd, (genericptr_t) &g.regions[i]->glyph, sizeof (int));
+            mread(nhfp->fd, (genericptr_t) &g.regions[i]->arg, sizeof (anything));
+        }
+        if (nhfp->fieldlevel) {
+            sfi_boolean(nhfp, &g.regions[i]->visible, "g.regions", "visible", 1);
+            sfi_int(nhfp, &g.regions[i]->glyph, "g.regions", "glyph", 1);
+            sfi_any(nhfp, &g.regions[i]->arg, "g.regions", "arg", 1);
+        }
     }
     /* remove expired regions, do not trigger the expire_f callback (yet!);
        also update monster lists if this data is coming from a bones file */
index 948e720bd5f4f52dd7f395abb1f4e098b3b18dbb..312bc083fead1a2fbe07fe94231affd7cfed9b37 100644 (file)
@@ -6,6 +6,9 @@
 #include "hack.h"
 #include "lev.h"
 #include "tcap.h" /* for TERMLIB and ASCIIGRAPH */
+#include "sfproto.h"
+
+
 
 #if defined(MICRO)
 extern int dotcnt; /* shared with save */
@@ -26,33 +29,40 @@ STATIC_DCL void NDECL(def_minit);
 STATIC_DCL void FDECL(def_mread, (int, genericptr_t, unsigned int));
 
 STATIC_DCL void NDECL(find_lev_obj);
-STATIC_DCL void FDECL(restlevchn, (int));
-STATIC_DCL void FDECL(restdamage, (int, BOOLEAN_P));
-STATIC_DCL void FDECL(restobj, (int, struct obj *));
-STATIC_DCL struct obj *FDECL(restobjchn, (int, BOOLEAN_P, BOOLEAN_P));
-STATIC_OVL void FDECL(restmon, (int, struct monst *));
-STATIC_DCL struct monst *FDECL(restmonchn, (int, BOOLEAN_P));
-STATIC_DCL struct fruit *FDECL(loadfruitchn, (int));
+STATIC_DCL void FDECL(restlevchn, (NHFILE *));
+STATIC_DCL void FDECL(restdamage, (NHFILE *, BOOLEAN_P));
+STATIC_DCL void FDECL(restobj, (NHFILE *, struct obj *));
+STATIC_DCL struct obj *FDECL(restobjchn, (NHFILE *, BOOLEAN_P, BOOLEAN_P));
+STATIC_OVL void FDECL(restmon, (NHFILE *, struct monst *));
+STATIC_DCL struct monst *FDECL(restmonchn, (NHFILE *, BOOLEAN_P));
+STATIC_DCL struct fruit *FDECL(loadfruitchn, (NHFILE *));
 STATIC_DCL void FDECL(freefruitchn, (struct fruit *));
 STATIC_DCL void FDECL(ghostfruit, (struct obj *));
-STATIC_DCL boolean FDECL(restgamestate, (int, unsigned int *, unsigned int *));
+STATIC_DCL boolean FDECL(restgamestate, (NHFILE *, unsigned int *, unsigned int *));
 STATIC_DCL void FDECL(restlevelstate, (unsigned int, unsigned int));
-STATIC_DCL int FDECL(restlevelfile, (int, XCHAR_P));
-STATIC_OVL void FDECL(restore_msghistory, (int));
+STATIC_DCL int FDECL(restlevelfile, (NHFILE *, XCHAR_P));
+STATIC_OVL void FDECL(restore_msghistory, (NHFILE *));
 STATIC_DCL void FDECL(reset_oattached_mids, (BOOLEAN_P));
-STATIC_DCL void FDECL(rest_levl, (int, BOOLEAN_P));
-
-static struct restore_procs {
-    const char *name;
-    int mread_flags;
-    void NDECL((*restore_minit));
-    void FDECL((*restore_mread), (int, genericptr_t, unsigned int));
-    void FDECL((*restore_bclose), (int));
-} restoreprocs = {
+STATIC_DCL void FDECL(rest_levl, (NHFILE *, BOOLEAN_P));
+
+#if 0
+extern int FDECL(nhin, (NHFILE *,char *,int,const char *, genericptr_t,int));
+int FDECL(dorecover, (NHFILE *));
+extern char *FDECL(sfdt2txt,(int));
+extern size_t FDECL(sfdtsz,(int));
+#endif
+
+static struct restore_procs restoreprocs = {
 #if !defined(ZEROCOMP) || (defined(COMPRESS) || defined(ZLIB_COMP))
-    "externalcomp", 0, def_minit, def_mread, def_bclose,
+       "externalcomp", 0,
+       def_minit,
+       def_mread,
+        def_bclose,
 #else
-    "zerocomp", 0, zerocomp_minit, zerocomp_mread, zerocomp_bclose,
+       "zerocomp", 0,
+       zerocomp_minit,
+       zerocomp_mread,
+       zerocomp_bclose,
 #endif
 };
 
@@ -133,17 +143,25 @@ boolean quietly;
 }
 
 STATIC_OVL void
-restlevchn(fd)
-register int fd;
+restlevchn(nhfp)
+NHFILE *nhfp;
 {
     int cnt;
     s_level *tmplev, *x;
 
     g.sp_levchn = (s_level *) 0;
-    mread(fd, (genericptr_t) &cnt, sizeof(int));
+    if (nhfp->structlevel)
+        mread(nhfp->fd, (genericptr_t) &cnt, sizeof(int));
+    if (nhfp->fieldlevel)
+        sfi_int(nhfp, &cnt, "levchn", "lev_count", 1);
+
     for (; cnt > 0; cnt--) {
         tmplev = (s_level *) alloc(sizeof(s_level));
-        mread(fd, (genericptr_t) tmplev, sizeof(s_level));
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) tmplev, sizeof(s_level));
+        if (nhfp->fieldlevel)
+            sfi_s_level(nhfp, tmplev, "levchn", "s_level", 1);
+
         if (!g.sp_levchn)
             g.sp_levchn = tmplev;
         else {
@@ -155,22 +173,34 @@ register int fd;
     }
 }
 
+/* SAVE2018 */
+
 STATIC_OVL void
-restdamage(fd, ghostly)
-int fd;
+restdamage(nhfp, ghostly)
+NHFILE *nhfp;
 boolean ghostly;
 {
+    unsigned int dmgcount;
     int counter;
     struct damage *tmp_dam;
 
-    mread(fd, (genericptr_t) &counter, sizeof(counter));
+    if (nhfp->structlevel)
+        mread(nhfp->fd, (genericptr_t) &dmgcount, sizeof(dmgcount));
+    if (nhfp->fieldlevel)
+        sfi_unsigned(nhfp, &dmgcount, "damage", "damage_count", 1);
+    counter = (int) dmgcount;
+
     if (!counter)
         return;
     tmp_dam = (struct damage *) alloc(sizeof(struct damage));
     while (--counter >= 0) {
         char damaged_shops[5], *shp = (char *) 0;
 
-        mread(fd, (genericptr_t) tmp_dam, sizeof(*tmp_dam));
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) tmp_dam, sizeof(*tmp_dam));
+        if (nhfp->fieldlevel)
+            sfi_damage(nhfp, tmp_dam, "damage", "damage", 1);
+
         if (ghostly)
             tmp_dam->when += (g.monstermoves - g.omoves);
         Strcpy(damaged_shops,
@@ -198,15 +228,20 @@ boolean ghostly;
     free((genericptr_t) tmp_dam);
 }
 
+/* SAVE2018 */
+
 /* restore one object */
 STATIC_OVL void
-restobj(fd, otmp)
-int fd;
+restobj(nhfp, otmp)
+NHFILE *nhfp;
 struct obj *otmp;
 {
     int buflen;
 
-    mread(fd, (genericptr_t) otmp, sizeof(struct obj));
+    if (nhfp->structlevel)
+        mread(nhfp->fd, (genericptr_t) otmp, sizeof(struct obj));
+    if (nhfp->fieldlevel)
+        sfi_obj(nhfp, otmp, "obj", "obj", 1);
 
     /* next object pointers are invalid; otmp->cobj needs to be left
        as is--being non-null is key to restoring container contents */
@@ -216,46 +251,81 @@ struct obj *otmp;
         otmp->oextra = newoextra();
 
         /* oname - object's name */
-        mread(fd, (genericptr_t) &buflen, sizeof(buflen));
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) &buflen, sizeof(buflen));
+        if (nhfp->fieldlevel)
+            sfi_int(nhfp, &buflen, "obj", "oname_length", 1);
+
         if (buflen > 0) { /* includes terminating '\0' */
             new_oname(otmp, buflen);
-            mread(fd, (genericptr_t) ONAME(otmp), buflen);
+            if (nhfp->structlevel)
+                mread(nhfp->fd, (genericptr_t) ONAME(otmp), buflen);
+            if (nhfp->fieldlevel)
+                sfi_str(nhfp, ONAME(otmp), "obj", "oname", buflen);
         }
+
         /* omonst - corpse or statue might retain full monster details */
-        mread(fd, (genericptr_t) &buflen, sizeof(buflen));
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) &buflen, sizeof(buflen));
+        if (nhfp->fieldlevel)
+            sfi_int(nhfp, &buflen, "obj", "omonst_length", 1);
         if (buflen > 0) {
             newomonst(otmp);
             /* this is actually a monst struct, so we
                can just defer to restmon() here */
-            restmon(fd, OMONST(otmp));
+            restmon(nhfp, OMONST(otmp));    /* SAVE2018 */
         }
+
         /* omid - monster id number, connecting corpse to ghost */
-        mread(fd, (genericptr_t) &buflen, sizeof(buflen));
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) &buflen, sizeof(buflen));
+        if (nhfp->fieldlevel)
+            sfi_int(nhfp, &buflen, "obj", "omid_length", 1);
+
         if (buflen > 0) {
             newomid(otmp);
-            mread(fd, (genericptr_t) OMID(otmp), buflen);
+            if (nhfp->structlevel)
+                mread(nhfp->fd, (genericptr_t) OMID(otmp), buflen);
+            if (nhfp->fieldlevel)
+                sfi_unsigned(nhfp, OMID(otmp), "obj", "omid", 1);
         }
+
         /* olong - temporary gold */
-        mread(fd, (genericptr_t) &buflen, sizeof(buflen));
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) &buflen, sizeof(buflen));
+        if (nhfp->fieldlevel)
+            sfi_int(nhfp, &buflen, "obj",  "olong_length", 1);
         if (buflen > 0) {
             newolong(otmp);
-            mread(fd, (genericptr_t) OLONG(otmp), buflen);
+            if (nhfp->structlevel)
+                mread(nhfp->fd, (genericptr_t) OLONG(otmp), buflen);
+            if (nhfp->fieldlevel)
+                sfi_long(nhfp, OLONG(otmp), "obj", "olong", 1);
         }
+
         /* omailcmd - feedback mechanism for scroll of mail */
-        mread(fd, (genericptr_t) &buflen, sizeof(buflen));
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) &buflen, sizeof(buflen));
+        if (nhfp->fieldlevel)
+            sfi_int(nhfp, &buflen, "obj", "omailcmd_length", 1);
         if (buflen > 0) {
             char *omailcmd = (char *) alloc(buflen);
 
-            mread(fd, (genericptr_t) omailcmd, buflen);
+            if (nhfp->structlevel)
+                mread(nhfp->fd, (genericptr_t) omailcmd, buflen);
+            if (nhfp->fieldlevel)
+                sfi_str(nhfp, omailcmd, "obj", "omailcmd", buflen);
             new_omailcmd(otmp, omailcmd);
             free((genericptr_t) omailcmd);
         }
     }
 }
 
+/* SAVE2018 */
+
 STATIC_OVL struct obj *
-restobjchn(fd, ghostly, frozen)
-register int fd;
+restobjchn(nhfp, ghostly, frozen)
+NHFILE *nhfp;
 boolean ghostly, frozen;
 {
     register struct obj *otmp, *otmp2 = 0;
@@ -263,12 +333,16 @@ boolean ghostly, frozen;
     int buflen;
 
     while (1) {
-        mread(fd, (genericptr_t) &buflen, sizeof buflen);
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) &buflen, sizeof buflen);
+        if (nhfp->fieldlevel)
+            sfi_int(nhfp, &buflen, "obj",  "obj_length", 1);
+
         if (buflen == -1)
             break;
 
         otmp = newobj();
-        restobj(fd, otmp);
+        restobj(nhfp, otmp); /* SAVE2018 */
         if (!first)
             first = otmp;
         else
@@ -292,7 +366,7 @@ boolean ghostly, frozen;
         if (Has_contents(otmp)) {
             struct obj *otmp3;
 
-            otmp->cobj = restobjchn(fd, ghostly, Is_IceBox(otmp));
+            otmp->cobj = restobjchn(nhfp, ghostly, Is_IceBox(otmp));
             /* restore container back pointers */
             for (otmp3 = otmp->cobj; otmp3; otmp3 = otmp3->nobj)
                 otmp3->ocontainer = otmp;
@@ -339,15 +413,20 @@ boolean ghostly, frozen;
     return first;
 }
 
+/* SAVE2018 */
+
 /* restore one monster */
 STATIC_OVL void
-restmon(fd, mtmp)
-int fd;
+restmon(nhfp, mtmp)
+NHFILE *nhfp;
 struct monst *mtmp;
 {
     int buflen;
 
-    mread(fd, (genericptr_t) mtmp, sizeof(struct monst));
+    if (nhfp->structlevel)
+        mread(nhfp->fd, (genericptr_t) mtmp, sizeof(struct monst));
+    if (nhfp->fieldlevel)
+        sfi_monst(nhfp, mtmp, "mon", "monst_length", 1);
 
     /* next monster pointer is invalid */
     mtmp->nmon = (struct monst *) 0;
@@ -356,50 +435,92 @@ struct monst *mtmp;
         mtmp->mextra = newmextra();
 
         /* mname - monster's name */
-        mread(fd, (genericptr_t) &buflen, sizeof(buflen));
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) &buflen, sizeof(buflen));
+        if (nhfp->fieldlevel)
+            sfi_int(nhfp, &buflen, "mon", "mname_length", 1);
         if (buflen > 0) { /* includes terminating '\0' */
             new_mname(mtmp, buflen);
-            mread(fd, (genericptr_t) MNAME(mtmp), buflen);
+            if (nhfp->structlevel)
+                mread(nhfp->fd, (genericptr_t) MNAME(mtmp), buflen);
+            if (nhfp->fieldlevel)
+                sfi_str(nhfp, MNAME(mtmp), "mon", "mname", buflen);
         }
         /* egd - vault guard */
-        mread(fd, (genericptr_t) &buflen, sizeof(buflen));
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) &buflen, sizeof(buflen));
+        if (nhfp->fieldlevel)
+            sfi_int(nhfp, &buflen, "mon", "egd_length", 1);
+
         if (buflen > 0) {
             newegd(mtmp);
-            mread(fd, (genericptr_t) EGD(mtmp), sizeof(struct egd));
+            if (nhfp->structlevel)
+                mread(nhfp->fd, (genericptr_t) EGD(mtmp), sizeof(struct egd));
+            if (nhfp->fieldlevel)
+                sfi_egd(nhfp, EGD(mtmp), "mon", "egd", 1);
         }
         /* epri - temple priest */
-        mread(fd, (genericptr_t) &buflen, sizeof(buflen));
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) &buflen, sizeof(buflen));
+        if (nhfp->fieldlevel)
+            sfi_int(nhfp, &buflen, "mon", "epri_length", 1);
         if (buflen > 0) {
             newepri(mtmp);
-            mread(fd, (genericptr_t) EPRI(mtmp), sizeof(struct epri));
+            if (nhfp->structlevel)
+                mread(nhfp->fd, (genericptr_t) EPRI(mtmp), sizeof(struct epri));
+            if (nhfp->fieldlevel)
+                sfi_epri(nhfp, EPRI(mtmp), "mon", "epri", 1);
         }
         /* eshk - shopkeeper */
-        mread(fd, (genericptr_t) &buflen, sizeof(buflen));
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) &buflen, sizeof(buflen));
+        if (nhfp->fieldlevel)
+            sfi_int(nhfp, &buflen, "mon", "eshk_length", 1);
         if (buflen > 0) {
             neweshk(mtmp);
-            mread(fd, (genericptr_t) ESHK(mtmp), sizeof(struct eshk));
+            if (nhfp->structlevel)
+                mread(nhfp->fd, (genericptr_t) ESHK(mtmp), sizeof(struct eshk));
+            if (nhfp->fieldlevel)
+                sfi_eshk(nhfp, ESHK(mtmp), "mon", "eshk", 1);
         }
         /* emin - minion */
-        mread(fd, (genericptr_t) &buflen, sizeof(buflen));
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) &buflen, sizeof(buflen));
+        if (nhfp->fieldlevel)
+            sfi_int(nhfp, &buflen, "mon", "emin_length", 1);
         if (buflen > 0) {
             newemin(mtmp);
-            mread(fd, (genericptr_t) EMIN(mtmp), sizeof(struct emin));
+            if (nhfp->structlevel)
+                mread(nhfp->fd, (genericptr_t) EMIN(mtmp), sizeof(struct emin));
+            if (nhfp->fieldlevel)
+                sfi_emin(nhfp, EMIN(mtmp), "mon", "emin", 1);
         }
         /* edog - pet */
-        mread(fd, (genericptr_t) &buflen, sizeof(buflen));
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) &buflen, sizeof(buflen));
+        if (nhfp->fieldlevel)
+            sfi_int(nhfp, &buflen, "mon", "edog_length", 1);
         if (buflen > 0) {
             newedog(mtmp);
-            mread(fd, (genericptr_t) EDOG(mtmp), sizeof(struct edog));
+            if (nhfp->structlevel)
+                mread(nhfp->fd, (genericptr_t) EDOG(mtmp), sizeof(struct edog));
+            if (nhfp->fieldlevel)
+                sfi_edog(nhfp, EDOG(mtmp), "mon", "edog", 1);
         }
         /* mcorpsenm - obj->corpsenm for mimic posing as corpse or
            statue (inline int rather than pointer to something) */
-        mread(fd, (genericptr_t) &MCORPSENM(mtmp), sizeof MCORPSENM(mtmp));
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) &MCORPSENM(mtmp), sizeof MCORPSENM(mtmp));
+        if (nhfp->fieldlevel)
+            sfi_int(nhfp, &MCORPSENM(mtmp), "mon", "mcorpsenm", 1);
     } /* mextra */
 }
 
+/* SAVE2018 */
+
 STATIC_OVL struct monst *
-restmonchn(fd, ghostly)
-register int fd;
+restmonchn(nhfp, ghostly)
+NHFILE *nhfp;
 boolean ghostly;
 {
     register struct monst *mtmp, *mtmp2 = 0;
@@ -407,12 +528,15 @@ boolean ghostly;
     int offset, buflen;
 
     while (1) {
-        mread(fd, (genericptr_t) &buflen, sizeof(buflen));
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) &buflen, sizeof(buflen));
+        if (nhfp->fieldlevel)
+            sfi_int(nhfp, &buflen, "mon", "monst_length", 1);
         if (buflen == -1)
             break;
 
         mtmp = newmonst();
-        restmon(fd, mtmp);
+        restmon(nhfp, mtmp);
         if (!first)
             first = mtmp;
         else
@@ -434,7 +558,7 @@ boolean ghostly;
         }
         if (mtmp->minvent) {
             struct obj *obj;
-            mtmp->minvent = restobjchn(fd, ghostly, FALSE);
+            mtmp->minvent = restobjchn(nhfp, ghostly, FALSE);
             /* restore monster back pointer */
             for (obj = mtmp->minvent; obj; obj = obj->nobj)
                 obj->ocarry = mtmp;
@@ -471,17 +595,27 @@ boolean ghostly;
     return first;
 }
 
+/* SAVE2018 */
+
 STATIC_OVL struct fruit *
-loadfruitchn(fd)
-int fd;
+loadfruitchn(nhfp)
+NHFILE *nhfp;
 {
-    register struct fruit *flist, *fnext;
+    register struct fruit *flist, *fnext = (struct fruit *) 0;
+    boolean keepgoing;
 
     flist = 0;
-    while (fnext = newfruit(), mread(fd, (genericptr_t) fnext, sizeof *fnext),
-           fnext->fid != 0) {
-        fnext->nextf = flist;
-        flist = fnext;
+    keepgoing = TRUE;
+    while (fnext = newfruit(), keepgoing) {
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t)fnext, sizeof *fnext);
+        if (nhfp->fieldlevel)
+            sfi_fruit(nhfp, fnext, "fruit", "fruit", 1);
+        if (fnext->fid != 0) {
+            fnext->nextf = flist;
+            flist = fnext;
+        } else
+            keepgoing = FALSE;
     }
     dealloc_fruit(fnext);
     return flist;
@@ -524,8 +658,8 @@ register struct obj *otmp;
 
 STATIC_OVL
 boolean
-restgamestate(fd, stuckid, steedid)
-register int fd;
+restgamestate(nhfp, stuckid, steedid)
+NHFILE *nhfp;
 unsigned int *stuckid, *steedid;
 {
     struct flag newgameflags;
@@ -538,7 +672,14 @@ unsigned int *stuckid, *steedid;
     unsigned long uid;
     boolean defer_perm_invent;
 
-    mread(fd, (genericptr_t) &uid, sizeof uid);
+    if (nhfp->fieldlevel && nhfp->addinfo)
+        sfi_addinfo(nhfp, "gamestate", "start", "", 0);
+
+    if (nhfp->structlevel)
+        mread(nhfp->fd, (genericptr_t) &uid, sizeof uid);
+    if (nhfp->fieldlevel)
+        sfi_ulong(nhfp, &uid, "gamestate", "uid", 1);
+      
     if (SYSOPT_CHECK_SAVE_UID
         && uid != (unsigned long) getuid()) { /* strange ... */
         /* for wizard mode, issue a reminder; for others, treat it
@@ -549,7 +690,10 @@ unsigned int *stuckid, *steedid;
     }
 
     newgamecontext = g.context; /* copy statically init'd context */
-    mread(fd, (genericptr_t) &g.context, sizeof (struct context_info));
+    if (nhfp->structlevel)
+        mread(nhfp->fd, (genericptr_t) &g.context, sizeof (struct context_info));
+    if (nhfp->fieldlevel)
+        sfi_context_info(nhfp, &g.context, "gamestate", "g.context", 1);
     g.context.warntype.species = (g.context.warntype.speciesidx >= LOW_PM)
                                   ? &mons[g.context.warntype.speciesidx]
                                   : (struct permonst *) 0;
@@ -561,7 +705,11 @@ unsigned int *stuckid, *steedid;
        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;
-    mread(fd, (genericptr_t) &flags, sizeof (struct flag));
+    if (nhfp->structlevel)
+        mread(nhfp->fd, (genericptr_t) &flags, sizeof (struct flag));
+    if (nhfp->fieldlevel)
+        sfi_flag(nhfp, &flags, "gamestate", "flags", 1);
+
     /* avoid keeping permanent inventory window up to date during restore
        (setworn() calls update_inventory); attempting to include the cost
        of unpaid items before shopkeeper's bill is available is a no-no;
@@ -585,6 +733,10 @@ unsigned int *stuckid, *steedid;
     }
 #ifdef SYSFLAGS
     newgamesysflags = sysflags;
+    if (nhfp->structlevel)
+        mread(nhfp->fd, (genericptr_t) &sysflags, sizeof(struct sysflag));
+    if (nhfp->fieldlevel)
+        sfi_sysflag(nhfp, &sysflags, "gamestate", "sysflags", 1);
     mread(fd, (genericptr_t) &sysflags, sizeof(struct sysflag));
 #endif
 
@@ -592,17 +744,30 @@ unsigned int *stuckid, *steedid;
 #ifdef AMII_GRAPHICS
     amii_setpens(amii_numcolors); /* use colors from save file */
 #endif
-    mread(fd, (genericptr_t) &u, sizeof(struct you));
+    if (nhfp->structlevel)
+        mread(nhfp->fd, (genericptr_t) &u, sizeof(struct you));
+    if (nhfp->fieldlevel)
+        sfi_you(nhfp, &u, "gamestate", "you", 1);
     g.youmonst.cham = u.mcham;
+        
+    if (nhfp->structlevel)
+        mread(nhfp->fd, (genericptr_t) timebuf, 14);
+    if (nhfp->fieldlevel)
+        sfi_str(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->fieldlevel)
+        sfi_long(nhfp, &urealtime.realtime, "gamestate", "realtime", 1);
+
+    if (nhfp->structlevel)
+        mread(nhfp->fd, (genericptr_t) timebuf, 14);
+    if (nhfp->fieldlevel)
+        sfi_str(nhfp, timebuf, "gamestate", "start_timing", 14);
+    timebuf[14] = '\0';
+    urealtime.start_timing = time_from_yyyymmddhhmmss(timebuf);
 
-#define ReadTimebuf(foo)                   \
-    mread(fd, (genericptr_t) timebuf, 14); \
-    timebuf[14] = '\0';                    \
-    foo = time_from_yyyymmddhhmmss(timebuf);
-
-    ReadTimebuf(ubirthday);
-    mread(fd, &urealtime.realtime, sizeof urealtime.realtime);
-    ReadTimebuf(urealtime.start_timing); /** [not used] **/
     /* current time is the time to use for next urealtime.realtime update */
     urealtime.start_timing = getnow();
 
@@ -634,14 +799,17 @@ unsigned int *stuckid, *steedid;
     assign_level(&u.uz0, &u.uz);
 
     /* this stuff comes after potential aborted restore attempts */
-    restore_killers(fd);
-    restore_timers(fd, RANGE_GLOBAL, FALSE, 0L);
-    restore_light_sources(fd);
-    g.invent = restobjchn(fd, FALSE, FALSE);
+    restore_killers(nhfp);
+    restore_timers(nhfp, RANGE_GLOBAL, FALSE, 0L);
+    restore_light_sources(nhfp);
+
+    if (nhfp->fieldlevel && nhfp->addinfo)
+        sfi_addinfo(nhfp, "objchain", "start", "invent", 0);
+    g.invent = restobjchn(nhfp, FALSE, FALSE);
     /* tmp_bc only gets set here if the ball & chain were orphaned
        because you were swallowed; otherwise they will be on the floor
        or in your inventory */
-    tmp_bc = restobjchn(fd, FALSE, FALSE);
+    tmp_bc = restobjchn(nhfp, FALSE, FALSE);
     if (tmp_bc) {
         for (otmp = tmp_bc; otmp; otmp = otmp->nobj) {
             if (otmp->owornmask)
@@ -650,10 +818,18 @@ unsigned int *stuckid, *steedid;
         if (!uball || !uchain)
             impossible("restgamestate: lost ball & chain");
     }
+    g.migrating_objs = restobjchn(nhfp, FALSE, FALSE);
+    g.migrating_mons = restmonchn(nhfp, FALSE);
+
+    if (nhfp->structlevel) {
+        mread(nhfp->fd, (genericptr_t) g.mvitals, sizeof(g.mvitals));
+    }
+    if (nhfp->fieldlevel) {
+        int i;
 
-    g.migrating_objs = restobjchn(fd, FALSE, FALSE);
-    g.migrating_mons = restmonchn(fd, FALSE);
-    mread(fd, (genericptr_t) g.mvitals, sizeof(g.mvitals));
+        for (i = 0; i < NUMMONS; ++i)
+            sfi_mvitals(nhfp, &g.mvitals[i], "gamestate", "g.mvitals", 1);
+    }
 
     /*
      * There are some things after this that can have unintended display
@@ -676,27 +852,55 @@ unsigned int *stuckid, *steedid;
     if (!uwep || uwep->otyp == PICK_AXE || uwep->otyp == GRAPPLING_HOOK)
         g.unweapon = TRUE;
 
-    restore_dungeon(fd);
-    restlevchn(fd);
-    mread(fd, (genericptr_t) &g.moves, sizeof g.moves);
-    mread(fd, (genericptr_t) &g.monstermoves, sizeof g.monstermoves);
-    mread(fd, (genericptr_t) &g.quest_status, sizeof (struct q_score));
-    mread(fd, (genericptr_t) g.spl_book, (MAXSPELL + 1) * sizeof (struct spell));
-    restore_artifacts(fd);
-    restore_oracles(fd);
-    if (u.ustuck)
-        mread(fd, (genericptr_t) stuckid, sizeof *stuckid);
-    if (u.usteed)
-        mread(fd, (genericptr_t) steedid, sizeof *steedid);
-    mread(fd, (genericptr_t) g.pl_character, sizeof g.pl_character);
-
-    mread(fd, (genericptr_t) g.pl_fruit, sizeof g.pl_fruit);
+    restore_dungeon(nhfp);
+    restlevchn(nhfp);
+    if (nhfp->structlevel) {
+        mread(nhfp->fd, (genericptr_t) &g.moves, sizeof g.moves);
+        mread(nhfp->fd, (genericptr_t) &g.monstermoves, sizeof g.monstermoves);
+        mread(nhfp->fd, (genericptr_t) &g.quest_status, sizeof (struct q_score));
+        mread(nhfp->fd, (genericptr_t) g.spl_book, (MAXSPELL + 1) * sizeof (struct spell));
+    }
+    if (nhfp->fieldlevel) {
+        int i;
+        struct spell *sptmp;
+
+        sfi_long(nhfp, &g.moves, "gamestate", "g.moves", 1);
+        sfi_long(nhfp, &g.monstermoves, "gamestate", "g.monstermoves", 1);
+        sfi_q_score(nhfp, &g.quest_status, "gamestate", "g.quest_status", 1);
+        sptmp = g.spl_book;
+        for (i = 0; i < (MAXSPELL + 1); ++i)
+            sfi_spell(nhfp, sptmp++, "gamestate", "g.spl_book", 1);
+    }        
+    restore_artifacts(nhfp);
+    restore_oracles(nhfp);
+    if (u.ustuck) {
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) stuckid, sizeof *stuckid);
+        if (nhfp->fieldlevel)
+            sfi_unsigned(nhfp, stuckid, "gamestate", "ustuck_id", 1);
+    }
+    if (u.usteed) {
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) steedid, sizeof *steedid);
+        if (nhfp->fieldlevel)
+            sfi_unsigned(nhfp, steedid, "gamestate", "usteed_id", 1);
+    }
+    if (nhfp->structlevel) {
+        mread(nhfp->fd, (genericptr_t) g.pl_character, sizeof g.pl_character);
+        mread(nhfp->fd, (genericptr_t) g.pl_fruit, sizeof g.pl_fruit);
+    }
+    if (nhfp->fieldlevel) {
+        sfi_char(nhfp, g.pl_character, "gamestate", "g.pl_character",
+                 sizeof g.pl_character);
+        sfi_char(nhfp, g.pl_fruit, "gamestate", "g.pl_fruit",
+                 sizeof g.pl_fruit);
+    }
     freefruitchn(g.ffruit); /* clean up fruit(s) made by initoptions() */
-    g.ffruit = loadfruitchn(fd);
-
-    restnames(fd);
-    restore_waterlevel(fd);
-    restore_msghistory(fd);
+    g.ffruit = loadfruitchn(nhfp);
+  
+    restnames(nhfp);
+    restore_waterlevel(nhfp);
+    restore_msghistory(nhfp);
     /* must come after all mons & objs are restored */
     relink_timers(FALSE);
     relink_light_sources(FALSE);
@@ -735,24 +939,29 @@ unsigned int stuckid, steedid;
 
 /*ARGSUSED*/
 STATIC_OVL int
-restlevelfile(fd, ltmp)
-int fd; /* fd used in MFLOPPY only */
+restlevelfile(nhfp, ltmp)
+NHFILE *nhfp; /* used in MFLOPPY only */
 xchar ltmp;
 {
-    int nfd;
     char whynot[BUFSZ];
+#ifdef MFLOPPY
+    int savemode;
+#endif
+    NHFILE *nnhfp = (NHFILE *) 0;
 
 #ifndef MFLOPPY
-    nhUse(fd);
+    nhUse(nhfp);
 #endif
-    nfd = create_levelfile(ltmp, whynot);
-    if (nfd < 0) {
+    nnhfp = create_levelfile(ltmp, whynot);
+    if (!nnhfp) {
         /* BUG: should suppress any attempt to write a panic
            save file if file creation is now failing... */
         panic("restlevelfile: %s", whynot);
     }
 #ifdef MFLOPPY
-    if (!savelev(nfd, ltmp, COUNT_SAVE)) {
+    savemode = nnhfp->mode;
+    nnhfp->mode = COUNTING;
+    if (!savelev(nnhfp, ltmp)) {
         /* The savelev can't proceed because the size required
          * is greater than the available disk space.
          */
@@ -760,7 +969,7 @@ xchar ltmp;
 
         /* Remove levels and bones that may have been created.
          */
-        (void) nhclose(nfd);
+        close_nhfile(nnhfp);
 #ifdef AMIGA
         clearlocks();
 #else /* !AMIGA */
@@ -776,24 +985,25 @@ xchar ltmp;
              */
             playwoRAMdisk();
             /* Rewind save file and try again */
-            (void) lseek(fd, (off_t) 0, 0);
-            (void) validate(fd, (char *) 0); /* skip version etc */
-            return dorecover(fd);            /* 0 or 1 */
+            rewind_nhfile(nhfp);
+            (void) validate(nhfp, (char *) 0); /* skip version etc */
+            return dorecover(nhfp);            /* 0 or 1 */
         }
 #endif /* ?AMIGA */
         pline("Be seeing you...");
         nh_terminate(EXIT_SUCCESS);
     }
 #endif /* MFLOPPY */
-    bufon(nfd);
-    savelev(nfd, ltmp, WRITE_SAVE | FREE_SAVE);
-    bclose(nfd);
+    bufon(nnhfp->fd);
+    nnhfp->mode = WRITING | FREEING;
+    savelev(nnhfp, ltmp);
+    close_nhfile(nnhfp);
     return 2;
 }
 
 int
-dorecover(fd)
-register int fd;
+dorecover(nhfp)
+NHFILE *nhfp;
 {
     unsigned int stuckid = 0, steedid = 0; /* not a register */
     xchar ltmp;
@@ -801,12 +1011,19 @@ register int fd;
     struct obj *otmp;
 
     g.restoring = TRUE;
-    get_plname_from_file(fd, g.plname);
-    getlev(fd, 0, (xchar) 0, FALSE);
-    if (!restgamestate(fd, &stuckid, &steedid)) {
+    get_plname_from_file(nhfp, g.plname);
+    getlev(nhfp, 0, (xchar) 0, FALSE);
+    if (!restgamestate(nhfp, &stuckid, &steedid)) {
+        NHFILE tnhfp;
+
         display_nhwindow(WIN_MESSAGE, TRUE);
-        savelev(-1, 0, FREE_SAVE); /* discard current level */
-        (void) nhclose(fd);
+        zero_nhfile(&tnhfp);
+        tnhfp.mode = FREEING;
+        tnhfp.fd = -1;
+        savelev(&tnhfp, 0); /* discard current level */
+        /* no need tfor close_nhfile(&tnhfp), which
+           is not really affiliated with an open file */
+        close_nhfile(nhfp);
         (void) delete_savefile();
         g.restoring = FALSE;
         return 0;
@@ -815,7 +1032,7 @@ register int fd;
 #ifdef INSURANCE
     savestateinlock();
 #endif
-    rtmp = restlevelfile(fd, ledger_no(&u.uz));
+    rtmp = restlevelfile(nhfp, ledger_no(&u.uz));
     if (rtmp < 2)
         return rtmp; /* dorecover called recursively */
 
@@ -852,10 +1069,17 @@ register int fd;
 #endif
     restoreprocs.mread_flags = 1; /* return despite error */
     while (1) {
-        mread(fd, (genericptr_t) &ltmp, sizeof ltmp);
-        if (restoreprocs.mread_flags == -1)
-            break;
-        getlev(fd, 0, ltmp, FALSE);
+        if (nhfp->structlevel) {
+            mread(nhfp->fd, (genericptr_t) &ltmp, sizeof ltmp);
+            if (restoreprocs.mread_flags == -1)
+                break;
+        }
+        if (nhfp->fieldlevel) {
+            sfi_xchar(nhfp, &ltmp, "gamestate", "level_number", 1);
+            if (nhfp->eof)
+                break;
+       }
+        getlev(nhfp, 0, ltmp, FALSE);
 #ifdef MICRO
         curs(WIN_MAP, 1 + dotcnt++, dotrow);
         if (dotcnt >= (COLNO - 1)) {
@@ -867,23 +1091,20 @@ register int fd;
         }
         mark_synch();
 #endif
-        rtmp = restlevelfile(fd, ltmp);
+        rtmp = restlevelfile(nhfp, ltmp);
         if (rtmp < 2)
             return rtmp; /* dorecover called recursively */
     }
     restoreprocs.mread_flags = 0;
+    if (nhfp->fieldlevel && nhfp->addinfo)
+        sfi_addinfo(nhfp, "NetHack", "end", "savefile", 0);
 
-#ifdef BSD
-    (void) lseek(fd, 0L, 0);
-#else
-    (void) lseek(fd, (off_t) 0, 0);
-#endif
-    (void) validate(fd, (char *) 0); /* skip version and savefile info */
-    get_plname_from_file(fd, g.plname);
-
-    getlev(fd, 0, (xchar) 0, FALSE);
-    (void) nhclose(fd);
+    rewind_nhfile(nhfp);        /* return to beginning of file */
+    (void) validate(nhfp, (char *) 0);
+    get_plname_from_file(nhfp, g.plname);
 
+    getlev(nhfp, 0, (xchar) 0, FALSE);
+    close_nhfile(nhfp);
     /* Now set the restore settings to match the
      * settings used by the save file output routines
      */
@@ -933,20 +1154,28 @@ register int fd;
     return 1;
 }
 
+/* SAVE2018 */
+
 void
-restcemetery(fd, cemeteryaddr)
-int fd;
+restcemetery(nhfp, cemeteryaddr)
+NHFILE *nhfp;
 struct cemetery **cemeteryaddr;
 {
     struct cemetery *bonesinfo, **bonesaddr;
-    int flag;
+    int cflag;
 
-    mread(fd, (genericptr_t) &flag, sizeof flag);
-    if (flag == 0) {
+    if (nhfp->structlevel)
+        mread(nhfp->fd, (genericptr_t) &cflag, sizeof cflag);
+    if (nhfp->fieldlevel)
+        sfi_int(nhfp, &cflag, "cemetery", "cemetery_flag", 1);
+    if (cflag == 0) {
         bonesaddr = cemeteryaddr;
         do {
             bonesinfo = (struct cemetery *) alloc(sizeof *bonesinfo);
-            mread(fd, (genericptr_t) bonesinfo, sizeof *bonesinfo);
+            if (nhfp->structlevel)
+                mread(nhfp->fd, (genericptr_t) bonesinfo, sizeof *bonesinfo);
+            if (nhfp->fieldlevel)
+                sfi_cemetery(nhfp, bonesinfo, "bones", "bonesinfo", 1);
             *bonesaddr = bonesinfo;
             bonesaddr = &(*bonesaddr)->next;
         } while (*bonesaddr);
@@ -955,10 +1184,12 @@ struct cemetery **cemeteryaddr;
     }
 }
 
+/* SAVE2018 */
+
 /*ARGSUSED*/
 STATIC_OVL void
-rest_levl(fd, rlecomp)
-int fd;
+rest_levl(nhfp, rlecomp)
+NHFILE *nhfp;
 boolean rlecomp;
 {
 #ifdef RLECOMP
@@ -978,8 +1209,14 @@ boolean rlecomp;
                     len -= 1;
                     j += 1;
                 } else {
-                    mread(fd, (genericptr_t) &len, sizeof(uchar));
-                    mread(fd, (genericptr_t) &r, sizeof(struct rm));
+                    if (nhfp->structlevel) {
+                        mread(nhfp->fd, (genericptr_t) &len, sizeof(uchar));
+                        mread(nhfp->fd, (genericptr_t) &r, sizeof(struct rm));
+                    }
+                    if (nhfp->fieldlevel) {
+                        sfi_uchar(nhfp, &len, "room", "levl", 1);
+                        sfi_rm(nhfp, &r, "room", "rm", 1);
+                    }
                 }
             }
             j = 0;
@@ -990,7 +1227,16 @@ boolean rlecomp;
 #else /* !RLECOMP */
     nhUse(rlecomp);
 #endif /* ?RLECOMP */
-    mread(fd, (genericptr_t) levl, sizeof levl);
+    if (nhfp->structlevel) {
+        mread(nhfp->fd, (genericptr_t) levl, sizeof levl);
+    }
+    if (nhfp->fieldlevel) {
+        int c, r;
+
+        for (c = 0; c < COLNO; ++c)
+            for (r = 0; r < ROWNO; ++r)    
+                sfi_rm(nhfp, &levl[c][r], "room", "levl", 1);
+    }
 }
 
 void
@@ -1005,8 +1251,9 @@ char *reason;
 }
 
 void
-getlev(fd, pid, lev, ghostly)
-int fd, pid;
+getlev(nhfp, pid, lev, ghostly)
+NHFILE *nhfp;
+int pid;
 xchar lev;
 boolean ghostly;
 {
@@ -1017,6 +1264,7 @@ boolean ghostly;
     int hpid;
     xchar dlvl;
     int x, y;
+    boolean keepgoing;
 #ifdef TOS
     short tlev;
 #endif
@@ -1025,22 +1273,33 @@ boolean ghostly;
         clear_id_mapping();
 
 #if defined(MSDOS) || defined(OS2)
-    setmode(fd, O_BINARY);
+    if (nhfp->structlevel)
+        setmode(nhfp->fd, O_BINARY);
 #endif
     /* Load the old fruit info.  We have to do it first, so the
      * information is available when restoring the objects.
      */
     if (ghostly)
-        g.oldfruit = loadfruitchn(fd);
+        g.oldfruit = loadfruitchn(nhfp);
 
     /* First some sanity checks */
-    mread(fd, (genericptr_t) &hpid, sizeof(hpid));
+    if (nhfp->structlevel)
+        mread(nhfp->fd, (genericptr_t) &hpid, sizeof(hpid));
+    if (nhfp->fieldlevel)
+        sfi_int(nhfp, &hpid, "gamestate", "g.hackpid", 1);
+
 /* CHECK:  This may prevent restoration */
 #ifdef TOS
-    mread(fd, (genericptr_t) &tlev, sizeof(tlev));
+    if (nhfp->structlevel)
+        mread(nhfp->fd, (genericptr_t) &tlev, sizeof(tlev));
+    if (nhfp->fieldlevel)
+        sfi_short(nhfp, &tlev, "gamestate", "tlev", 1);
     dlvl = tlev & 0x00ff;
 #else
-    mread(fd, (genericptr_t) &dlvl, sizeof(dlvl));
+    if (nhfp->structlevel)
+        mread(nhfp->fd, (genericptr_t) &dlvl, sizeof(dlvl));
+    if (nhfp->fieldlevel)
+        sfi_xchar(nhfp, &dlvl, "gamestate", "dlvl", 1);
 #endif
     if ((pid && pid != hpid) || (lev && dlvl != lev)) {
         char trickbuf[BUFSZ];
@@ -1054,47 +1313,82 @@ boolean ghostly;
             pline1(trickbuf);
         trickery(trickbuf);
     }
-    restcemetery(fd, &g.level.bonesinfo);
-    rest_levl(fd,
+    restcemetery(nhfp, &g.level.bonesinfo);
+    rest_levl(nhfp,
               (boolean) ((sfrestinfo.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP));
-    mread(fd, (genericptr_t) g.lastseentyp, sizeof(g.lastseentyp));
-    mread(fd, (genericptr_t) &g.omoves, sizeof(g.omoves));
+    if (nhfp->structlevel) {
+        mread(nhfp->fd, (genericptr_t) g.lastseentyp, sizeof(g.lastseentyp));
+        mread(nhfp->fd, (genericptr_t) &g.omoves, sizeof(g.omoves));
+    }
+    if (nhfp->fieldlevel) {
+        int c, r;
+
+        for (c = 0; c < COLNO; ++c)
+            for (r = 0; r < ROWNO; ++r)
+                sfi_schar(nhfp, &g.lastseentyp[c][r], "lev", "g.lastseentyp", 1);
+
+        sfi_long(nhfp, &g.omoves, "lev", "timestmp", 1);
+    }
     elapsed = g.monstermoves - g.omoves;
-    mread(fd, (genericptr_t) &g.upstair, sizeof(stairway));
-    mread(fd, (genericptr_t) &g.dnstair, sizeof(stairway));
-    mread(fd, (genericptr_t) &g.upladder, sizeof(stairway));
-    mread(fd, (genericptr_t) &g.dnladder, sizeof(stairway));
-    mread(fd, (genericptr_t) &g.sstairs, sizeof(stairway));
-    mread(fd, (genericptr_t) &g.updest, sizeof(dest_area));
-    mread(fd, (genericptr_t) &g.dndest, sizeof(dest_area));
-    mread(fd, (genericptr_t) &g.level.flags, sizeof(g.level.flags));
-    mread(fd, (genericptr_t) g.doors, sizeof(g.doors));
-    rest_rooms(fd); /* No joke :-) */
+
+    if (nhfp->structlevel) {
+        mread(nhfp->fd, (genericptr_t)&g.upstair, sizeof(stairway));
+        mread(nhfp->fd, (genericptr_t)&g.dnstair, sizeof(stairway));
+        mread(nhfp->fd, (genericptr_t)&g.upladder, sizeof(stairway));
+        mread(nhfp->fd, (genericptr_t)&g.dnladder, sizeof(stairway));
+        mread(nhfp->fd, (genericptr_t)&g.sstairs, sizeof(stairway));
+        mread(nhfp->fd, (genericptr_t)&g.updest, sizeof(dest_area));
+        mread(nhfp->fd, (genericptr_t)&g.dndest, sizeof(dest_area));
+        mread(nhfp->fd, (genericptr_t)&g.level.flags, sizeof(g.level.flags));
+        mread(nhfp->fd, (genericptr_t)g.doors, sizeof(g.doors));
+    }
+    if (nhfp->fieldlevel) {
+        int i;
+
+        sfi_stairway(nhfp, &g.upstair, "lev", "g.upstair", 1);
+        sfi_stairway(nhfp, &g.dnstair, "lev", "g.dnstair", 1);
+        sfi_stairway(nhfp, &g.upladder, "lev", "g.upladder", 1);
+        sfi_stairway(nhfp, &g.dnladder, "lev", "g.dnladder", 1);
+        sfi_stairway(nhfp, &g.sstairs, "lev", "g.sstairs", 1);
+        sfi_dest_area(nhfp, &g.updest, "lev", "g.updest", 1);
+        sfi_dest_area(nhfp, &g.dndest, "lev", "g.dndest", 1);
+        sfi_levelflags(nhfp, &g.level.flags, "lev", "g.level.flags", 1);
+        for (i = 0; i < DOORMAX; ++i)
+            sfi_nhcoord(nhfp, &g.doors[i], "lev", "g.doors", 1);
+    }
+    rest_rooms(nhfp); /* No joke :-) */
     if (g.nroom)
         g.doorindex = g.rooms[g.nroom - 1].fdoor + g.rooms[g.nroom - 1].doorct;
     else
         g.doorindex = 0;
+  
+    restore_timers(nhfp, RANGE_LEVEL, ghostly, elapsed);
+    restore_light_sources(nhfp);
+    fmon = restmonchn(nhfp, ghostly);
 
-    restore_timers(fd, RANGE_LEVEL, ghostly, elapsed);
-    restore_light_sources(fd);
-    fmon = restmonchn(fd, ghostly);
-
-    rest_worm(fd); /* restore worm information */
+    /* rest_worm(fd); */    /* restore worm information */
+    rest_worm(nhfp);    /* restore worm information */
     g.ftrap = 0;
-    while (trap = newtrap(),
-           mread(fd, (genericptr_t) trap, sizeof(struct trap)),
-           trap->tx != 0) { /* need "!= 0" to work around DICE 3.0 bug */
-        trap->ntrap = g.ftrap;
-        g.ftrap = trap;
+    keepgoing = TRUE;
+    while (trap = newtrap(), keepgoing) {
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t)trap, sizeof(struct trap));
+        if (nhfp->fieldlevel)
+            sfi_trap(nhfp, trap, "trap", "trap", 1);
+        if (trap->tx != 0) {
+            trap->ntrap = g.ftrap;
+            g.ftrap = trap;
+        } else
+            keepgoing = FALSE;
     }
     dealloc_trap(trap);
-    fobj = restobjchn(fd, ghostly, FALSE);
+    fobj = restobjchn(nhfp, ghostly, FALSE);    /* SAVE2018 */
     find_lev_obj();
     /* restobjchn()'s `frozen' argument probably ought to be a callback
        routine so that we can check for objects being buried under ice */
-    g.level.buriedobjlist = restobjchn(fd, ghostly, FALSE);
-    g.billobjs = restobjchn(fd, ghostly, FALSE);
-    rest_engravings(fd);
+    g.level.buriedobjlist = restobjchn(nhfp, ghostly, FALSE);
+    g.billobjs = restobjchn(nhfp, ghostly, FALSE);
+    rest_engravings(nhfp);
 
     /* reset level.monsters for new level */
     for (x = 0; x < COLNO; x++)
@@ -1130,9 +1424,9 @@ boolean ghostly;
         if (ghostly || elapsed > (long) rnd(10))
             hide_monst(mtmp);
     }
+    restdamage(nhfp, ghostly);
+    rest_regions(nhfp, ghostly);
 
-    restdamage(fd, ghostly);
-    rest_regions(fd, ghostly);
     if (ghostly) {
         /* Now get rid of all the temp fruits... */
         freefruitchn(g.oldfruit), g.oldfruit = 0;
@@ -1192,31 +1486,58 @@ boolean ghostly;
         clear_id_mapping();
 }
 
+/* SAVE2018 */
+
 void
-get_plname_from_file(fd, plbuf)
-int fd;
+get_plname_from_file(nhfp, plbuf)
+NHFILE *nhfp;
 char *plbuf;
 {
     int pltmpsiz = 0;
-    (void) read(fd, (genericptr_t) &pltmpsiz, sizeof(pltmpsiz));
-    (void) read(fd, (genericptr_t) plbuf, pltmpsiz);
+
+    if (nhfp->structlevel) {
+        (void) read(nhfp->fd, (genericptr_t) &pltmpsiz, sizeof(pltmpsiz));
+        (void) read(nhfp->fd, (genericptr_t) plbuf, pltmpsiz);
+    }
+    if (nhfp->fieldlevel) {
+#if 0
+        if ((nhfp->mode & WRITING) != 0) {
+#endif
+            sfi_int(nhfp, &pltmpsiz, "plname", "plname_size", 1);
+            sfi_str(nhfp, plbuf, "plname", "g.plname", pltmpsiz);
+#if 0
+        } else {
+            /* int rlen; */
+            (void) read(nhfp->fd, (genericptr_t) &pltmpsiz, sizeof(pltmpsiz));
+            (void) read(nhfp->fd, (genericptr_t) plbuf, pltmpsiz);
+        }
+#endif
+    }
     return;
 }
 
+/* SAVE2018 */
+
 STATIC_OVL void
-restore_msghistory(fd)
-register int fd;
+restore_msghistory(nhfp)
+NHFILE *nhfp;
 {
     int msgsize, msgcount = 0;
     char msg[BUFSZ];
 
     while (1) {
-        mread(fd, (genericptr_t) &msgsize, sizeof(msgsize));
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) &msgsize, sizeof(msgsize));
+        if (nhfp->fieldlevel)
+            sfi_int(nhfp, &msgsize, "msghistory", "msghistory_length", 1);
         if (msgsize == -1)
             break;
         if (msgsize > (BUFSZ - 1))
             panic("restore_msghistory: msg too big (%d)", msgsize);
-        mread(fd, (genericptr_t) msg, msgsize);
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) msg, msgsize);
+        if (nhfp->fieldlevel)
+            sfi_str(nhfp, msg, "msghistory", "msg", msgsize);
         msg[msgsize] = '\0';
         putmsghistory(msg, TRUE);
         ++msgcount;
@@ -1401,6 +1722,16 @@ register int fd;
 register genericptr_t buf;
 register unsigned int len;
 {
+
+#ifdef TROUBLESHOOTING
+    int n;
+    static int mcatch;
+    n = mcatch;
+again:
+    mcatch=rn2(500);
+    if (mcatch == n) goto again;
+#endif
+
     (*restoreprocs.restore_mread)(fd, buf, len);
     return;
 }
@@ -1412,76 +1743,86 @@ register unsigned int len;
    Return 2 if it failed the savefile feature check.
    Return -1 if it failed for some unknown reason.
  */
+
 int
-validate(fd, name)
-int fd;
+validate(nhfp, name)
+NHFILE *nhfp;
 const char *name;
 {
     int rlen;
     struct savefile_info sfi;
-    unsigned long compatible;
+    unsigned long compatible, utdflags = 0L;
     boolean verbose = name ? TRUE : FALSE, reslt = FALSE;
 
-    if (!(reslt = uptodate(fd, name)))
-        return 1;
-
-    rlen = read(fd, (genericptr_t) &sfi, sizeof sfi);
-    minit(); /* ZEROCOMP */
-    if (rlen == 0) {
-        if (verbose) {
-            pline("File \"%s\" is empty during save file feature check?",
-                  name);
-            wait_synch();
+    if (nhfp->structlevel)
+        utdflags |= UTD_CHECKSIZES;
+    if (nhfp->fieldlevel)
+        utdflags |= UTD_CHECKFIELDCOUNTS |
+                    UTD_SKIP_SANITY1 | UTD_SKIP_SAVEFILEINFO;
+    if (!(reslt = uptodate(nhfp, name, utdflags))) return 1;
+
+    if ((nhfp->mode & WRITING) == 0) {
+       if (nhfp->structlevel)
+            rlen = read(nhfp->fd, (genericptr_t) &sfi, sizeof sfi);
+        if (nhfp->fieldlevel)
+           sfi_savefile_info(nhfp, &sfi, "savefileinfo", "savefile_info", 1);
+    } else {
+        if (nhfp->structlevel)
+            rlen = read(nhfp->fd, (genericptr_t) &sfi, sizeof sfi);
+        if (nhfp->fieldlevel)
+            sfi_savefile_info(nhfp, &sfi, "savefileinfo", "savefile_info", 1);
+        minit();               /* ZEROCOMP */
+        if (rlen == 0) {
+           if (verbose) {
+               pline("File \"%s\" is empty during save file feature check?", name);
+               wait_synch();
+           }
+           return -1;
         }
-        return -1;
     }
+    if ((utdflags & UTD_SKIP_SAVEFILEINFO) != 0)
+        return 0;
 
     compatible = (sfi.sfi1 & sfcap.sfi1);
-
     if ((sfi.sfi1 & SFI1_ZEROCOMP) == SFI1_ZEROCOMP) {
-        if ((compatible & SFI1_ZEROCOMP) != SFI1_ZEROCOMP) {
-            if (verbose) {
-                pline("File \"%s\" has incompatible ZEROCOMP compression.",
-                      name);
-                wait_synch();
-            }
-            return 2;
-        } else if ((sfrestinfo.sfi1 & SFI1_ZEROCOMP) != SFI1_ZEROCOMP) {
-            set_restpref("zerocomp");
-        }
+       if ((compatible & SFI1_ZEROCOMP) != SFI1_ZEROCOMP) {
+           if (verbose) {
+               pline("File \"%s\" has incompatible ZEROCOMP compression.", name);
+               wait_synch();
+           }
+           return 2;
+       } else if ((sfrestinfo.sfi1 & SFI1_ZEROCOMP) != SFI1_ZEROCOMP) {
+           set_restpref("zerocomp");
+       }
     }
 
     if ((sfi.sfi1 & SFI1_EXTERNALCOMP) == SFI1_EXTERNALCOMP) {
-        if ((compatible & SFI1_EXTERNALCOMP) != SFI1_EXTERNALCOMP) {
-            if (verbose) {
-                pline("File \"%s\" lacks required internal compression.",
-                      name);
-                wait_synch();
-            }
-            return 2;
-        } else if ((sfrestinfo.sfi1 & SFI1_EXTERNALCOMP)
-                   != SFI1_EXTERNALCOMP) {
-            set_restpref("externalcomp");
-        }
+       if ((compatible & SFI1_EXTERNALCOMP) != SFI1_EXTERNALCOMP) {
+           if (verbose) {
+               pline("File \"%s\" lacks required internal compression.", name);
+               wait_synch();
+           }
+           return 2;
+       } else if ((sfrestinfo.sfi1 & SFI1_EXTERNALCOMP) != SFI1_EXTERNALCOMP) {
+           set_restpref("externalcomp");
+       }
     }
 
-    /* RLECOMP check must be last, after ZEROCOMP or INTERNALCOMP adjustments
-     */
+    /* RLECOMP check must be last, after ZEROCOMP or INTERNALCOMP adjustments */
     if ((sfi.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP) {
-        if ((compatible & SFI1_RLECOMP) != SFI1_RLECOMP) {
-            if (verbose) {
-                pline("File \"%s\" has incompatible run-length compression.",
-                      name);
-                wait_synch();
-            }
-            return 2;
-        } else if ((sfrestinfo.sfi1 & SFI1_RLECOMP) != SFI1_RLECOMP) {
-            set_restpref("rlecomp");
+       if ((compatible & SFI1_RLECOMP) != SFI1_RLECOMP) {
+           if (verbose) {
+               pline("File \"%s\" has incompatible run-length compression.", name);
+               wait_synch();
+           }
+           return 2;
+       } else if ((sfrestinfo.sfi1 & SFI1_RLECOMP) != SFI1_RLECOMP) {
+           set_restpref("rlecomp");
         }
     }
     /* savefile does not have RLECOMP level location compression, so adjust */
     else
-        set_restpref("!rlecomp");
+       set_restpref("!rlecomp");
 
     return 0;
 }
@@ -1490,53 +1831,53 @@ void
 reset_restpref()
 {
 #ifdef ZEROCOMP
-    if (iflags.zerocomp)
-        set_restpref("zerocomp");
-    else
+       if (iflags.zerocomp)
+               set_restpref("zerocomp");
+       else 
 #endif
-        set_restpref("externalcomp");
+               set_restpref("externalcomp");
 #ifdef RLECOMP
-    if (iflags.rlecomp)
-        set_restpref("rlecomp");
-    else
+       if (iflags.rlecomp)
+               set_restpref("rlecomp");
+       else
 #endif
-        set_restpref("!rlecomp");
+               set_restpref("!rlecomp");
 }
 
 void
 set_restpref(suitename)
 const char *suitename;
 {
-    if (!strcmpi(suitename, "externalcomp")) {
-        restoreprocs.name = "externalcomp";
-        restoreprocs.restore_mread = def_mread;
-        restoreprocs.restore_minit = def_minit;
-        sfrestinfo.sfi1 |= SFI1_EXTERNALCOMP;
-        sfrestinfo.sfi1 &= ~SFI1_ZEROCOMP;
-        def_minit();
-    }
-    if (!strcmpi(suitename, "!rlecomp")) {
-        sfrestinfo.sfi1 &= ~SFI1_RLECOMP;
-    }
+       if (!strcmpi(suitename, "externalcomp")) {
+               restoreprocs.name = "externalcomp";
+               restoreprocs.restore_mread = def_mread;
+               restoreprocs.restore_minit = def_minit;
+               sfrestinfo.sfi1 |= SFI1_EXTERNALCOMP;
+               sfrestinfo.sfi1 &= ~SFI1_ZEROCOMP;
+               def_minit();
+       }
+       if (!strcmpi(suitename, "!rlecomp")) {
+               sfrestinfo.sfi1 &= ~SFI1_RLECOMP;
+       }
 #ifdef ZEROCOMP
-    if (!strcmpi(suitename, "zerocomp")) {
-        restoreprocs.name = "zerocomp";
-        restoreprocs.restore_mread = zerocomp_mread;
-        restoreprocs.restore_minit = zerocomp_minit;
-        sfrestinfo.sfi1 |= SFI1_ZEROCOMP;
-        sfrestinfo.sfi1 &= ~SFI1_EXTERNALCOMP;
-        zerocomp_minit();
-    }
+       if (!strcmpi(suitename, "zerocomp")) {
+               restoreprocs.name = "zerocomp";
+               restoreprocs.restore_mread = zerocomp_mread;
+               restoreprocs.restore_minit = zerocomp_minit;
+               sfrestinfo.sfi1 |= SFI1_ZEROCOMP;
+               sfrestinfo.sfi1 &= ~SFI1_EXTERNALCOMP;
+               zerocomp_minit();
+       }
 #endif
 #ifdef RLECOMP
-    if (!strcmpi(suitename, "rlecomp")) {
-        sfrestinfo.sfi1 |= SFI1_RLECOMP;
-    }
+       if (!strcmpi(suitename, "rlecomp")) {
+               sfrestinfo.sfi1 |= SFI1_RLECOMP;
+       }
 #endif
 }
 
 #ifdef ZEROCOMP
-#define RLESC '\0' /* Leading character for run of RLESC's */
+#define RLESC '\0'     /* Leading character for run of RLESC's */
 
 #ifndef ZEROCOMP_BUFSIZ
 #define ZEROCOMP_BUFSIZ BUFSZ
@@ -1551,14 +1892,14 @@ STATIC_OVL int
 zerocomp_mgetc()
 {
     if (inbufp >= inbufsz) {
-        inbufsz = read(mreadfd, (genericptr_t) inbuf, sizeof inbuf);
-        if (!inbufsz) {
-            if (inbufp > sizeof inbuf)
-                error("EOF on file #%d.\n", mreadfd);
-            inbufp = 1 + sizeof inbuf; /* exactly one warning :-) */
-            return -1;
-        }
-        inbufp = 0;
+       inbufsz = read(mreadfd, (genericptr_t)inbuf, sizeof inbuf);
+       if (!inbufsz) {
+           if (inbufp > sizeof inbuf)
+               error("EOF on file #%d.\n", mreadfd);
+           inbufp = 1 + sizeof inbuf;  /* exactly one warning :-) */
+           return -1;
+       }
+       inbufp = 0;
     }
     return inbuf[inbufp++];
 }
@@ -1578,24 +1919,23 @@ genericptr_t buf;
 register unsigned len;
 {
     /*register int readlen = 0;*/
-    if (fd < 0)
-        error("Restore error; mread attempting to read file %d.", fd);
+    if (fd < 0) error("Restore error; mread attempting to read file %d.", fd);
     mreadfd = fd;
     while (len--) {
-        if (inrunlength > 0) {
-            inrunlength--;
-            *(*((char **) &buf))++ = '\0';
-        } else {
-            register short ch = zerocomp_mgetc();
-            if (ch < 0) {
-                restoreprocs.mread_flags = -1;
-                return;
-            }
-            if ((*(*(char **) &buf)++ = (char) ch) == RLESC) {
-                inrunlength = zerocomp_mgetc();
-            }
-        }
-        /*readlen++;*/
+       if (inrunlength > 0) {
+           inrunlength--;
+           *(*((char **)&buf))++ = '\0';
+       } else {
+           register short ch = zerocomp_mgetc();
+           if (ch < 0) {
+               restoreprocs.mread_flags = -1;
+               return;
+           }
+           if ((*(*(char **)&buf)++ = (char)ch) == RLESC) {
+               inrunlength = zerocomp_mgetc();
+           }
+       }
+       /*readlen++;*/
     }
 }
 #endif /* ZEROCOMP */
index 9a3cb62bd61379e9add800ea32d6174322eae02f..c6f61fd064509e4ea231cfc2d1b64484200ea981 100644 (file)
@@ -6,6 +6,8 @@
 #include "hack.h"
 #include "lev.h"
 #include "dlb.h"
+#include "sfproto.h"
+
 
 /*      [note: this comment is fairly old, but still accurate for 3.1]
  * Rumors have been entirely rewritten to speed up the access.  This is
@@ -383,15 +385,27 @@ dlb *fp;
 }
 
 void
-save_oracles(fd, mode)
-int fd, mode;
+save_oracles(nhfp)
+NHFILE *nhfp;
 {
-    if (perform_bwrite(mode)) {
-        bwrite(fd, (genericptr_t) &g.oracle_cnt, sizeof g.oracle_cnt);
-        if (g.oracle_cnt)
-            bwrite(fd, (genericptr_t) g.oracle_loc, g.oracle_cnt * sizeof(long));
+    int i;
+
+    if (perform_bwrite(nhfp)) {
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t) &g.oracle_cnt, sizeof g.oracle_cnt);
+            if (nhfp->fieldlevel)
+                sfo_unsigned(nhfp, &g.oracle_cnt, "oracles", "g.oracle_cnt", 1);
+            if (g.oracle_cnt) {
+                if (nhfp->structlevel) {
+                    bwrite(nhfp->fd, (genericptr_t)g.oracle_loc, g.oracle_cnt * sizeof (long));
+                }
+                if (nhfp->fieldlevel) {
+                    for (i = 0; (unsigned) i < g.oracle_cnt; ++i)
+                        sfo_ulong(nhfp, &g.oracle_loc[i], "oracles", "oracle loc", 1);
+                }
+            }
     }
-    if (release_data(mode)) {
+    if (release_data(nhfp)) {
         if (g.oracle_cnt) {
             free((genericptr_t) g.oracle_loc);
             g.oracle_loc = 0, g.oracle_cnt = 0, g.oracle_flg = 0;
@@ -400,13 +414,24 @@ int fd, mode;
 }
 
 void
-restore_oracles(fd)
-int fd;
+restore_oracles(nhfp)
+NHFILE *nhfp;
 {
-    mread(fd, (genericptr_t) &g.oracle_cnt, sizeof g.oracle_cnt);
+    int i;
+    if (nhfp->structlevel)
+        mread(nhfp->fd, (genericptr_t) &g.oracle_cnt, sizeof g.oracle_cnt);
+    if (nhfp->fieldlevel)
+        sfi_unsigned(nhfp, &g.oracle_cnt, "oracles", "g.oracle_cnt", 1);
+
     if (g.oracle_cnt) {
         g.oracle_loc = (unsigned long *) alloc(g.oracle_cnt * sizeof(long));
-        mread(fd, (genericptr_t) g.oracle_loc, g.oracle_cnt * sizeof(long));
+        if (nhfp->structlevel) {
+            mread(nhfp->fd, (genericptr_t) g.oracle_loc, g.oracle_cnt * sizeof (long));
+        }
+        if (nhfp->fieldlevel) {
+            for (i = 0; (unsigned) i < g.oracle_cnt; ++i)
+                sfi_ulong(nhfp, &g.oracle_loc[i], "oracles", "g.oracle_loc", 1);
+        }
         g.oracle_flg = 1; /* no need to call init_oracles() */
     }
 }
index ad5fd51f8d444b8013cf6df7a570bf1e6b018cce..063646cc69b5e5c44078c1f29bd30935e49ea3ac 100644 (file)
@@ -5,6 +5,8 @@
 
 #include "hack.h"
 #include "lev.h"
+#include "sfproto.h"
+
 
 #ifndef NO_SIGNAL
 #include <signal.h>
@@ -18,25 +20,35 @@ long bytes_counted;
 static int count_only;
 #endif
 
+/*SAVE2018*/
+extern void FDECL(nhout, (int, const char *,
+                    const char *, int, genericptr_t, int));
+extern int NDECL(nhdatatypes_size);
+
 #ifdef MICRO
 int dotcnt, dotrow; /* also used in restore */
 #endif
 
-STATIC_DCL void FDECL(savelevchn, (int, int));
-STATIC_DCL void FDECL(savedamage, (int, int));
-STATIC_DCL void FDECL(saveobj, (int, struct obj *));
-STATIC_DCL void FDECL(saveobjchn, (int, struct obj *, int));
-STATIC_DCL void FDECL(savemon, (int, struct monst *));
-STATIC_DCL void FDECL(savemonchn, (int, struct monst *, int));
-STATIC_DCL void FDECL(savetrapchn, (int, struct trap *, int));
-STATIC_DCL void FDECL(savegamestate, (int, int));
-STATIC_OVL void FDECL(save_msghistory, (int, int));
+STATIC_DCL void FDECL(savelevchn, (NHFILE *));
+STATIC_DCL void FDECL(savedamage, (NHFILE *));
+/* STATIC_DCL void FDECL(saveobj, (NHFILE *,struct obj *)); */
+/* STATIC_DCL void FDECL(savemon, (NHFILE *,struct monst *)); */
+/* STATIC_DCL void FDECL(savelevl, (NHFILE *, BOOLEAN_P)); */
+STATIC_DCL void FDECL(saveobj, (NHFILE *,struct obj *));
+STATIC_DCL void FDECL(savemon, (NHFILE *,struct monst *));
+STATIC_DCL void FDECL(savelevl, (NHFILE *,BOOLEAN_P));
+STATIC_DCL void FDECL(saveobjchn, (NHFILE *,struct obj *));
+STATIC_DCL void FDECL(savemonchn, (NHFILE *,struct monst *));
+STATIC_DCL void FDECL(savetrapchn, (NHFILE *,struct trap *));
+STATIC_DCL void FDECL(savegamestate, (NHFILE *));
+STATIC_OVL void FDECL(save_msghistory, (NHFILE *));
+
 #ifdef MFLOPPY
-STATIC_DCL void FDECL(savelev0, (int, XCHAR_P, int));
+STATIC_DCL void FDECL(savelev0, (NHFILE *, XCHAR_P, int));
 STATIC_DCL boolean NDECL(swapout_oldest);
 STATIC_DCL void FDECL(copyfile, (char *, char *));
 #endif /* MFLOPPY */
-STATIC_DCL void FDECL(savelevl, (int fd, BOOLEAN_P));
+/* STATIC_DCL void FDECL(savelevl, (int fd, BOOLEAN_P)); */
 STATIC_DCL void FDECL(def_bufon, (int));
 STATIC_DCL void FDECL(def_bufoff, (int));
 STATIC_DCL void FDECL(def_bflush, (int));
@@ -104,10 +116,11 @@ int
 dosave0()
 {
     const char *fq_save;
-    register int fd, ofd;
     xchar ltmp;
     d_level uz_save;
-    char whynot[BUFSZ];
+    char whynot[BUFSZ], indicate;
+    NHFILE *nhfp, *onhfp;
+    int cmc = 0;
 
     /* we may get here via hangup signal, in which case we want to fix up
        a few of things before saving so that they won't be restored in
@@ -138,9 +151,9 @@ dosave0()
 
     HUP if (iflags.window_inited) {
         nh_uncompress(fq_save);
-        fd = open_savefile();
-        if (fd > 0) {
-            (void) nhclose(fd);
+        nhfp = open_savefile();
+        if (nhfp) {
+            close_nhfile(nhfp);
             clear_nhwindow(WIN_MESSAGE);
             There("seems to be an old save file.");
             if (yn("Overwrite the old file?") == 'n') {
@@ -152,12 +165,16 @@ dosave0()
 
     HUP mark_synch(); /* flush any buffered screen output */
 
-    fd = create_savefile();
-    if (fd < 0) {
+    nhfp = create_savefile();
+    if (!nhfp) {
         HUP pline("Cannot open save file.");
         (void) delete_savefile(); /* ab@unido */
         return 0;
     }
+#ifdef SAVEFILE_DEBUGGING
+    if (nhfp && nhfp->fieldlevel && nhfp->fplog)
+        (void) fprintf(nhfp->fplog, "# just opened\n");
+#endif
 
     vision_recalc(2); /* shut down vision to prevent problems
                          in the event of an impossible() call */
@@ -182,8 +199,9 @@ dosave0()
     if (iflags.checkspace) {
         long fds, needed;
 
-        savelev(fd, ledger_no(&u.uz), COUNT_SAVE);
-        savegamestate(fd, COUNT_SAVE);
+        nhfp->mode = COUNTING;
+        savelev(nhfp, ledger_no(&u.uz));
+        savegamestate(nhfp);
         needed = bytes_counted;
 
         for (ltmp = 1; ltmp <= maxledgerno(); ltmp++)
@@ -197,7 +215,7 @@ dosave0()
                 pline("Require %ld bytes but only have %ld.", needed, fds);
             }
             flushout();
-            (void) nhclose(fd);
+            close_nhfile(nhfp);
             (void) delete_savefile();
             return 0;
         }
@@ -206,13 +224,36 @@ dosave0()
     }
 #endif /* MFLOPPY */
 
-    store_version(fd);
-    store_savefileinfo(fd);
-    store_plname_in_file(fd);
+    if (nhfp->fieldlevel && nhfp->addinfo && (nhfp->mode & WRITING))
+        sfo_addinfo(nhfp, "NetHack", "start", "savefile", 0);
+
+    nhfp->mode = WRITING | FREEING;
+    if (nhfp->mode & WRITING) {
+        if (nhfp->fieldlevel && nhfp->mode & WRITING) {
+            indicate = (nhfp->fnidx == lendian) ? 'l'
+                       : (nhfp->fnidx == ascii) ? 'a' : 'u';
+            sfo_char(nhfp, &indicate, "indicate", "format", 1);
+            cmc = critical_members_count();
+            {
+                pline("critical-members=%d.", cmc);
+            }
+            sfo_int(nhfp, &cmc, "validate", "critical_members_count", 1);
+        }
+        if (nhfp->structlevel && nhfp->mode & WRITING) {
+            indicate = 'h';     /* historical */
+            bwrite(nhfp->fd, (genericptr_t) &indicate, sizeof indicate);
+            bwrite(nhfp->fd, (genericptr_t) &cmc, sizeof cmc);
+        }
+    }
+    store_version(nhfp);
+    store_savefileinfo(nhfp);
+    if (nhfp && nhfp->fplog)
+        (void) fprintf(nhfp->fplog, "# post-validation\n");
+    store_plname_in_file(nhfp);
     g.ustuck_id = (u.ustuck ? u.ustuck->m_id : 0);
     g.usteed_id = (u.usteed ? u.usteed->m_id : 0);
-    savelev(fd, ledger_no(&u.uz), WRITE_SAVE | FREE_SAVE);
-    savegamestate(fd, WRITE_SAVE | FREE_SAVE);
+    savelev(nhfp, ledger_no(&u.uz));
+    savegamestate(nhfp);
 
     /* While copying level files around, zero out u.uz to keep
      * parts of the restore code from completely initializing all
@@ -243,23 +284,26 @@ dosave0()
         }
         mark_synch();
 #endif
-        ofd = open_levelfile(ltmp, whynot);
-        if (ofd < 0) {
+        onhfp = open_levelfile(ltmp, whynot);
+        if (!onhfp) {
             HUP pline1(whynot);
-            (void) nhclose(fd);
+            close_nhfile(nhfp);
             (void) delete_savefile();
             HUP Strcpy(g.killer.name, whynot);
             HUP done(TRICKED);
             return 0;
         }
         minit(); /* ZEROCOMP */
-        getlev(ofd, g.hackpid, ltmp, FALSE);
-        (void) nhclose(ofd);
-        bwrite(fd, (genericptr_t) &ltmp, sizeof ltmp); /* level number*/
-        savelev(fd, ltmp, WRITE_SAVE | FREE_SAVE);     /* actual level*/
+        getlev(onhfp, g.hackpid, ltmp, FALSE);
+        close_nhfile(onhfp);
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &ltmp, sizeof ltmp); /* level number*/
+        if (nhfp->fieldlevel)
+            sfo_xchar(nhfp, &ltmp, "gamestate", "level_number", 1);         /* xchar */
+        savelev(nhfp, ltmp);     /* actual level*/
         delete_levelfile(ltmp);
     }
-    bclose(fd);
+    close_nhfile(nhfp);
 
     u.uz = uz_save;
 
@@ -273,84 +317,141 @@ dosave0()
 }
 
 STATIC_OVL void
-savegamestate(fd, mode)
-register int fd, mode;
+savegamestate(nhfp)
+NHFILE *nhfp;
 {
     unsigned long uid;
 
 #ifdef MFLOPPY
-    count_only = (mode & COUNT_SAVE);
+    count_only = (nhfp->mode & COUNTING);
 #endif
     uid = (unsigned long) getuid();
-    bwrite(fd, (genericptr_t) &uid, sizeof uid);
-    bwrite(fd, (genericptr_t) &g.context, sizeof g.context);
-    bwrite(fd, (genericptr_t) &flags, sizeof flags);
+    if (nhfp->structlevel) {
+        bwrite(nhfp->fd, (genericptr_t) &uid, sizeof uid);
+        bwrite(nhfp->fd, (genericptr_t) &g.context, sizeof g.context);
+        bwrite(nhfp->fd, (genericptr_t) &flags, sizeof flags);
 #ifdef SYSFLAGS
-    bwrite(fd, (genericptr_t) &sysflags, sysflags);
+        bwrite(nhfp->fd, (genericptr_t) &sysflags, sysflags);
 #endif
+    }
+    if (nhfp->fieldlevel) {
+        sfo_ulong(nhfp, &uid, "gamestate", "uid", 1);
+        sfo_context_info(nhfp, &g.context, "gamestate", "g.context", 1);
+        sfo_flag(nhfp, &flags, "gamestate" , "flags", 1);
+#ifdef SYSFLAGS
+        sfo_flag(nhfp, &sysflags, "gamestate" , "sysflags", 1);
+#endif
+    }
+    urealtime.finish_time = getnow();
+    urealtime.realtime += (long) (urealtime.finish_time
+                                    - urealtime.start_timing);
+
     urealtime.finish_time = getnow();
     urealtime.realtime += (long) (urealtime.finish_time
                                   - urealtime.start_timing);
-    bwrite(fd, (genericptr_t) &u, sizeof u);
-    bwrite(fd, yyyymmddhhmmss(ubirthday), 14);
-    bwrite(fd, (genericptr_t) &urealtime.realtime, sizeof urealtime.realtime);
-    bwrite(fd, yyyymmddhhmmss(urealtime.start_timing), 14);  /** Why? **/
+    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);
+    }
+    if (nhfp->fieldlevel) {
+        sfo_you(nhfp, &u, "gamestate", "you", 1);
+        sfo_str(nhfp, yyyymmddhhmmss(ubirthday), "gamestate", "ubirthday", 14);
+        sfo_long(nhfp, &urealtime.realtime, "gamestate", "realtime", 1);
+        sfo_str(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(fd, mode);
+    save_killers(nhfp);
 
     /* must come before g.migrating_objs and g.migrating_mons are freed */
-    save_timers(fd, mode, RANGE_GLOBAL);
-    save_light_sources(fd, mode, RANGE_GLOBAL);
+    save_timers(nhfp, RANGE_GLOBAL);
+    save_light_sources(nhfp, RANGE_GLOBAL);
 
-    saveobjchn(fd, g.invent, mode);
+    saveobjchn(nhfp, g.invent);
     if (BALL_IN_MON) {
         /* prevent loss of ball & chain when swallowed */
         uball->nobj = uchain;
         uchain->nobj = (struct obj *) 0;
-        saveobjchn(fd, uball, mode);
+        saveobjchn(nhfp, uball);
     } else {
-        saveobjchn(fd, (struct obj *) 0, mode);
+        saveobjchn(nhfp, (struct obj *) 0);
     }
 
-    saveobjchn(fd, g.migrating_objs, mode);
-    savemonchn(fd, g.migrating_mons, mode);
-    if (release_data(mode)) {
+    saveobjchn(nhfp, g.migrating_objs);
+    savemonchn(nhfp, g.migrating_mons);
+    if (release_data(nhfp)) {
         g.invent = 0;
         g.migrating_objs = 0;
         g.migrating_mons = 0;
     }
-    bwrite(fd, (genericptr_t) g.mvitals, sizeof g.mvitals);
-
-    save_dungeon(fd, (boolean) !!perform_bwrite(mode),
-                 (boolean) !!release_data(mode));
-    savelevchn(fd, mode);
-    bwrite(fd, (genericptr_t) &g.moves, sizeof g.moves);
-    bwrite(fd, (genericptr_t) &g.monstermoves, sizeof g.monstermoves);
-    bwrite(fd, (genericptr_t) &g.quest_status, sizeof g.quest_status);
-    bwrite(fd, (genericptr_t) g.spl_book,
-           sizeof(struct spell) * (MAXSPELL + 1));
-    save_artifacts(fd);
-    save_oracles(fd, mode);
-    if (g.ustuck_id)
-        bwrite(fd, (genericptr_t) &g.ustuck_id, sizeof g.ustuck_id);
-    if (g.usteed_id)
-        bwrite(fd, (genericptr_t) &g.usteed_id, sizeof g.usteed_id);
-    bwrite(fd, (genericptr_t) g.pl_character, sizeof g.pl_character);
-    bwrite(fd, (genericptr_t) g.pl_fruit, sizeof g.pl_fruit);
-    savefruitchn(fd, mode);
-    savenames(fd, mode);
-    save_waterlevel(fd, mode);
-    save_msghistory(fd, mode);
-    bflush(fd);
+    if (nhfp->structlevel)
+        bwrite(nhfp->fd, (genericptr_t) g.mvitals, sizeof g.mvitals);
+    if (nhfp->fieldlevel) {
+        int i;
+
+        for (i = 0; i < NUMMONS; ++i)
+            sfo_mvitals(nhfp, &g.mvitals[i], "gamestate", "g.mvitals", 1);
+    }            
+    save_dungeon(nhfp, (boolean) !!perform_bwrite(nhfp),
+                 (boolean) !!release_data(nhfp));
+    savelevchn(nhfp);
+    if (nhfp->structlevel) {
+        bwrite(nhfp->fd, (genericptr_t) &g.moves, sizeof g.moves);
+        bwrite(nhfp->fd, (genericptr_t) &g.monstermoves, sizeof g.monstermoves);
+        bwrite(nhfp->fd, (genericptr_t) &g.quest_status, sizeof g.quest_status);
+        bwrite(nhfp->fd, (genericptr_t) g.spl_book,
+               sizeof (struct spell) * (MAXSPELL + 1));
+    }
+    if (nhfp->fieldlevel) {
+        int i;
+        struct spell *sptmp;
+
+        sfo_long(nhfp, &g.moves, "gamestate", "g.moves", 1);
+        sfo_long(nhfp, &g.monstermoves, "gamestate", "g.monstermoves", 1);
+        sfo_q_score(nhfp, &g.quest_status, "gamestate", "g.quest_status", 1);
+        sptmp = g.spl_book;
+        for (i = 0; i < (MAXSPELL + 1); ++i)
+            sfo_spell(nhfp, sptmp++, "gamestate", "g.spl_book", 1);
+    }
+    save_artifacts(nhfp);
+    save_oracles(nhfp);
+    if (g.ustuck_id) {
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &g.ustuck_id, sizeof g.ustuck_id);
+        if (nhfp->fieldlevel)
+            sfo_unsigned(nhfp, &g.ustuck_id, "gamestate", "g.ustuck_id", 1);
+    }
+    if (g.usteed_id) {
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &g.usteed_id, sizeof g.usteed_id);
+        if (nhfp->fieldlevel)
+            sfo_unsigned(nhfp, &g.usteed_id, "gamestate", "g.usteed_id", 1);
+    }
+    if (nhfp->structlevel) {
+        bwrite(nhfp->fd, (genericptr_t) g.pl_character, sizeof g.pl_character);
+        bwrite(nhfp->fd, (genericptr_t) g.pl_fruit, sizeof g.pl_fruit);
+    }
+    if (nhfp->fieldlevel) {
+        sfo_char(nhfp, g.pl_character, "gamestate", "g.pl_character", sizeof g.pl_character);
+        sfo_char(nhfp, g.pl_fruit, "gamestate", "g.pl_fruit", sizeof g.pl_fruit); 
+    }
+    savefruitchn(nhfp);
+    savenames(nhfp);
+    save_waterlevel(nhfp);
+    save_msghistory(nhfp);
+    if (nhfp->structlevel)
+        bflush(nhfp->fd);
 }
 
 boolean
-tricked_fileremoved(fd, whynot)
-int fd;
+tricked_fileremoved(nhfp, whynot)
+NHFILE *nhfp;
 char *whynot;
 {
-    if (fd < 0) {
+    if (!nhfp) {
         pline1(whynot);
         pline("Probably someone removed it.");
         Strcpy(g.killer.name, whynot);
@@ -364,8 +465,10 @@ char *whynot;
 void
 savestateinlock()
 {
-    int fd, hpid;
+    int hpid;
+    static boolean havestate = TRUE;
     char whynot[BUFSZ];
+    NHFILE *nhfp;
 
     /* When checkpointing is on, the full state needs to be written
      * on each checkpoint.  When checkpointing is off, only the pid
@@ -385,11 +488,12 @@ savestateinlock()
          * to any internal compression schemes since they must be
          * readable by an external utility
          */
-        fd = open_levelfile(0, whynot);
-        if (tricked_fileremoved(fd, whynot))
+        nhfp = open_levelfile(0, whynot);
+        if (tricked_fileremoved(nhfp, whynot))
             return;
 
-        (void) read(fd, (genericptr_t) &hpid, sizeof hpid);
+        if (nhfp->structlevel)
+            (void) read(nhfp->fd, (genericptr_t) &hpid, sizeof hpid);
         if (g.hackpid != hpid) {
             Sprintf(whynot, "Level #0 pid (%d) doesn't match ours (%d)!",
                     hpid, g.hackpid);
@@ -397,30 +501,37 @@ savestateinlock()
             Strcpy(g.killer.name, whynot);
             done(TRICKED);
         }
-        (void) nhclose(fd);
+        close_nhfile(nhfp);
 
-        fd = create_levelfile(0, whynot);
-        if (fd < 0) {
+        nhfp = create_levelfile(0, whynot);
+        if (!nhfp) {
             pline1(whynot);
             Strcpy(g.killer.name, whynot);
             done(TRICKED);
             return;
         }
-        (void) write(fd, (genericptr_t) &g.hackpid, sizeof g.hackpid);
+        nhfp->mode = WRITING;
+        if (nhfp->structlevel)
+            (void) write(nhfp->fd, (genericptr_t) &g.hackpid, sizeof g.hackpid);
+        if (nhfp->fieldlevel)
+            sfo_int(nhfp, &g.hackpid, "gamestate", "g.hackpid", 1);
         if (flags.ins_chkpt) {
             int currlev = ledger_no(&u.uz);
 
-            (void) write(fd, (genericptr_t) &currlev, sizeof currlev);
-            save_savefile_name(fd);
-            store_version(fd);
-            store_savefileinfo(fd);
-            store_plname_in_file(fd);
+            if (nhfp->structlevel)
+                (void) write(nhfp->fd, (genericptr_t) &currlev, sizeof currlev);
+            if (nhfp->fieldlevel)
+                sfo_int(nhfp, &currlev, "gamestate", "savestateinlock", 1);
+            save_savefile_name(nhfp);
+            store_version(nhfp);
+            store_savefileinfo(nhfp);
+            store_plname_in_file(nhfp);
 
             g.ustuck_id = (u.ustuck ? u.ustuck->m_id : 0);
             g.usteed_id = (u.usteed ? u.usteed->m_id : 0);
-            savegamestate(fd, WRITE_SAVE);
+            savegamestate(nhfp);
         }
-        bclose(fd);
+        close_nhfile(nhfp);
     }
     g.havestate = flags.ins_chkpt;
 }
@@ -428,14 +539,15 @@ savestateinlock()
 
 #ifdef MFLOPPY
 boolean
-savelev(fd, lev, mode)
-int fd;
+savelev(nhfp, lev)
+NHFILE *nhfp;
 xchar lev;
-int mode;
 {
-    if (mode & COUNT_SAVE) {
+    if (nhfp->mode & COUNTING) {
+        int savemode = nhfp->mode;
+
         bytes_counted = 0;
-        savelev0(fd, lev, COUNT_SAVE);
+        savelev0(nhfp, lev);
         /* probably bytes_counted will be filled in again by an
          * immediately following WRITE_SAVE anyway, but we'll
          * leave it out of checkspace just in case */
@@ -445,11 +557,11 @@ int mode;
                     return FALSE;
         }
     }
-    if (mode & (WRITE_SAVE | FREE_SAVE)) {
+    if (nhfp->mode & (WRITING | FREEING)) {
         bytes_counted = 0;
-        savelev0(fd, lev, mode);
+        savelev0(nhfp, lev);
     }
-    if (mode != FREE_SAVE) {
+    if (nhfp->mode != FREEING) {
         g.level_info[lev].where = ACTIVE;
         g.level_info[lev].time = g.moves;
         g.level_info[lev].size = bytes_counted;
@@ -458,14 +570,13 @@ int mode;
 }
 
 STATIC_OVL void
-savelev0(fd, lev, mode)
+savelev0(nhfp, lev)
 #else
 void
-savelev(fd, lev, mode)
+savelev(nhfp, lev)
 #endif
-int fd;
+NHFILE *nhfp;
 xchar lev;
-int mode;
 {
 #ifdef TOS
     short tlev;
@@ -487,8 +598,8 @@ int mode;
      *  portion (which has some freeing to do), then jump quite a bit
      *  further ahead to the middle of the 'actual level data' portion.
      */
-    if (mode != FREE_SAVE) {
-        /* WRITE_SAVE (probably ORed with FREE_SAVE), or COUNT_SAVE */
+    if (nhfp->mode != FREEING) {
+        /* WRITING (probably ORed with FREEING), or COUNTING */
 
         /* purge any dead monsters (necessary if we're starting
            a panic save rather than a normal one, or sometimes
@@ -497,20 +608,29 @@ int mode;
         if (iflags.purge_monsters)
             dmonsfree();
 
-        if (fd < 0)
+        if (!nhfp)
             panic("Save on bad file!"); /* impossible */
 #ifdef MFLOPPY
-        count_only = (mode & COUNT_SAVE);
+        count_only = (nhfp->mode & COUNTING);
 #endif
         if (lev >= 0 && lev <= maxledgerno())
             g.level_info[lev].flags |= VISITED;
-        bwrite(fd, (genericptr_t) &g.hackpid, sizeof g.hackpid);
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &g.hackpid, sizeof g.hackpid);
+        if (nhfp->fieldlevel)
+            sfo_int(nhfp, &g.hackpid, "gamestate", "g.hackpid", 1);
 #ifdef TOS
         tlev = lev;
         tlev &= 0x00ff;
-        bwrite(fd, (genericptr_t) &tlev, sizeof tlev);
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &tlev, sizeof tlev);
+        if (nhfp->fieldlevel)
+            sfo_short(nhfp, &tlev, "gamestate", "tlev", 1);
 #else
-        bwrite(fd, (genericptr_t) &lev, sizeof lev);
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &lev, sizeof lev);
+        if (nhfp->fieldlevel)
+            sfo_xchar(nhfp, &lev, "gamestate", "dlvl", 1);
 #endif
     }
 
@@ -520,37 +640,57 @@ int mode;
        the guessing that was needed in 3.4.3 and without having to
        interpret level data to find where to start; unfortunately it
        still needs to handle all the data compression schemes */
-    savecemetery(fd, mode, &g.level.bonesinfo);
-    if (mode == FREE_SAVE) /* see above */
+    savecemetery(nhfp, &g.level.bonesinfo);
+    if (nhfp->mode == FREEING) /* see above */
         goto skip_lots;
 
-    savelevl(fd, (boolean) ((sfsaveinfo.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP));
-    bwrite(fd, (genericptr_t) g.lastseentyp, sizeof g.lastseentyp);
-    bwrite(fd, (genericptr_t) &g.monstermoves, sizeof g.monstermoves);
-    bwrite(fd, (genericptr_t) &g.upstair, sizeof (stairway));
-    bwrite(fd, (genericptr_t) &g.dnstair, sizeof (stairway));
-    bwrite(fd, (genericptr_t) &g.upladder, sizeof (stairway));
-    bwrite(fd, (genericptr_t) &g.dnladder, sizeof (stairway));
-    bwrite(fd, (genericptr_t) &g.sstairs, sizeof (stairway));
-    bwrite(fd, (genericptr_t) &g.updest, sizeof (dest_area));
-    bwrite(fd, (genericptr_t) &g.dndest, sizeof (dest_area));
-    bwrite(fd, (genericptr_t) &g.level.flags, sizeof g.level.flags);
-    bwrite(fd, (genericptr_t) g.doors, sizeof g.doors);
-    save_rooms(fd); /* no dynamic memory to reclaim */
+    savelevl(nhfp, (boolean) ((sfsaveinfo.sfi1 & SFI1_RLECOMP) == SFI1_RLECOMP));
+    if (nhfp->structlevel) {
+        bwrite(nhfp->fd, (genericptr_t) g.lastseentyp, sizeof g.lastseentyp);
+        bwrite(nhfp->fd, (genericptr_t) &g.monstermoves, sizeof g.monstermoves);
+        bwrite(nhfp->fd, (genericptr_t) &g.upstair, sizeof (stairway));
+        bwrite(nhfp->fd, (genericptr_t) &g.dnstair, sizeof (stairway));
+        bwrite(nhfp->fd, (genericptr_t) &g.upladder, sizeof (stairway));
+        bwrite(nhfp->fd, (genericptr_t) &g.dnladder, sizeof (stairway));
+        bwrite(nhfp->fd, (genericptr_t) &g.sstairs, sizeof (stairway));
+        bwrite(nhfp->fd, (genericptr_t) &g.updest, sizeof (dest_area));
+        bwrite(nhfp->fd, (genericptr_t) &g.dndest, sizeof (dest_area));
+        bwrite(nhfp->fd, (genericptr_t) &g.level.flags, sizeof g.level.flags);
+        bwrite(nhfp->fd, (genericptr_t) g.doors, sizeof g.doors);
+    }
+    if (nhfp->fieldlevel) {
+        int i, c, r;
+
+        for (c = 0; c < COLNO; ++c)
+            for (r = 0; r < ROWNO; ++r)
+                sfo_schar(nhfp, &g.lastseentyp[c][r], "lev", "g.lastseentyp", 1);
+        sfo_long(nhfp, &g.monstermoves, "lev", "timestmp", 1);
+        sfo_stairway(nhfp, &g.upstair, "lev", "g.upstair", 1);
+        sfo_stairway(nhfp, &g.dnstair, "lev", "g.dnstair", 1);
+        sfo_stairway(nhfp, &g.upladder, "lev", "g.upladder", 1);
+        sfo_stairway(nhfp, &g.dnladder, "lev", "g.dnladder", 1);
+        sfo_stairway(nhfp, &g.sstairs, "lev", "g.sstairs", 1);
+        sfo_dest_area(nhfp, &g.updest, "lev", "g.updest", 1);
+        sfo_dest_area(nhfp, &g.dndest, "lev", "g.dndest", 1);
+        sfo_levelflags(nhfp, &g.level.flags, "lev", "g.level.flags", 1);
+        for (i = 0; i < DOORMAX; ++i)
+            sfo_nhcoord(nhfp, &g.doors[i], "lev", "door", 1);
+    }
+    save_rooms(nhfp); /* no dynamic memory to reclaim */
 
     /* from here on out, saving also involves allocated memory cleanup */
  skip_lots:
     /* timers and lights must be saved before monsters and objects */
-    save_timers(fd, mode, RANGE_LEVEL);
-    save_light_sources(fd, mode, RANGE_LEVEL);
-
-    savemonchn(fd, fmon, mode);
-    save_worm(fd, mode); /* save worm information */
-    savetrapchn(fd, g.ftrap, mode);
-    saveobjchn(fd, fobj, mode);
-    saveobjchn(fd, g.level.buriedobjlist, mode);
-    saveobjchn(fd, g.billobjs, mode);
-    if (release_data(mode)) {
+    save_timers(nhfp, RANGE_LEVEL);
+    save_light_sources(nhfp, RANGE_LEVEL);
+
+    savemonchn(nhfp, fmon);
+    save_worm(nhfp); /* save worm information */
+    savetrapchn(nhfp, g.ftrap);
+    saveobjchn(nhfp, fobj);
+    saveobjchn(nhfp, g.level.buriedobjlist);
+    saveobjchn(nhfp, g.billobjs);
+    if (release_data(nhfp)) {
         int x,y;
 
         for (y = 0; y < ROWNO; y++)
@@ -563,16 +703,18 @@ int mode;
         g.billobjs = 0;
         /* level.bonesinfo = 0; -- handled by savecemetery() */
     }
-    save_engravings(fd, mode);
-    savedamage(fd, mode); /* pending shop wall and/or floor repair */
-    save_regions(fd, mode);
-    if (mode != FREE_SAVE)
-        bflush(fd);
+    save_engravings(nhfp);
+    savedamage(nhfp); /* pending shop wall and/or floor repair */
+    save_regions(nhfp);
+    if (nhfp->mode != FREEING) {
+        if (nhfp->structlevel)
+            bflush(nhfp->fd);
+    }
 }
 
 STATIC_OVL void
-savelevl(fd, rlecomp)
-int fd;
+savelevl(nhfp, rlecomp)
+NHFILE *nhfp;
 boolean rlecomp;
 {
 #ifdef RLECOMP
@@ -604,8 +746,14 @@ boolean rlecomp;
                 } else {
                     /* run has been broken, write out run-length encoding */
  writeout:
-                    bwrite(fd, (genericptr_t) &match, sizeof (uchar));
-                    bwrite(fd, (genericptr_t) rgrm, sizeof (struct rm));
+                    if (nhfp->structlevel) {
+                        bwrite(nhfp->fd, (genericptr_t) &match, sizeof (uchar));
+                        bwrite(nhfp->fd, (genericptr_t) rgrm, sizeof (struct rm));
+                   }
+                   if (nhfp->fieldlevel) {
+                        sfo_uchar(nhfp, &match, "levl", "match", 1);
+                        sfo_rm(nhfp, rgrm, "levl", "rgrm", 1);
+                   }
                     /* start encoding again. we have at least 1 rm
                        in the next run, viz. this one. */
                     match = 1;
@@ -614,15 +762,30 @@ boolean rlecomp;
             }
         }
         if (match > 0) {
-            bwrite(fd, (genericptr_t) &match, sizeof (uchar));
-            bwrite(fd, (genericptr_t) rgrm, sizeof (struct rm));
+            if (nhfp->structlevel) {
+                bwrite(nhfp->fd, (genericptr_t) &match, sizeof (uchar));
+                bwrite(nhfp->fd, (genericptr_t) rgrm, sizeof (struct rm));
+            }
+            if (nhfp->fieldlevel) {
+                sfo_uchar(nhfp, &match, "levl", "match", 1);
+                sfo_rm(nhfp, rgrm, "levl", "rgrm", 1);
+            }
         }
         return;
     }
 #else /* !RLECOMP */
     nhUse(rlecomp);
 #endif /* ?RLECOMP */
-    bwrite(fd, (genericptr_t) levl, sizeof levl);
+    if (nhfp->structlevel) {
+        bwrite(nhfp->fd, (genericptr_t) levl, sizeof levl);
+    }
+    if (nhfp->fieldlevel) {
+        int c, r;
+
+        for (c = 0; c < COLNO; ++c)
+            for (r = 0; r < ROWNO; ++r)
+                sfo_rm(nhfp, &g.level.locations[c][r], "room", "levl", 1);
+    }
 }
 
 /*ARGSUSED*/
@@ -676,14 +839,14 @@ static boolean buffering = FALSE;
 
 STATIC_OVL void
 def_bufon(fd)
-int fd;
+    int fd;
 {
 #ifdef UNIX
-    if (bw_fd != fd) {
-        if (bw_fd >= 0)
+    if(bw_fd != fd) {
+        if(bw_fd >= 0)
             panic("double buffering unexpected");
         bw_fd = fd;
-        if ((bw_FILE = fdopen(fd, "w")) == 0)
+        if((bw_FILE = fdopen(fd, "w")) == 0)
             panic("buffering of file %d failed", fd);
     }
 #endif
@@ -777,11 +940,11 @@ int fd;
  * file is written out.
  */
 
-#define RLESC '\0' /* Leading character for run of LRESC's */
+#define RLESC '\0'    /* Leading character for run of LRESC's */
 #define flushoutrun(ln) (zerocomp_bputc(RLESC), zerocomp_bputc(ln), ln = -1)
 
 #ifndef ZEROCOMP_BUFSIZ
-#define ZEROCOMP_BUFSIZ BUFSZ
+# define ZEROCOMP_BUFSIZ BUFSZ
 #endif
 static NEARDATA unsigned char outbuf[ZEROCOMP_BUFSIZ];
 static NEARDATA unsigned short outbufp = 0;
@@ -801,18 +964,18 @@ int c;
 #ifdef MFLOPPY
     bytes_counted++;
     if (count_only)
-        return;
+      return;
 #endif
     if (outbufp >= sizeof outbuf) {
         (void) write(bwritefd, outbuf, sizeof outbuf);
         outbufp = 0;
     }
-    outbuf[outbufp++] = (unsigned char) c;
+    outbuf[outbufp++] = (unsigned char)c;
 }
 
 /*ARGSUSED*/
-void STATIC_OVL
-zerocomp_bufon(fd)
+void
+STATIC_OVL zerocomp_bufon(fd)
 int fd;
 {
     compressing = TRUE;
@@ -910,56 +1073,70 @@ int fd;
 #endif /* ZEROCOMP */
 
 STATIC_OVL void
-savelevchn(fd, mode)
-register int fd, mode;
+savelevchn(nhfp)
+NHFILE *nhfp;
 {
     s_level *tmplev, *tmplev2;
     int cnt = 0;
 
     for (tmplev = g.sp_levchn; tmplev; tmplev = tmplev->next)
         cnt++;
-    if (perform_bwrite(mode))
-        bwrite(fd, (genericptr_t) &cnt, sizeof cnt);
-
+    if (perform_bwrite(nhfp)) {
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &cnt, sizeof cnt);
+        if (nhfp->fieldlevel)
+            sfo_int(nhfp, &cnt, "levchn", "lev_count", 1);
+    }
     for (tmplev = g.sp_levchn; tmplev; tmplev = tmplev2) {
         tmplev2 = tmplev->next;
-        if (perform_bwrite(mode))
-            bwrite(fd, (genericptr_t) tmplev, sizeof *tmplev);
-        if (release_data(mode))
+        if (perform_bwrite(nhfp)) {
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t) tmplev, sizeof *tmplev);
+            if (nhfp->fieldlevel)
+                sfo_s_level(nhfp, tmplev, "levchn", "s_level", 1);
+       }
+        if (release_data(nhfp))
             free((genericptr_t) tmplev);
     }
-    if (release_data(mode))
+    if (release_data(nhfp))
         g.sp_levchn = 0;
 }
 
 /* used when saving a level and also when saving dungeon overview data */
 void
-savecemetery(fd, mode, cemeteryaddr)
-int fd;
-int mode;
+savecemetery(nhfp, cemeteryaddr)
+NHFILE *nhfp;
 struct cemetery **cemeteryaddr;
 {
     struct cemetery *thisbones, *nextbones;
     int flag;
 
     flag = *cemeteryaddr ? 0 : -1;
-    if (perform_bwrite(mode))
-        bwrite(fd, (genericptr_t) &flag, sizeof flag);
+    if (perform_bwrite(nhfp)) {
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &flag, sizeof flag);
+        if (nhfp->fieldlevel)
+            sfo_int(nhfp, &flag, "cemetery", "cemetery_flag", 1);
+    }
     nextbones = *cemeteryaddr;
     while ((thisbones = nextbones) != 0) {
         nextbones = thisbones->next;
-        if (perform_bwrite(mode))
-            bwrite(fd, (genericptr_t) thisbones, sizeof *thisbones);
-        if (release_data(mode))
+        if (perform_bwrite(nhfp)) {
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t) thisbones, sizeof *thisbones);
+            if (nhfp->fieldlevel)
+                sfo_cemetery(nhfp, thisbones, "cemetery", "cemetery", 1);
+       }
+        if (release_data(nhfp))
             free((genericptr_t) thisbones);
     }
-    if (release_data(mode))
+    if (release_data(nhfp))
         *cemeteryaddr = 0;
 }
 
 STATIC_OVL void
-savedamage(fd, mode)
-register int fd, mode;
+savedamage(nhfp)
+NHFILE *nhfp;
 {
     register struct damage *damageptr, *tmp_dam;
     unsigned int xl = 0;
@@ -967,64 +1144,107 @@ register int fd, mode;
     damageptr = g.level.damagelist;
     for (tmp_dam = damageptr; tmp_dam; tmp_dam = tmp_dam->next)
         xl++;
-    if (perform_bwrite(mode))
-        bwrite(fd, (genericptr_t) &xl, sizeof xl);
-
+    if (perform_bwrite(nhfp)) {
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &xl, sizeof xl);
+        if (nhfp->fieldlevel)
+            sfo_unsigned(nhfp, &xl, "damage", "damage_count", 1);
+    }
     while (xl--) {
-        if (perform_bwrite(mode))
-            bwrite(fd, (genericptr_t) damageptr, sizeof *damageptr);
+        if (perform_bwrite(nhfp)) {
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t) damageptr, sizeof *damageptr);
+            if (nhfp->fieldlevel)
+                sfo_damage(nhfp, damageptr, "damage", "damage", 1);
+       }
         tmp_dam = damageptr;
         damageptr = damageptr->next;
-        if (release_data(mode))
+        if (release_data(nhfp))
             free((genericptr_t) tmp_dam);
     }
-    if (release_data(mode))
+    if (release_data(nhfp))
         g.level.damagelist = 0;
 }
 
 STATIC_OVL void
-saveobj(fd, otmp)
-int fd;
+saveobj(nhfp, otmp)
+NHFILE *nhfp;
 struct obj *otmp;
 {
     int buflen, zerobuf = 0;
 
     buflen = (int) sizeof (struct obj);
-    bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
-    bwrite(fd, (genericptr_t) otmp, buflen);
+    if (nhfp->structlevel) {
+        bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen);
+        bwrite(nhfp->fd, (genericptr_t) otmp, buflen);
+    }
+    if (nhfp->fieldlevel) {
+        sfo_int(nhfp, &buflen, "obj", "obj_length", 1);
+        sfo_obj(nhfp, otmp, "obj", "obj", 1);
+    }
     if (otmp->oextra) {
         buflen = ONAME(otmp) ? (int) strlen(ONAME(otmp)) + 1 : 0;
-        bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
-        if (buflen > 0)
-            bwrite(fd, (genericptr_t) ONAME(otmp), buflen);
-
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen);
+        if (nhfp->fieldlevel)
+            sfo_int(nhfp, &buflen, "obj", "oname_length", 1);
+
+        if (buflen > 0) {
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t) ONAME(otmp), buflen);
+            if (nhfp->fieldlevel)
+                sfo_str(nhfp, ONAME(otmp), "obj", "oname", buflen);
+        }
         /* defer to savemon() for this one */
-        if (OMONST(otmp))
-            savemon(fd, OMONST(otmp));
-        else
-            bwrite(fd, (genericptr_t) &zerobuf, sizeof zerobuf);
-
+        if (OMONST(otmp)) {
+            savemon(nhfp, OMONST(otmp));
+        } else {
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t) &zerobuf, sizeof zerobuf);
+            if (nhfp->fieldlevel)
+                sfo_int(nhfp, &zerobuf, "obj", "omonst_length", 1);
+       }
         buflen = OMID(otmp) ? (int) sizeof (unsigned) : 0;
-        bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
-        if (buflen > 0)
-            bwrite(fd, (genericptr_t) OMID(otmp), buflen);
-
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen);
+        if (nhfp->fieldlevel)
+            sfo_int(nhfp, &buflen, "obj", "omid_length", 1);            
+        if (buflen > 0) {
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t) OMID(otmp), buflen);
+            if (nhfp->fieldlevel)
+                sfo_int(nhfp, &buflen, "obj", "omid_length", 1);
+       }
         /* TODO: post 3.6.x, get rid of this */
         buflen = OLONG(otmp) ? (int) sizeof (long) : 0;
-        bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
-        if (buflen > 0)
-            bwrite(fd, (genericptr_t) OLONG(otmp), buflen);
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen);
+        if (nhfp->fieldlevel)
+            sfo_int(nhfp, &buflen, "obj", "olong_length", 1);
+        if (buflen > 0) {
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t) OLONG(otmp), buflen);
+            if (nhfp->fieldlevel)
+                sfo_long(nhfp, OLONG(otmp), "obj", "olong", 1);
+       }
 
         buflen = OMAILCMD(otmp) ? (int) strlen(OMAILCMD(otmp)) + 1 : 0;
-        bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
-        if (buflen > 0)
-            bwrite(fd, (genericptr_t) OMAILCMD(otmp), buflen);
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen);
+        if (nhfp->fieldlevel)
+            sfo_int(nhfp, &buflen, "obj", "omailcmd_length", 1);
+        if (buflen > 0) {
+            if (nhfp->structlevel)
+                  bwrite(nhfp->fd, (genericptr_t) OMAILCMD(otmp), buflen);
+            if (nhfp->fieldlevel)
+                sfo_str(nhfp, OMAILCMD(otmp), "obj", "omailcmd", buflen);
+        }
     }
 }
 
 STATIC_OVL void
-saveobjchn(fd, otmp, mode)
-register int fd, mode;
+saveobjchn(nhfp, otmp)
+NHFILE *nhfp;
 register struct obj *otmp;
 {
     register struct obj *otmp2;
@@ -1032,12 +1252,12 @@ register struct obj *otmp;
 
     while (otmp) {
         otmp2 = otmp->nobj;
-        if (perform_bwrite(mode)) {
-            saveobj(fd, otmp);
+        if (perform_bwrite(nhfp)) {
+            saveobj(nhfp, otmp);
         }
         if (Has_contents(otmp))
-            saveobjchn(fd, otmp->cobj, mode);
-        if (release_data(mode)) {
+            saveobjchn(nhfp, otmp->cobj);
+        if (release_data(nhfp)) {
             /*
              * If these are on the floor, the discarding could be
              * due to game save, or we could just be changing levels.
@@ -1065,13 +1285,17 @@ register struct obj *otmp;
         }
         otmp = otmp2;
     }
-    if (perform_bwrite(mode))
-        bwrite(fd, (genericptr_t) &minusone, sizeof (int));
+    if (perform_bwrite(nhfp)) {
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &minusone, sizeof (int));
+        if (nhfp->fieldlevel)
+            sfo_int(nhfp, &minusone, "obj", "obj_length", 1);
+    }
 }
 
 STATIC_OVL void
-savemon(fd, mtmp)
-int fd;
+savemon(nhfp, mtmp)
+NHFILE *nhfp;
 struct monst *mtmp;
 {
     int buflen;
@@ -1079,42 +1303,93 @@ 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);
-    bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
-    bwrite(fd, (genericptr_t) mtmp, buflen);
+    if (nhfp->structlevel) {
+        bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen);
+        bwrite(nhfp->fd, (genericptr_t) mtmp, buflen);
+    }
+    if (nhfp->fieldlevel) {
+        sfo_int(nhfp, &buflen, "mon", "monst_length", 1);
+        sfo_monst(nhfp, mtmp, "mon", "monst", 1);
+    }
     if (mtmp->mextra) {
         buflen = MNAME(mtmp) ? (int) strlen(MNAME(mtmp)) + 1 : 0;
-        bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
-        if (buflen > 0)
-            bwrite(fd, (genericptr_t) MNAME(mtmp), buflen);
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen);
+        if (nhfp->fieldlevel)
+            sfo_int(nhfp, &buflen, "mon", "mname_length", 1);
+        if (buflen > 0) {
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t) MNAME(mtmp), buflen);
+            if (nhfp->fieldlevel)
+                sfo_str(nhfp, MNAME(mtmp), "mon", "mname", buflen);
+        }
         buflen = EGD(mtmp) ? (int) sizeof (struct egd) : 0;
-        bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
-        if (buflen > 0)
-            bwrite(fd, (genericptr_t) EGD(mtmp), buflen);
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen);
+        if (nhfp->fieldlevel)
+            sfo_int(nhfp, &buflen, "mon", "egd_length", 1);
+        if (buflen > 0) {
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t) EGD(mtmp), buflen);
+            if (nhfp->fieldlevel)
+                sfo_egd(nhfp, EGD(mtmp), "mon", "egd", 1);
+        }
         buflen = EPRI(mtmp) ? (int) sizeof (struct epri) : 0;
-        bwrite(fd, (genericptr_t) &buflen, sizeof buflen);
-        if (buflen > 0)
-            bwrite(fd, (genericptr_t) EPRI(mtmp), buflen);
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof buflen);
+        if (nhfp->fieldlevel)
+            sfo_int(nhfp, &buflen, "mon", "epri_length", 1);
+        if (buflen > 0) {
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t) EPRI(mtmp), buflen);
+            if (nhfp->fieldlevel)
+                sfo_epri(nhfp, EPRI(mtmp), "mon", "epri", 1);
+        }
         buflen = ESHK(mtmp) ? (int) sizeof (struct eshk) : 0;
-        bwrite(fd, (genericptr_t) &buflen, sizeof(int));
-        if (buflen > 0)
-            bwrite(fd, (genericptr_t) ESHK(mtmp), buflen);
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof (int));
+        if (nhfp->fieldlevel)
+            sfo_int(nhfp, &buflen, "mon", "eshk_length", 1);
+        if (buflen > 0) {
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t) ESHK(mtmp), buflen);
+            if (nhfp->fieldlevel)
+                sfo_eshk(nhfp, ESHK(mtmp), "mon", "eshk", 1);
+        }
         buflen = EMIN(mtmp) ? (int) sizeof (struct emin) : 0;
-        bwrite(fd, (genericptr_t) &buflen, sizeof(int));
-        if (buflen > 0)
-            bwrite(fd, (genericptr_t) EMIN(mtmp), buflen);
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof (int));
+        if (nhfp->fieldlevel)
+            sfo_int(nhfp, &buflen, "mon", "emin_length", 1);
+        if (buflen > 0) {
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t) EMIN(mtmp), buflen);
+            if (nhfp->fieldlevel)
+                sfo_emin(nhfp, EMIN(mtmp), "mon", "emin", 1);
+        }
         buflen = EDOG(mtmp) ? (int) sizeof (struct edog) : 0;
-        bwrite(fd, (genericptr_t) &buflen, sizeof(int));
-        if (buflen > 0)
-            bwrite(fd, (genericptr_t) EDOG(mtmp), buflen);
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &buflen, sizeof (int));
+        if (nhfp->fieldlevel)
+            sfo_int(nhfp, &buflen, "mon", "edog_length", 1);
+        if (buflen > 0) {
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t) EDOG(mtmp), buflen);
+            if (nhfp->fieldlevel)
+                sfo_edog(nhfp, EDOG(mtmp), "mon", "edog", 1);
+       }
         /* mcorpsenm is inline int rather than pointer to something,
            so doesn't need to be preceded by a length field */
-        bwrite(fd, (genericptr_t) &MCORPSENM(mtmp), sizeof MCORPSENM(mtmp));
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &MCORPSENM(mtmp), sizeof MCORPSENM(mtmp));
+        if (nhfp->fieldlevel)
+            sfo_int(nhfp, &MCORPSENM(mtmp), "mon", "mcorpsenm", 1);
     }
 }
 
 STATIC_OVL void
-savemonchn(fd, mtmp, mode)
-register int fd, mode;
+savemonchn(nhfp, mtmp)
+NHFILE *nhfp;
 register struct monst *mtmp;
 {
     register struct monst *mtmp2;
@@ -1122,15 +1397,15 @@ register struct monst *mtmp;
 
     while (mtmp) {
         mtmp2 = mtmp->nmon;
-        if (perform_bwrite(mode)) {
+        if (perform_bwrite(nhfp)) {
             mtmp->mnum = monsndx(mtmp->data);
             if (mtmp->ispriest)
                 forget_temple_entry(mtmp); /* EPRI() */
-            savemon(fd, mtmp);
+            savemon(nhfp, mtmp);
         }
         if (mtmp->minvent)
-            saveobjchn(fd, mtmp->minvent, mode);
-        if (release_data(mode)) {
+            saveobjchn(nhfp, mtmp->minvent);
+        if (release_data(nhfp)) {
             if (mtmp == g.context.polearm.hitmon) {
                 g.context.polearm.m_id = mtmp->m_id;
                 g.context.polearm.hitmon = NULL;
@@ -1140,30 +1415,41 @@ register struct monst *mtmp;
         }
         mtmp = mtmp2;
     }
-    if (perform_bwrite(mode))
-        bwrite(fd, (genericptr_t) &minusone, sizeof (int));
+    if (perform_bwrite(nhfp)) {
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &minusone, sizeof (int));
+        if (nhfp->fieldlevel)
+            sfo_int(nhfp, &minusone, "mon", "monst_length", 1);
+    }
 }
 
 /* save traps; g.ftrap is the only trap chain so the 2nd arg is superfluous */
 STATIC_OVL void
-savetrapchn(fd, trap, mode)
-int fd;
+savetrapchn(nhfp, trap)
+NHFILE *nhfp;
 register struct trap *trap;
-int mode;
 {
     static struct trap zerotrap;
     register struct trap *trap2;
 
     while (trap) {
         trap2 = trap->ntrap;
-        if (perform_bwrite(mode))
-            bwrite(fd, (genericptr_t) trap, sizeof *trap);
-        if (release_data(mode))
+        if (perform_bwrite(nhfp)) {
+            if (nhfp->structlevel)  
+                bwrite(nhfp->fd, (genericptr_t) trap, sizeof *trap);
+            if (nhfp->fieldlevel)
+                sfo_trap(nhfp, trap, "trap", "trap", 1);
+       }
+        if (release_data(nhfp))
             dealloc_trap(trap);
         trap = trap2;
     }
-    if (perform_bwrite(mode))
-        bwrite(fd, (genericptr_t) &zerotrap, sizeof zerotrap);
+    if (perform_bwrite(nhfp)) {
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &zerotrap, sizeof zerotrap);
+        if (nhfp->fieldlevel)
+            sfo_trap(nhfp, &zerotrap, "trap", "trap", 1);
+    }
 }
 
 /* save all the fruit names and ID's; this is used only in saving whole games
@@ -1172,8 +1458,8 @@ int mode;
  * level routine marks nonexistent fruits by making the fid negative.
  */
 void
-savefruitchn(fd, mode)
-int fd, mode;
+savefruitchn(nhfp)
+NHFILE *nhfp;
 {
     static struct fruit zerofruit;
     register struct fruit *f2, *f1;
@@ -1181,42 +1467,56 @@ int fd, mode;
     f1 = g.ffruit;
     while (f1) {
         f2 = f1->nextf;
-        if (f1->fid >= 0 && perform_bwrite(mode))
-            bwrite(fd, (genericptr_t) f1, sizeof *f1);
-        if (release_data(mode))
+        if (f1->fid >= 0 && perform_bwrite(nhfp)) {
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t) f1, sizeof *f1);
+            if (nhfp->fieldlevel)
+                sfo_fruit(nhfp, f1, "fruit", "fruit", 1);
+       }
+        if (release_data(nhfp))
             dealloc_fruit(f1);
         f1 = f2;
     }
-    if (perform_bwrite(mode))
-        bwrite(fd, (genericptr_t) &zerofruit, sizeof zerofruit);
-    if (release_data(mode))
+    if (perform_bwrite(nhfp)) {
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &zerofruit, sizeof zerofruit);
+        if (nhfp->fieldlevel)
+            sfo_fruit(nhfp, &zerofruit, "fruit", "terminator", 1);
+    }
+    if (release_data(nhfp))
         g.ffruit = 0;
 }
 
 void
-store_plname_in_file(fd)
-int fd;
+store_plname_in_file(nhfp)
+NHFILE *nhfp;
 {
     int plsiztmp = PL_NSIZ;
 
-    bufoff(fd);
-    /* bwrite() before bufon() uses plain write() */
-    bwrite(fd, (genericptr_t) &plsiztmp, sizeof plsiztmp);
-    bwrite(fd, (genericptr_t) g.plname, plsiztmp);
-    bufon(fd);
+    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) g.plname, plsiztmp);
+        bufon(nhfp->fd);
+    }
+    if (nhfp->fieldlevel) {
+        sfo_int(nhfp, &plsiztmp, "plname", "plname_size", 1);
+        sfo_str(nhfp, g.plname, "plname", "g.plname", plsiztmp);
+    }
     return;
 }
 
 STATIC_OVL void
-save_msghistory(fd, mode)
-int fd, mode;
+save_msghistory(nhfp)
+NHFILE *nhfp;
 {
     char *msg;
     int msgcount = 0, msglen;
     int minusone = -1;
     boolean init = TRUE;
 
-    if (perform_bwrite(mode)) {
+    if (perform_bwrite(nhfp)) {
         /* ask window port for each message in sequence */
         while ((msg = getmsghistory(init)) != 0) {
             init = FALSE;
@@ -1227,19 +1527,28 @@ int fd, mode;
                no need to modify msg[] since terminator isn't written */
             if (msglen > BUFSZ - 1)
                 msglen = BUFSZ - 1;
-            bwrite(fd, (genericptr_t) &msglen, sizeof msglen);
-            bwrite(fd, (genericptr_t) msg, msglen);
+            if (nhfp->structlevel) {
+                bwrite(nhfp->fd, (genericptr_t) &msglen, sizeof msglen);
+                bwrite(nhfp->fd, (genericptr_t) msg, msglen);
+            }
+            if (nhfp->fieldlevel) {
+                sfo_int(nhfp, &msglen, "msghistory", "msghistory_length", 1);
+                sfo_str(nhfp, msg, "msghistory", "msg", msglen);
+            }
             ++msgcount;
         }
-        bwrite(fd, (genericptr_t) &minusone, sizeof (int));
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &minusone, sizeof (int));
+        if (nhfp->fieldlevel)
+            sfo_int(nhfp, &minusone, "msghistory", "msghistory_length", 1);
     }
     debugpline1("Stored %d messages into savefile.", msgcount);
     /* note: we don't attempt to handle release_data() here */
 }
 
 void
-store_savefileinfo(fd)
-int fd;
+store_savefileinfo(nhfp)
+NHFILE *nhfp;
 {
     /* sfcap (decl.c) describes the savefile feature capabilities
      * that are supported by this port/platform build.
@@ -1252,10 +1561,15 @@ int fd;
      * being used to read the information from an existing savefile.
      */
 
-    bufoff(fd);
-    /* bwrite() before bufon() uses plain write() */
-    bwrite(fd, (genericptr_t) &sfsaveinfo, (unsigned) sizeof sfsaveinfo);
-    bufon(fd);
+    if (nhfp->structlevel) {
+        bufoff(nhfp->fd);
+        /* bwrite() before bufon() uses plain write() */
+        bwrite(nhfp->fd, (genericptr_t) &sfsaveinfo, (unsigned) sizeof sfsaveinfo);
+        bufon(nhfp->fd);
+    }
+    if (nhfp->fieldlevel) {
+        sfo_savefile_info(nhfp, &sfsaveinfo, "savefileinfo", "savefile_info", 1);
+    }
     return;
 }
 
@@ -1300,8 +1614,12 @@ void
 free_dungeons()
 {
 #ifdef FREE_ALL_MEMORY
-    savelevchn(0, FREE_SAVE);
-    save_dungeon(0, FALSE, TRUE);
+    NHFILE tnhfp;
+
+    zero_nhfile(&tnhfp);    /* also sets fd to -1 */
+    tnhfp.mode = FREEING;
+    savelevchn(&tnhfp);
+    save_dungeon(&tnhfp, FALSE, TRUE);
 #endif
     return;
 }
@@ -1309,9 +1627,13 @@ free_dungeons()
 void
 freedynamicdata()
 {
+    NHFILE tnhfp;
+
 #if defined(UNIX) && defined(MAIL)
     free_maildata();
 #endif
+    zero_nhfile(&tnhfp);    /* also sets fd to -1 */
+    tnhfp.mode = FREEING;
     unload_qtlist();
     free_menu_coloring();
     free_invbuf();           /* let_to_name (invent.c) */
@@ -1319,16 +1641,16 @@ freedynamicdata()
     msgtype_free();
     tmp_at(DISP_FREEMEM, 0); /* temporary display effects */
 #ifdef FREE_ALL_MEMORY
-#define free_current_level() savelev(-1, -1, FREE_SAVE)
-#define freeobjchn(X) (saveobjchn(0, X, FREE_SAVE), X = 0)
-#define freemonchn(X) (savemonchn(0, X, FREE_SAVE), X = 0)
-#define freefruitchn() savefruitchn(0, FREE_SAVE)
-#define freenames() savenames(0, FREE_SAVE)
-#define free_killers() save_killers(0, FREE_SAVE)
-#define free_oracles() save_oracles(0, FREE_SAVE)
-#define free_waterlevel() save_waterlevel(0, FREE_SAVE)
-#define free_timers(R) save_timers(0, FREE_SAVE, R)
-#define free_light_sources(R) save_light_sources(0, FREE_SAVE, R)
+#define free_current_level() savelev(&tnhfp, -1)
+#define freeobjchn(X) (saveobjchn(&tnhfp, X), X = 0)
+#define freemonchn(X) (savemonchn(&tnhfp, X), X = 0)
+#define freefruitchn() savefruitchn(&tnhfp)
+#define freenames() savenames(&tnhfp)
+#define free_killers() save_killers(&tnhfp)
+#define free_oracles() save_oracles(&tnhfp)
+#define free_waterlevel() save_waterlevel(&tnhfp)
+#define free_timers(R) save_timers(&tnhfp, R)
+#define free_light_sources(R) save_light_sources(&tnhfp, R)
 #define free_animals() mon_animal_list(FALSE)
 
     /* move-specific data */
diff --git a/src/sfascii.c b/src/sfascii.c
new file mode 100644 (file)
index 0000000..31e9438
--- /dev/null
@@ -0,0 +1,1112 @@
+/* NetHack 3.6 sfascii.c $NHDT-Date$  $NHDT-Branch$:$NHDT-Revision$ */
+/* Copyright (c) Michael Allison, 2019. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "integer.h"
+#include "sfprocs.h"
+
+static void FDECL(put_savefield, (NHFILE *, char *, size_t));
+char *FDECL(get_savefield, (NHFILE *, char *, size_t));
+#ifdef SAVEFILE_DEBUGGING
+void FDECL(report_problem_ascii, (NHFILE *, const char *, const char *, const char *));
+#endif
+
+struct sf_procs ascii_sfo_procs = {
+    "-ascii",
+    {
+        ascii_sfo_aligntyp,
+        ascii_sfo_any,
+        ascii_sfo_bitfield,
+        ascii_sfo_boolean,
+        ascii_sfo_char,
+        ascii_sfo_genericptr,
+        ascii_sfo_int,
+        ascii_sfo_long,
+        ascii_sfo_schar,
+        ascii_sfo_short,
+        ascii_sfo_size_t,
+        ascii_sfo_time_t,
+        ascii_sfo_unsigned,
+        ascii_sfo_uchar,
+        ascii_sfo_uint,
+        ascii_sfo_ulong,
+        ascii_sfo_ushort,
+        ascii_sfo_xchar,
+        ascii_sfo_str,
+        ascii_sfo_addinfo,
+    }
+};
+
+struct sf_procs ascii_sfi_procs =
+{
+    "-ascii",
+    {
+        ascii_sfi_aligntyp,
+        ascii_sfi_any,
+        ascii_sfi_bitfield,
+        ascii_sfi_boolean,
+        ascii_sfi_char,
+        ascii_sfi_genericptr,
+        ascii_sfi_int,
+        ascii_sfi_long,
+        ascii_sfi_schar,
+        ascii_sfi_short,
+        ascii_sfi_size_t,
+        ascii_sfi_time_t,
+        ascii_sfi_unsigned,
+        ascii_sfi_uchar,
+        ascii_sfi_uint,
+        ascii_sfi_ulong,
+        ascii_sfi_ushort,
+        ascii_sfi_xchar,
+        ascii_sfi_str,
+        ascii_sfi_addinfo,
+    }
+};
+
+static char linebuf[BUFSZ];
+static char outbuf[BUFSZ];
+
+/*
+ *----------------------------------------------------------------------------
+ * sfo_def_ routines
+ *
+ * Default output routines.
+ *
+ *----------------------------------------------------------------------------
+ */
+void
+ascii_sfo_any(nhfp, d_any, myparent, myname, cnt)
+NHFILE *nhfp;
+union any *d_any;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "any";
+
+    Sprintf(outbuf, "%llx", (unsigned long long) d_any->a_void);
+    put_savefield(nhfp, outbuf, BUFSZ);
+
+    Sprintf(outbuf, "%lu", d_any->a_ulong);
+    put_savefield(nhfp, outbuf, BUFSZ);
+
+    Sprintf(outbuf, "%ld", d_any->a_long);
+    put_savefield(nhfp, outbuf, BUFSZ);
+
+    Sprintf(outbuf, "%d", d_any->a_uint);
+    put_savefield(nhfp, outbuf, BUFSZ);
+
+    Sprintf(outbuf, "%d", d_any->a_int);;
+    put_savefield(nhfp, outbuf, BUFSZ);
+
+    Sprintf(outbuf, "%hd", (short) d_any->a_char);
+    put_savefield(nhfp, outbuf, BUFSZ);
+
+#if 0
+    sfo_genericptr(nhfp, d_any->a_void, parent, "a_void", 1);      /* (genericptr_t)    */
+    sfo_genericptr(nhfp, d_any->a_obj, parent, "a_obj", 1);        /* (struct obj *)    */
+    sfo_genericptr(nhfp, d_any->a_monst, parent, "a_monst", 1);    /* (struct monst *)  */
+    sfo_int(nhfp, &d_any->a_int, parent, "a_int", 1);              /* (int)             */
+    sfo_char(nhfp, &d_any->a_char, parent, "a_char", 1);           /* (char)            */
+    sfo_schar(nhfp, &d_any->a_schar, parent, "a_schar", 1);        /* (schar)           */
+    sfo_uchar(nhfp, &d_any->a_uchar, parent, "a_uchar", 1);        /* (uchar)           */
+    sfo_uint(nhfp, &d_any->a_uint, parent, "a_uint", 1);           /* (unsigned int)    */
+    sfo_long(nhfp, &d_any->a_long, parent, "a_long", 1);           /* (long)            */
+    sfo_ulong(nhfp, &d_any->a_ulong, parent, "a_ulong", 1);        /* (unsigned long)   */
+    sfo_genericptr(nhfp, d_any->a_iptr, parent, "a_iptr", 1);      /* (int *)           */
+    sfo_genericptr(nhfp, d_any->a_lptr, parent, "a_lptr", 1);      /* (long *)          */
+    sfo_genericptr(nhfp, d_any->a_ulptr, parent, "a_ulptr", 1);    /* (unsigned long *) */
+    sfo_genericptr(nhfp, d_any->a_uptr, parent, "a_uptr", 1);      /* (unsigned *)      */my
+    sfo_genericptr(nhfp, d_any->a_string, parent, "a_string", 1);  /* (const char *)    */
+    sfo_ulong(nhfp, &d_any->a_mask32, parent, "a_mask32", 1);      /* (unsigned long)   */
+#endif
+}
+
+void
+ascii_sfo_aligntyp(nhfp, d_aligntyp, myparent, myname, cnt)
+NHFILE *nhfp;
+aligntyp *d_aligntyp;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int itmp;
+    const char *parent = "aligntyp";
+
+    itmp = (int) *d_aligntyp;
+    Sprintf(outbuf, "%d", (short) itmp);
+    put_savefield(nhfp, outbuf, BUFSZ);
+}
+
+void
+ascii_sfo_bitfield(nhfp, d_bitfield, myparent, myname, cnt)
+NHFILE *nhfp;
+uint8_t *d_bitfield;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "bitfield";
+
+    /* for bitfields, cnt is the number of bits, not an array */
+    Sprintf(outbuf, "%hu", (unsigned short) *d_bitfield);
+    put_savefield(nhfp, outbuf, BUFSZ);
+}
+
+void
+ascii_sfo_boolean(nhfp, d_boolean, myparent, myname, cnt)
+NHFILE *nhfp;
+boolean *d_boolean;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    const char *parent = "boolean";
+
+    for (i = 0; i < cnt; ++i) {
+        if (nhfp->fpdebug)
+            fprintf(nhfp->fpdebug, "(%s)\n", (*d_boolean) ? "TRUE" : "FALSE");
+        Sprintf(outbuf, "%s", *d_boolean ? "true" : "false");
+        put_savefield(nhfp, outbuf, BUFSZ);
+        d_boolean++;
+    }
+}
+
+void
+ascii_sfo_char(nhfp, d_char, myparent, myname, cnt)
+NHFILE *nhfp;
+char *d_char;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i = cnt;
+    const char *parent = "char";
+
+    for (i = 0; i < cnt; ++i) {
+        if (nhfp->fpdebug)
+            fprintf(nhfp->fpdebug, "(%s)\n", d_char ? d_char : "");
+        Sprintf(outbuf, "%hd", (short) *d_char);
+        put_savefield(nhfp, outbuf, BUFSZ);
+        d_char++;
+    }
+}
+
+void
+ascii_sfo_genericptr(nhfp, d_genericptr, myparent, myname, cnt)
+NHFILE *nhfp;
+genericptr_t *d_genericptr;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    unsigned long tmp;
+    char *byteptr = (char *) d_genericptr;
+    const char *parent = "genericptr";
+
+    /*
+     * sbrooms is an array of pointers to mkroom.
+     * That array dimension is MAX_SUBROOMS.
+     * Even though the pointers themselves won't
+     * be valid, we need to account for the existence
+     * of that array and perhaps zero or non-zero.
+     */
+    for (i = 0; i < cnt; ++i) {
+        tmp = (*d_genericptr) ? 1UL : 0UL;
+        Sprintf(outbuf, "%08lu", tmp);
+        put_savefield(nhfp, outbuf, BUFSZ);
+        if (cnt > 1) {
+            byteptr += sizeof(void *);
+            d_genericptr = (genericptr_t) byteptr;
+       }
+    }
+}
+
+void
+ascii_sfo_int(nhfp, d_int, myparent, myname, cnt)
+NHFILE *nhfp;
+int *d_int;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    const char *parent = "int";
+
+    for (i = 0; i < cnt; ++i) {
+        Sprintf(outbuf, "%d", *d_int);
+        put_savefield(nhfp, outbuf, BUFSZ);
+        d_int++;
+    }
+}
+
+void
+ascii_sfo_long(nhfp, d_long, myparent, myname, cnt)
+NHFILE *nhfp;
+long *d_long;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    const char *parent = "long";
+
+    for (i = 0; i < cnt; ++i) {
+        Sprintf(outbuf, "%ld", *d_long);
+        put_savefield(nhfp, outbuf, BUFSZ);
+        d_long++;
+    }
+}
+
+void
+ascii_sfo_schar(nhfp, d_schar, myparent, myname, cnt)
+NHFILE *nhfp;
+schar *d_schar;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i, itmp;
+    const char *parent = "schar";
+
+    for (i = 0; i < cnt; ++i) {
+        itmp = (int) *d_schar;
+        Sprintf(outbuf, "%d", itmp);
+        put_savefield(nhfp, outbuf, BUFSZ);
+        d_schar++;
+    }
+}
+
+void
+ascii_sfo_short(nhfp, d_short, myparent, myname, cnt)
+NHFILE *nhfp;
+short *d_short;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    const char *parent = "short";
+
+    for (i = 0; i < cnt; ++i) {
+        Sprintf(outbuf, "%hd", *d_short);
+        put_savefield(nhfp, outbuf, BUFSZ);
+        d_short++;
+    }
+}
+
+void
+ascii_sfo_size_t(nhfp, d_size_t, myparent, myname, cnt)
+NHFILE *nhfp;
+size_t *d_size_t;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    const char *parent = "size_t";
+
+    for (i = 0; i < cnt; ++i) {
+        unsigned long ul = (unsigned long) *d_size_t;
+
+        Sprintf(outbuf, "%lu", ul);
+        put_savefield(nhfp, outbuf, BUFSZ);
+        d_size_t++;
+    }
+}
+
+void
+ascii_sfo_time_t(nhfp, d_time_t, myparent, myname, cnt)
+NHFILE *nhfp;
+time_t *d_time_t;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "time_t";
+
+    Sprintf(outbuf, "%s", yyyymmddhhmmss(*d_time_t));
+    put_savefield(nhfp, outbuf, BUFSZ);
+}
+
+void
+ascii_sfo_unsigned(nhfp, d_unsigned, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned *d_unsigned;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    ascii_sfo_uint(nhfp, d_unsigned, myparent, myname, cnt);
+}
+
+void
+ascii_sfo_uchar(nhfp, d_uchar, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned char *d_uchar;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    const char *parent = "uchar";
+
+    for (i = 0; i < cnt; ++i) {
+        unsigned short us = (unsigned short) *d_uchar;
+
+        Sprintf(outbuf, "%hu", us);
+        put_savefield(nhfp, outbuf, BUFSZ);
+        d_uchar++;
+    }
+}
+
+void
+ascii_sfo_uint(nhfp, d_uint, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned int *d_uint;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    const char *parent = "uint";
+
+    for (i = 0; i < cnt; ++i) {
+        Sprintf(outbuf, "%u", *d_uint);
+        put_savefield(nhfp, outbuf, BUFSZ);
+        d_uint++;
+    }
+}
+
+void
+ascii_sfo_ulong(nhfp, d_ulong, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned long *d_ulong;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    const char *parent = "ulong";
+
+    for (i = 0; i < cnt; ++i) {
+        Sprintf(outbuf, "%lu", *d_ulong);
+        put_savefield(nhfp, outbuf, BUFSZ);
+        d_ulong++;
+    }
+}
+
+void
+ascii_sfo_ushort(nhfp, d_ushort, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned short *d_ushort;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    const char *parent = "ushort";
+
+    for (i = 0; i < cnt; ++i) {
+        Sprintf(outbuf, "%hu", *d_ushort);
+        put_savefield(nhfp, outbuf, BUFSZ);
+        d_ushort++;
+    }
+}
+
+void
+ascii_sfo_xchar(nhfp, d_xchar, myparent, myname, cnt)
+NHFILE *nhfp;
+xchar *d_xchar;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    const char *parent = "xchar";
+
+    for (i = 0; i < cnt; ++i) {
+        short tmp;
+
+        tmp = (short) *d_xchar;
+        Sprintf(outbuf, "%hu", tmp);
+        put_savefield(nhfp, outbuf, BUFSZ);
+        d_xchar++;
+    }
+}
+
+static char strbuf[BUFSZ * 4];
+
+void
+ascii_sfo_str(nhfp, d_str, myparent, myname, cnt)
+NHFILE *nhfp;
+char *d_str;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i, j, intval;
+    const char *parent = "str";
+    char sval[QBUFSZ], *src = d_str, *dest = strbuf;
+
+    /* cnt is the number of characters */
+    for (i = 0; i < cnt; ++i) {
+        if ((*src < 32) || (*src == '\\') || (*src > 128)) {
+            *dest++ = '\\';
+            intval = (int) *src++;
+            Sprintf(sval, "%03d", intval);
+            for (j = 0; j < 3; ++j)
+                *dest++ = sval[j];
+        } else {
+            *dest++ = *src++;
+        }
+    }
+    put_savefield(nhfp, strbuf, BUFSZ * 4);
+}
+
+void
+ascii_sfo_addinfo(nhfp, parent, action, myname, index)
+NHFILE *nhfp;
+const char *parent, *action, *myname;
+int index;
+{
+    /* ignored */
+}
+
+
+static void
+put_savefield(nhfp, outbuf, outbufsz)
+NHFILE *nhfp;
+char *outbuf;
+size_t outbufsz;
+{
+    nhfp->count++;
+    fprintf(nhfp->fpdef, "%07ld|%s\n", nhfp->count, outbuf);
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * ascii_sfi_ routines called from functions in sfi_base.c
+ *----------------------------------------------------------------------------
+ */
+void
+ascii_sfi_any(nhfp, d_any, myparent, myname, cnt)
+NHFILE *nhfp;
+union any *d_any;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *rstr;
+    long long tmp;
+    const char *parent = "any";
+
+    rstr = get_savefield(nhfp, linebuf, BUFSZ);
+    tmp = atoll(rstr);
+    d_any->a_void = (void *) tmp;
+
+    rstr = get_savefield(nhfp, linebuf, BUFSZ);
+    tmp = atoll(rstr);
+    d_any->a_ulong = (unsigned long) tmp;
+
+    rstr = get_savefield(nhfp, linebuf, BUFSZ);
+    d_any->a_long = atol(rstr);
+
+    rstr = get_savefield(nhfp, linebuf, BUFSZ);
+    tmp = atoll(rstr);
+    d_any->a_uint = (unsigned int) tmp;
+
+    rstr = get_savefield(nhfp, linebuf, BUFSZ);
+    d_any->a_int = atoi(rstr);
+
+    rstr = get_savefield(nhfp, linebuf, BUFSZ);
+    d_any->a_char = (char) atoi(rstr);
+
+#if 0
+    sfi_genericptr(nhfp, d_any->a_void, parent, "a_void", 1);
+    sfi_genericptr(nhfp, d_any->a_obj, parent, "a_obj", 1);
+    sfi_genericptr(nhfp, d_any->a_monst, parent, "a_monst", 1);
+    sfi_int(nhfp, &d_any->a_int, parent, "a_int", 1);
+    sfi_char(nhfp, &d_any->a_char, parent, "a_char", 1);
+    sfi_schar(nhfp, &d_any->a_schar, parent, "a_schar", 1);
+    sfi_uchar(nhfp, &d_any->a_uchar, parent, "a_uchar", 1);
+    sfi_uint(nhfp, &d_any->a_uint, parent, "a_uint", 1);
+    sfi_long(nhfp, &d_any->a_long, parent, "a_long", 1);
+    sfi_ulong(nhfp, &d_any->a_ulong, parent, "a_ulong", 1);
+    sfi_genericptr(nhfp, d_any->a_iptr, parent, "a_iptr", 1);
+    sfi_genericptr(nhfp, d_any->a_lptr, parent, "a_lptr", 1);
+    sfi_genericptr(nhfp, d_any->a_ulptr, parent, "a_ulptr", 1);
+    sfi_genericptr(nhfp, d_any->a_uptr, parent, "a_uptr", 1);
+    sfi_genericptr(nhfp, d_any->a_string, parent, "a_string", 1);
+    sfi_ulong(nhfp, &d_any->a_mask32, parent, "a_mask32", 1);
+#endif
+}
+
+void
+ascii_sfi_aligntyp(nhfp, d_aligntyp, myparent, myname, cnt)
+NHFILE *nhfp;
+aligntyp *d_aligntyp;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *rstr;
+    aligntyp tmp;
+    long long lltmp;
+    const char *parent = "aligntyp";
+
+    rstr = get_savefield(nhfp, linebuf, BUFSZ);
+    lltmp = atoll(rstr);
+    tmp = (aligntyp) lltmp;
+#ifdef SAVEFILE_DEBUGGING
+    if (nhfp->structlevel && tmp != *d_aligntyp)
+        report_problem_ascii(nhfp, myparent, myname, parent);
+    else
+#endif
+    *d_aligntyp = tmp;
+}
+
+void
+ascii_sfi_bitfield(nhfp, d_bitfield, myparent, myname, cnt)
+NHFILE *nhfp;
+uint8_t *d_bitfield;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *rstr;
+    uint8_t tmp;
+    const char *parent = "bitfield";
+
+    /* cnt is the number of bits in the bitfield, not an array dimension */
+    rstr = get_savefield(nhfp, linebuf, BUFSZ);
+    tmp = (uint8_t) atoi(rstr);
+#ifdef SAVEFILE_DEBUGGING
+    if (nhfp->structlevel && tmp != *d_bitfield)
+        report_problem_ascii(nhfp, myparent, myname, parent);
+        else
+#endif
+    *d_bitfield = tmp;
+}
+
+void
+ascii_sfi_boolean(nhfp, d_boolean, myparent, myname, cnt)
+NHFILE *nhfp;
+boolean *d_boolean;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *rstr;
+    int i;
+    const char *parent = "boolean";
+
+    for (i = 0; i < cnt; ++i) {
+        rstr = get_savefield(nhfp, linebuf, BUFSZ);
+#ifdef SAVEFILE_DEBUGGING
+        if (!strcmpi(rstr, "false") &&
+                !strcmpi(rstr, "true"))
+            report_problem_ascii(nhfp, myparent, myname, parent);
+        else
+#endif
+        if (!strcmpi(rstr, "false"))
+            *d_boolean = FALSE;
+        else
+            *d_boolean = TRUE;
+        d_boolean++;
+    }
+}
+
+void
+ascii_sfi_char(nhfp, d_char, myparent, myname, cnt)
+NHFILE *nhfp;
+char *d_char;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *rstr;
+    int i;
+    char tmp;
+    const char *parent = "char";
+
+    for (i = 0; i < cnt; ++i) {
+        rstr = get_savefield(nhfp, linebuf, BUFSZ);
+        tmp = (char) atoi(rstr);
+#ifdef SAVEFILE_DEBUGGING
+        if (nhfp->structlevel && tmp != *d_char)
+            report_problem_ascii(nhfp, myparent, myname, parent);
+        else
+#endif
+        *d_char = tmp;
+        d_char++;
+    }
+}
+
+void
+ascii_sfi_genericptr(nhfp, d_genericptr, myparent, myname, cnt)
+NHFILE *nhfp;
+genericptr_t *d_genericptr;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    long long lltmp;
+    char *rstr;
+    const char *parent = "genericptr";
+    static char *glorkum = "glorkum";
+    char *byteptr = (char *) d_genericptr;
+
+    /*
+     * sbrooms is an array of pointers to mkroom.
+     * That array dimension is MAX_SUBROOMS.
+     * Even though the pointers themselves won't
+     * be valid, we need to account for the existence
+     * of that array.
+     */
+    for (i = 0; i < cnt; ++i) {
+        /* these pointers can't actually be valid */
+        byteptr = (char *) d_genericptr;
+        rstr = get_savefield(nhfp, linebuf, BUFSZ);
+        lltmp = atoll(rstr);
+        *d_genericptr = lltmp ? (genericptr_t) glorkum : (genericptr_t) 0;
+        if (cnt > 1) {
+            byteptr += sizeof(void *);
+            d_genericptr = (genericptr_t) byteptr;
+       }
+    }
+}
+
+void
+ascii_sfi_int(nhfp, d_int, myparent, myname, cnt)
+NHFILE *nhfp;
+int *d_int;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i, tmp;
+    char *rstr;
+    long long lltmp;
+    const char *parent = "int";
+
+    for (i = 0; i < cnt; ++i) {
+        rstr = get_savefield(nhfp, linebuf, BUFSZ);
+        lltmp = atoll(rstr);
+        tmp = (int) lltmp;
+#ifdef SAVEFILE_DEBUGGING
+        if (nhfp->structlevel && tmp != *d_int)
+            report_problem_ascii(nhfp, myparent, myname, parent);
+        else
+#endif
+        *d_int = tmp;
+        d_int++;
+    }
+}
+
+void
+ascii_sfi_long(nhfp, d_long, myparent, myname, cnt)
+NHFILE *nhfp;
+long *d_long;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    long tmp;
+    long long lltmp;
+    char *rstr;
+    const char *parent = "long";
+
+    for (i = 0; i < cnt; ++i) {
+        rstr = get_savefield(nhfp, linebuf, BUFSZ);
+        lltmp = atoll(rstr);
+        tmp = (long) lltmp;
+#ifdef SAVEFILE_DEBUGGING
+        if (nhfp->structlevel && tmp != *d_long)
+            report_problem_ascii(nhfp, myparent, myname, parent);
+        else
+#endif
+        *d_long = tmp;
+        d_long++;
+    }
+}
+
+void
+ascii_sfi_schar(nhfp, d_schar, myparent, myname, cnt)
+NHFILE *nhfp;
+schar *d_schar;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    schar tmp;
+    char *rstr;
+    const char *parent = "schar";
+
+    for (i = 0; i < cnt; ++i) {
+        rstr = get_savefield(nhfp, linebuf, BUFSZ);
+        tmp = (schar) atoi(rstr);
+#ifdef SAVEFILE_DEBUGGING
+        if (nhfp->structlevel && tmp != *d_schar)
+            report_problem_ascii(nhfp, myparent, myname, parent);
+        else
+#endif
+        *d_schar = tmp;
+        d_schar++;
+    }
+}
+
+void
+ascii_sfi_short(nhfp, d_short, myparent, myname, cnt)
+NHFILE *nhfp;
+short *d_short;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    short tmp;
+    char *rstr;
+    const char *parent = "short";
+
+    for (i = 0; i < cnt; ++i) {
+        rstr = get_savefield(nhfp, linebuf, BUFSZ);
+        tmp = (short) atoi(rstr);
+#ifdef SAVEFILE_DEBUGGING
+        if (nhfp->structlevel && tmp != *d_short)
+            report_problem_ascii(nhfp, myparent, myname, parent);
+        else
+#endif
+        *d_short = tmp;
+        d_short++;
+    }
+}
+
+void
+ascii_sfi_size_t(nhfp, d_size_t, myparent, myname, cnt)
+NHFILE *nhfp;
+size_t *d_size_t;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    size_t tmp;
+    char *rstr;
+    const char *parent = "size_t";
+
+    for (i = 0; i < cnt; ++i) {
+        rstr = get_savefield(nhfp, linebuf, BUFSZ);
+        tmp = (size_t) atol(rstr);
+#ifdef SAVEFILE_DEBUGGING
+        if (nhfp->structlevel && tmp != *d_size_t)
+            report_problem_ascii(nhfp, myparent, myname, parent);
+        else
+#endif
+        *d_size_t = tmp;
+        d_size_t++;
+    }
+}
+
+void
+ascii_sfi_time_t(nhfp, d_time_t, myparent, myname, cnt)
+NHFILE *nhfp;
+time_t *d_time_t;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    time_t tmp;
+    char *rstr;
+    const char *parent = "time_t";
+
+    for (i = 0; i < cnt; ++i) {
+        rstr = get_savefield(nhfp, linebuf, BUFSZ);
+        tmp = time_from_yyyymmddhhmmss(rstr);
+#ifdef SAVEFILE_DEBUGGING
+        if (nhfp->structlevel && tmp != *d_time_t)
+            report_problem_ascii(nhfp, myparent, myname, parent);
+        else
+#endif
+        *d_time_t = tmp;
+        d_time_t++;
+    }
+}
+
+void
+ascii_sfi_unsigned(nhfp, d_unsigned, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned *d_unsigned;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    /* deferal */
+    ascii_sfi_uint(nhfp, d_unsigned, myparent, myname, cnt);
+}
+
+void
+ascii_sfi_uchar(nhfp, d_uchar, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned char *d_uchar;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    uchar tmp;
+    int i, itmp;
+    char *rstr;
+    const char *parent = "uchar";
+
+    for (i = 0; i < cnt; ++i) {
+        rstr = get_savefield(nhfp, linebuf, BUFSZ);
+        itmp = atoi(rstr);
+        tmp = (char ) itmp;
+#ifdef SAVEFILE_DEBUGGING
+        if (nhfp->structlevel && tmp != *d_uchar)
+            report_problem_ascii(nhfp, myparent, myname, parent);
+        else
+#endif
+        *d_uchar = tmp;
+        d_uchar++;
+    }
+}
+
+void
+ascii_sfi_uint(nhfp, d_uint, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned int *d_uint;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    char *rstr;
+    unsigned int tmp;
+    long long lltmp;
+    const char *parent = "uint";
+
+    for (i = 0; i < cnt; ++i) {
+        rstr = get_savefield(nhfp, linebuf, BUFSZ);
+        lltmp = atoll(rstr);
+        tmp = (unsigned int) lltmp;
+#ifdef SAVEFILE_DEBUGGING
+        if (nhfp->structlevel && tmp != *d_uint)
+            report_problem_ascii(nhfp, myparent, myname, parent);
+        else
+#endif
+        *d_uint = tmp;
+        d_uint++;
+    }
+}
+
+void
+ascii_sfi_ulong(nhfp, d_ulong, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned long *d_ulong;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    unsigned long tmp;
+    long long lltmp;
+    char *rstr;
+    const char *parent = "ulong";
+
+    for (i = 0; i < cnt; ++i) {
+        rstr = get_savefield(nhfp, linebuf, BUFSZ);
+        lltmp = atoll(rstr);
+        tmp = (unsigned long) lltmp;
+#ifdef SAVEFILE_DEBUGGING
+        if (nhfp->structlevel && tmp != *d_ulong)
+            report_problem_ascii(nhfp, myparent, myname, parent);
+        else
+#endif
+        *d_ulong = tmp;
+        d_ulong++;
+    }
+}
+
+void
+ascii_sfi_ushort(nhfp, d_ushort, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned short *d_ushort;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    short tmp;
+    long long lltmp;
+    char *rstr;
+    const char *parent = "ushort";
+
+    for (i = 0; i < cnt; ++i) {
+        rstr = get_savefield(nhfp, linebuf, BUFSZ);
+        lltmp = atoll(rstr);
+        tmp = (unsigned short) lltmp;
+#ifdef SAVEFILE_DEBUGGING
+        if (nhfp->structlevel && tmp != *d_ushort)
+            report_problem_ascii(nhfp, myparent, myname, parent);
+        else
+#endif
+        *d_ushort = tmp;
+        d_ushort++;
+    }
+}
+
+void
+ascii_sfi_xchar(nhfp, d_xchar, myparent, myname, cnt)
+NHFILE *nhfp;
+xchar *d_xchar;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    xchar tmp;
+    int i, itmp;
+    char *rstr;
+    const char *parent = "xchar";
+
+    for (i = 0; i < cnt; ++i) {
+        rstr = get_savefield(nhfp, linebuf, BUFSZ);
+        itmp = atoi(rstr);
+        tmp = (xchar) itmp;
+#ifdef SAVEFILE_DEBUGGING
+        if (nhfp->structlevel && tmp != *d_xchar)
+            report_problem_ascii(nhfp, myparent, myname, parent);
+        else
+#endif
+        *d_xchar = tmp;
+        d_xchar++;
+    }
+}
+
+static char strbuf[BUFSZ * 4];
+
+void
+ascii_sfi_str(nhfp, d_str, myparent, myname, cnt)
+NHFILE *nhfp;
+char *d_str;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i, j, sval;
+    char n[4], *rstr;
+    const char *parent = "str";
+    char *src, *dest;
+#ifdef SAVEFILE_DEBUGGING
+    boolean match;
+    char testbuf[BUFSZ];
+#endif
+
+    /* cnt is the length of the string */
+    rstr = get_savefield(nhfp, strbuf, BUFSZ * 4);
+    src = rstr;
+    dest =
+#ifdef SAVEFILE_DEBUGGING
+            testbuf;
+#else
+            d_str;
+#endif
+
+    for (i = 0; i < cnt; ++i) {
+        if (*src == '\\') {
+            src++;
+            for (j = 0; j < 4; ++j) {
+                if (j < 3)
+                    n[j] = *src++;
+                else
+                    n[j] = '\0';
+           }
+            sval = atoi(n);
+            *dest++ = (char) sval;
+        } else
+            *dest++ = *src++;
+    }
+#ifdef SAVEFILE_DEBUGGING
+    if (nhfp->structlevel) {
+        src = testbuf;
+        dest = d_str;
+        match = TRUE;
+        for (i = 0; i < cnt; ++i) {
+            if (*src++ != *dest++)
+                match = FALSE;
+        }
+        if (!match)
+            report_problem_ascii(nhfp, myparent, myname, parent);
+        else {
+            src = testbuf;
+            dest = d_str;
+            for (i = 0; i < cnt; ++i)
+                *dest++ = *src++;
+        }
+    }
+#endif
+}
+void
+ascii_sfi_addinfo(nhfp, myparent, action, myname, index)
+NHFILE *nhfp;
+const char *myparent, *action, *myname;
+int index;
+{
+    /* not doing anything here */
+}
+
+char *
+get_savefield(nhfp, inbuf, inbufsz)
+NHFILE *nhfp;
+char *inbuf;
+size_t inbufsz;
+{
+    boolean rv = TRUE; /* assume successful parse */
+    char *ep, *sep;
+
+    if (fgets(inbuf, (int) inbufsz, nhfp->fpdef)) {
+        nhfp->count++;
+        ep = index(inbuf, '\n');
+        if (!ep) {  /* newline missing */
+            if (strlen(inbuf) < (inbufsz - 2)) {
+                /* likely the last line of file is just
+                   missing a newline; process it anyway  */
+                ep = eos(inbuf);
+            }
+        }
+        if (ep)
+            *ep = '\0'; /* remove newline */
+        sep = index(inbuf, '|');
+        if (sep)
+            sep++;
+        
+        return sep;
+    }
+    inbuf[0] = '\0';
+    nhfp->eof = TRUE;
+    return inbuf;
+}
+
+#ifdef SAVEFILE_DEBUGGING
+void
+report_problem_ascii(nhfp, s1, s2, s3)
+NHFILE *nhfp;
+const char *s1, *s2, *s3;
+{
+    fprintf(nhfp->fpdebug, "faulty value preservation "
+            "(%ld, %s, %s, %s)\n", nhfp->count, s1, s2, s3);
+}
+#endif
+
+
diff --git a/src/sfbase.c b/src/sfbase.c
new file mode 100644 (file)
index 0000000..fa28ad5
--- /dev/null
@@ -0,0 +1,640 @@
+/* NetHack 3.6 sf_base.c $NHDT-Date$  $NHDT-Branch$:$NHDT-Revision$ */
+/* Copyright (c) Michael Allison, 2019. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+#include "hack.h"
+#include "integer.h"
+#include "sfprocs.h"
+
+struct sf_procs sfoprocs[4], sfiprocs[4],
+                zerosfoprocs = {0}, zerosfiprocs = {0};
+
+void FDECL(sfi_log, (NHFILE *, const char *, const char *, const char *, int));
+
+/*
+ *----------------------------------------------------------------------------
+ * initialize the function pointers. These are called from initoptions_init().
+ *----------------------------------------------------------------------------
+ */
+
+void
+sf_init()
+{
+    sfoprocs[invalid] = zerosfoprocs;
+    sfiprocs[invalid] = zerosfiprocs;
+    sfoprocs[historical] = zerosfoprocs;
+    sfiprocs[historical] = zerosfiprocs;
+    sfoprocs[lendian] = lendian_sfo_procs;
+    sfiprocs[lendian] = lendian_sfi_procs;
+    sfoprocs[ascii] = ascii_sfo_procs;
+    sfiprocs[ascii] = ascii_sfi_procs;
+}
+
+/*
+ *----------------------------------------
+ * routines called from engine core and
+ * from functions in generated sfdata.c
+ *----------------------------------------
+ */
+
+void
+sfo_any(nhfp, d_any, myparent, myname, cnt)
+ NHFILE *nhfp;
+union any *d_any;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    (*sfoprocs[nhfp->fnidx].fn.sf_any)(nhfp, d_any, myparent, myname, cnt);
+}
+
+void
+sfo_aligntyp(nhfp, d_aligntyp, myparent, myname, cnt)
+NHFILE *nhfp;
+aligntyp *d_aligntyp;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    (*sfoprocs[nhfp->fnidx].fn.sf_aligntyp)(nhfp, d_aligntyp, myparent, myname, cnt);
+}
+
+void
+sfo_bitfield(nhfp, d_bitfield, myparent, myname, cnt)
+NHFILE *nhfp;
+uint8_t *d_bitfield;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    (*sfoprocs[nhfp->fnidx].fn.sf_bitfield)(nhfp, d_bitfield, myparent, myname, cnt);
+}
+
+void
+sfo_boolean(nhfp, d_boolean, myparent, myname, cnt)
+NHFILE *nhfp;
+boolean *d_boolean;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    (*sfoprocs[nhfp->fnidx].fn.sf_boolean)(nhfp, d_boolean, myparent, myname, cnt);
+}
+
+void
+sfo_char(nhfp, d_char, myparent, myname, cnt)
+NHFILE *nhfp;
+char *d_char;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    (*sfoprocs[nhfp->fnidx].fn.sf_char)(nhfp, d_char, myparent, myname, cnt);
+}
+
+void
+sfo_genericptr(nhfp, d_genericptr, myparent, myname, cnt)
+NHFILE *nhfp;
+genericptr_t d_genericptr;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    (*sfoprocs[nhfp->fnidx].fn.sf_genericptr)(nhfp, d_genericptr, myparent, myname, cnt);
+}
+
+void
+sfo_int(nhfp, d_int, myparent, myname, cnt)
+NHFILE *nhfp;
+int *d_int;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    (*sfoprocs[nhfp->fnidx].fn.sf_int)(nhfp, d_int, myparent, myname, cnt);
+}
+
+void
+sfo_long(nhfp, d_long, myparent, myname, cnt)
+NHFILE *nhfp;
+long *d_long;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    (*sfoprocs[nhfp->fnidx].fn.sf_long)(nhfp, d_long, myparent, myname, cnt);
+}
+
+void
+sfo_schar(nhfp, d_schar, myparent, myname, cnt)
+NHFILE *nhfp;
+schar *d_schar;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    (*sfoprocs[nhfp->fnidx].fn.sf_schar)(nhfp, d_schar, myparent, myname, cnt);
+}
+
+void
+sfo_short(nhfp, d_short, myparent, myname, cnt)
+NHFILE *nhfp;
+short *d_short;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    (*sfoprocs[nhfp->fnidx].fn.sf_short)(nhfp, d_short, myparent, myname, cnt);
+}
+
+void
+sfo_size_t(nhfp, d_size_t, myparent, myname, cnt)
+NHFILE *nhfp;
+size_t *d_size_t;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    (*sfoprocs[nhfp->fnidx].fn.sf_size_t)(nhfp, d_size_t, myparent, myname, cnt);
+}
+
+void
+sfo_time_t(nhfp, d_time_t, myparent, myname, cnt)
+NHFILE *nhfp;
+time_t *d_time_t;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    (*sfoprocs[nhfp->fnidx].fn.sf_time_t)(nhfp, d_time_t, myparent, myname, cnt);
+}
+
+void
+sfo_unsigned(nhfp, d_unsigned, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned *d_unsigned;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    (*sfoprocs[nhfp->fnidx].fn.sf_unsigned)(nhfp, d_unsigned, myparent, myname, cnt);
+}
+
+void
+sfo_uchar(nhfp, d_uchar, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned char *d_uchar;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    (*sfoprocs[nhfp->fnidx].fn.sf_uchar)(nhfp, d_uchar, myparent, myname, cnt);
+}
+
+void
+sfo_uint(nhfp, d_uint, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned int *d_uint;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    (*sfoprocs[nhfp->fnidx].fn.sf_uint)(nhfp, d_uint, myparent, myname, cnt);
+}
+
+void
+sfo_ulong(nhfp, d_ulong, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned long *d_ulong;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    (*sfoprocs[nhfp->fnidx].fn.sf_ulong)(nhfp, d_ulong, myparent, myname, cnt);
+}
+
+void
+sfo_ushort(nhfp, d_ushort, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned short *d_ushort;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    (*sfoprocs[nhfp->fnidx].fn.sf_ushort)(nhfp, d_ushort, myparent, myname, cnt);
+}
+
+void
+sfo_xchar(nhfp, d_xchar, myparent, myname, cnt)
+NHFILE *nhfp;
+xchar *d_xchar;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    (*sfoprocs[nhfp->fnidx].fn.sf_xchar)(nhfp, d_xchar, myparent, myname, cnt);
+}
+
+void
+sfo_str(nhfp, d_str, myparent, myname, cnt)
+NHFILE *nhfp;
+char *d_str;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    (*sfoprocs[nhfp->fnidx].fn.sf_str)(nhfp, d_str, myparent, myname, cnt);
+}
+
+void
+sfo_addinfo(nhfp, parent, action, myname, index)
+NHFILE *nhfp;
+const char *parent, *action, *myname;
+int index;
+{
+    (*sfoprocs[nhfp->fnidx].fn.sf_addinfo)(nhfp, parent, action, myname, index);
+}
+
+/*
+ *----------------------------------------------------------------------------
+ * routines called from core and from functions in generated sfi_data.c
+ *----------------------------------------------------------------------------
+ */
+
+void
+sfi_any(nhfp, d_any, myparent, myname, cnt)
+NHFILE *nhfp;
+union any *d_any;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "any";
+
+    sfi_log(nhfp, myparent, myname, parent, cnt);
+    (*sfiprocs[nhfp->fnidx].fn.sf_any)(nhfp, d_any, myparent, myname, cnt);
+#ifdef DO_DEBUG
+    if (nhfp->fpdebug)
+        fprintf(nhfp->fpdebug, "(%ld)\n", d_any->a_long);
+#endif
+}
+
+void
+sfi_aligntyp(nhfp, d_aligntyp, myparent, myname, cnt)
+NHFILE *nhfp;
+aligntyp *d_aligntyp;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "aligntyp";
+
+    sfi_log(nhfp, myparent, myname, parent, cnt);
+    (*sfiprocs[nhfp->fnidx].fn.sf_aligntyp)(nhfp, d_aligntyp, myparent, myname, cnt);
+#ifdef DO_DEBUG
+    if (nhfp->fpdebug)
+        fprintf(nhfp->fpdebug, "(%d)\n", *d_aligntyp);
+#endif
+}
+
+void
+sfi_bitfield(nhfp, d_bitfield, myparent, myname, cnt)
+NHFILE *nhfp;
+uint8_t *d_bitfield;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "bitfield";
+
+    sfi_log(nhfp, myparent, myname, parent, cnt);
+    (*sfiprocs[nhfp->fnidx].fn.sf_bitfield)(nhfp, d_bitfield, myparent, myname, cnt);
+#ifdef DO_DEBUG
+    if (nhfp->fpdebug)
+        fprintf(nhfp->fpdebug, "(%hd)\n", *d_bitfield);
+#endif
+}
+
+void
+sfi_boolean(nhfp, d_boolean, myparent, myname, cnt)
+NHFILE *nhfp;
+boolean *d_boolean;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "boolean";
+
+    sfi_log(nhfp, myparent, myname, parent, cnt);
+    (*sfiprocs[nhfp->fnidx].fn.sf_boolean)(nhfp, d_boolean, myparent, myname, cnt);
+#ifdef DO_DEBUG
+    if (nhfp->fpdebug)
+        fprintf(nhfp->fpdebug, "(%s)\n", (*d_boolean) ? "true" : "false");
+#endif
+}
+
+void
+sfi_char(nhfp, d_char, myparent, myname, cnt)
+NHFILE *nhfp;
+char *d_char;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "char";
+
+    sfi_log(nhfp, myparent, myname, parent, cnt);
+    (*sfiprocs[nhfp->fnidx].fn.sf_char)(nhfp, d_char, myparent, myname, cnt);
+#ifdef DO_DEBUG
+    if (nhfp->fpdebug)
+        fprintf(nhfp->fpdebug, "(%s)\n", d_char ? d_char : "");
+#endif
+}
+
+void
+sfi_genericptr(nhfp, d_genericptr, myparent, myname, cnt)
+NHFILE *nhfp;
+genericptr_t d_genericptr;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "genericptr";
+
+    sfi_log(nhfp, myparent, myname, parent, cnt);
+    (*sfiprocs[nhfp->fnidx].fn.sf_genericptr)(nhfp, d_genericptr, myparent, myname, cnt);
+#ifdef DO_DEBUG
+    if (nhfp->fpdebug)
+        fprintf(nhfp->fpdebug, "(%s)\n", (d_genericptr) ? "set" : "null");
+#endif
+}
+
+void
+sfi_int(nhfp, d_int, myparent, myname, cnt)
+NHFILE *nhfp;
+int *d_int;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "int";
+
+    sfi_log(nhfp, myparent, myname, parent, cnt);
+    (*sfiprocs[nhfp->fnidx].fn.sf_int)(nhfp, d_int, myparent, myname, cnt);
+#ifdef DO_DEBUG
+    if (nhfp->fpdebug)
+        fprintf(nhfp->fpdebug, "(%d)\n", *d_int);
+#endif
+}
+
+void
+sfi_long(nhfp, d_long, myparent, myname, cnt)
+NHFILE *nhfp;
+long *d_long;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "long";
+
+    sfi_log(nhfp, myparent, myname, parent, cnt);
+    (*sfiprocs[nhfp->fnidx].fn.sf_long)(nhfp, d_long, myparent, myname, cnt);
+#ifdef DO_DEBUG
+    if (nhfp->fpdebug)
+        fprintf(nhfp->fpdebug, "(%ld)\n", *d_long);
+#endif
+}
+
+void
+sfi_schar(nhfp, d_schar, myparent, myname, cnt)
+NHFILE *nhfp;
+schar *d_schar;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "schar";
+
+    sfi_log(nhfp, myparent, myname, parent, cnt);
+    (*sfiprocs[nhfp->fnidx].fn.sf_schar)(nhfp, d_schar, myparent, myname, cnt);
+#ifdef DO_DEBUG
+    if (nhfp->fpdebug)
+        fprintf(nhfp->fpdebug, "(%hd)\n", (short) *d_schar);
+#endif
+}
+
+void
+sfi_short(nhfp, d_short, myparent, myname, cnt)
+NHFILE *nhfp;
+short *d_short;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "short";
+
+    sfi_log(nhfp, myparent, myname, parent, cnt);
+    (*sfiprocs[nhfp->fnidx].fn.sf_short)(nhfp, d_short, myparent, myname, cnt);
+#ifdef DO_DEBUG
+    if (nhfp->fpdebug)
+        fprintf(nhfp->fpdebug, "(%hd)\n", *d_short);
+#endif
+}
+
+void
+sfi_size_t(nhfp, d_size_t, myparent, myname, cnt)
+NHFILE *nhfp;
+size_t *d_size_t;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "size_t";
+
+    sfi_log(nhfp, myparent, myname, parent, cnt);
+    (*sfiprocs[nhfp->fnidx].fn.sf_size_t)(nhfp, d_size_t, myparent, myname, cnt);
+#ifdef DO_DEBUG
+    if (nhfp->fpdebug)
+        fprintf(nhfp->fpdebug, "(%lu)\n", (unsigned long) *d_size_t);
+#endif
+}
+
+void
+sfi_time_t(nhfp, d_time_t, myparent, myname, cnt)
+NHFILE *nhfp;
+time_t *d_time_t;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "time_t";
+
+    sfi_log(nhfp, myparent, myname, parent, cnt);
+    (*sfiprocs[nhfp->fnidx].fn.sf_time_t)(nhfp, d_time_t, myparent, myname, cnt);
+#ifdef DO_DEBUG
+    if (nhfp->fpdebug)
+        fprintf(nhfp->fpdebug, "(%s)\n", yyyymmddhhmmss(*d_time_t));
+#endif
+}
+
+void
+sfi_unsigned(nhfp, d_unsigned, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned *d_unsigned;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "unsigned";
+
+    sfi_log(nhfp, myparent, myname, parent, cnt);
+    (*sfiprocs[nhfp->fnidx].fn.sf_unsigned)(nhfp, d_unsigned, myparent, myname, cnt);
+#ifdef DO_DEBUG
+    if (nhfp->fpdebug)
+        fprintf(nhfp->fpdebug, "(%u)\n", *d_unsigned);
+#endif
+}
+
+void
+sfi_uchar(nhfp, d_uchar, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned char *d_uchar;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "uchar";
+
+    sfi_log(nhfp, myparent, myname, parent, cnt);
+    (*sfiprocs[nhfp->fnidx].fn.sf_uchar)(nhfp, d_uchar, myparent, myname, cnt);
+#ifdef DO_DEBUG
+    if (nhfp->fpdebug)
+        fprintf(nhfp->fpdebug, "(%hu)\n", (unsigned short) *d_uchar);
+#endif
+}
+
+void
+sfi_uint(nhfp, d_uint, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned int *d_uint;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "uint";
+
+    sfi_log(nhfp, myparent, myname, parent, cnt);
+    (*sfiprocs[nhfp->fnidx].fn.sf_uint)(nhfp, d_uint, myparent, myname, cnt);
+#ifdef DO_DEBUG
+    if (nhfp->fpdebug)
+        fprintf(nhfp->fpdebug, "(%u)\n", *d_uint);
+#endif
+}
+
+void
+sfi_ulong(nhfp, d_ulong, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned long *d_ulong;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "ulong";
+
+    sfi_log(nhfp, myparent, myname, parent, cnt);
+    (*sfiprocs[nhfp->fnidx].fn.sf_ulong)(nhfp, d_ulong, myparent, myname, cnt);
+#ifdef DO_DEBUG
+    if (nhfp->fpdebug)
+        fprintf(nhfp->fpdebug, "(%lu)\n", *d_ulong);
+#endif
+}
+
+void
+sfi_ushort(nhfp, d_ushort, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned short *d_ushort;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "ushort";
+
+    sfi_log(nhfp, myparent, myname, parent, cnt);
+    (*sfiprocs[nhfp->fnidx].fn.sf_ushort)(nhfp, d_ushort, myparent, myname, cnt);
+#ifdef DO_DEBUG
+    if (nhfp->fpdebug)
+        fprintf(nhfp->fpdebug, "(%hu)\n", *d_ushort);
+#endif
+}
+
+void
+sfi_xchar(nhfp, d_xchar, myparent, myname, cnt)
+NHFILE *nhfp;
+xchar *d_xchar;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "xchar";
+
+    sfi_log(nhfp, myparent, myname, parent, cnt);
+    (*sfiprocs[nhfp->fnidx].fn.sf_xchar)(nhfp, d_xchar, myparent, myname, cnt);
+#ifdef DO_DEBUG
+    if (nhfp->fpdebug)
+        fprintf(nhfp->fpdebug, "(%hd)\n", (short) *d_xchar);
+#endif
+}
+void
+sfi_str(nhfp, d_str, myparent, myname, cnt)
+NHFILE *nhfp;
+char *d_str;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "str";
+
+    sfi_log(nhfp, myparent, myname, parent, cnt);
+    (*sfiprocs[nhfp->fnidx].fn.sf_str)(nhfp, d_str, myparent, myname, cnt);
+#ifdef DO_DEBUG
+    if (nhfp->fpdebug)
+        fprintf(nhfp->fpdebug, "(\"%s\")\n", d_str);
+#endif
+}
+
+void 
+sfi_addinfo(nhfp, myparent, action, myname, index)
+NHFILE *nhfp;
+const char *myparent, *action, *myname;
+int index;
+{
+    if (nhfp) {
+        if (nhfp->fplog) 
+            (void) fprintf(nhfp->fplog, "# %s %s %s %d\n", myparent, action, myname, index);
+#ifdef DO_DEBUG
+        if (nhfp->fpdebug)
+            (void) fprintf(nhfp->fpdebug, "# %s %s %s %d\n", myparent, action, myname, index);
+#endif
+    }
+    (*sfiprocs[nhfp->fnidx].fn.sf_addinfo)(nhfp, myparent, action, myname, index);
+}
+
+void
+sfi_log(nhfp, t1, t2, t3, cnt)
+NHFILE *nhfp;
+const char *t1, *t2, *t3;
+int cnt;
+{
+#ifdef DO_DEBUG
+#ifdef SAVEFILE_DEBUGGING
+    if (nhfp) {
+        if (nhfp->fplog) 
+            (void) fprintf(nhfp->fplog, "%s %s %s cnt=%d\n", t1, t2, t3, cnt);
+        if (nhfp->fpdebug)
+            (void) fprintf(nhfp->fpdebug, "%s %s %s cnt=%d ", t1, t2, t3, cnt);
+    }
+#endif
+#endif
+}
+
diff --git a/src/sfdata.c b/src/sfdata.c
new file mode 100644 (file)
index 0000000..32b6a74
--- /dev/null
@@ -0,0 +1,5776 @@
+/* NetHack 3.7 sfdata.c        $Date$ $Revision$ */
+/* Copyright (c) NetHack Development Team 2018.                   */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE!          */
+
+#include "hack.h"
+#include "artifact.h"
+#include "func_tab.h"
+#include "lev.h"
+#include "integer.h"
+#include "wintype.h"
+#include "sfproto.h"
+
+#define BUILD_DATE "Sat Jun 22 23:55:47 2019"
+#define BUILD_TIME (1561262147L)
+
+#define NHTYPE_SIMPLE    1
+#define NHTYPE_COMPLEX   2
+struct nhdatatypes_t {
+    unsigned int dtclass;
+    char *dtype;
+    size_t dtsize;
+};
+
+static uint8_t bitfield = 0;
+
+void
+sfo_align(nhfp, d_align, myparent, myname, cnt)
+NHFILE *nhfp;
+struct align *d_align;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "align";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "align", 1);
+
+    sfo_aligntyp(nhfp, &d_align->type, parent, "type", 1);       /* (aligntyp) */
+    sfo_int(nhfp, &d_align->record, parent, "record", 1);        /* (int) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "align", 1);
+}
+
+void
+sfo_attribs(nhfp, d_attribs, myparent, myname, cnt)
+NHFILE *nhfp;
+struct attribs *d_attribs;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "attribs";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "attribs", 1);
+
+    sfo_schar(nhfp, d_attribs->a, parent, "a", A_MAX);           /* (schar) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "attribs", 1);
+}
+
+void
+sfo_bill_x(nhfp, d_bill_x, myparent, myname, cnt)
+NHFILE *nhfp;
+struct bill_x *d_bill_x;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "bill_x";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "bill_x", 1);
+
+    sfo_unsigned(nhfp, &d_bill_x->bo_id, parent, "bo_id", 1);    /* (unsigned) */
+    sfo_boolean(nhfp, &d_bill_x->useup, parent, "useup", 1);     /* (boolean) */
+    sfo_long(nhfp, &d_bill_x->price, parent, "price", 1);        /* (long) */
+    sfo_long(nhfp, &d_bill_x->bquan, parent, "bquan", 1);        /* (long) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "bill_x", 1);
+}
+
+void
+sfo_book_info(nhfp, d_book_info, myparent, myname, cnt)
+NHFILE *nhfp;
+struct book_info *d_book_info;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "book_info";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "book_info", 1);
+
+    sfo_genericptr(nhfp, (genericptr_t) &d_book_info->book, parent, "book", 1);/* (struct obj *) */
+    sfo_unsigned(nhfp, &d_book_info->o_id, parent, "o_id", 1);   /* (unsigned) */
+    sfo_schar(nhfp, &d_book_info->delay, parent, "delay", 1);    /* (schar) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "book_info", 1);
+}
+
+void
+sfo_branch(nhfp, d_branch, myparent, myname, cnt)
+NHFILE *nhfp;
+struct branch *d_branch;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "branch";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "branch", 1);
+
+    sfo_genericptr(nhfp, (genericptr_t) &d_branch->next, parent, "next", 1);/* (struct branch *) */
+    sfo_int(nhfp, &d_branch->id, parent, "id", 1);               /* (int) */
+    sfo_int(nhfp, &d_branch->type, parent, "type", 1);           /* (int) */
+    sfo_d_level(nhfp, &d_branch->end1, parent, "end1", 1);       /* (d_level) */
+    sfo_d_level(nhfp, &d_branch->end2, parent, "end2", 1);       /* (d_level) */
+    sfo_boolean(nhfp, &d_branch->end1_up, parent, "end1_up", 1); /* (boolean) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "branch", 1);
+}
+
+void
+sfo_bubble(nhfp, d_bubble, myparent, myname, cnt)
+NHFILE *nhfp;
+struct bubble *d_bubble;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "bubble";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "bubble", 1);
+
+    sfo_xchar(nhfp, &d_bubble->x, parent, "x", 1);               /* (xchar) */
+    sfo_xchar(nhfp, &d_bubble->y, parent, "y", 1);               /* (xchar) */
+    sfo_schar(nhfp, &d_bubble->dx, parent, "dx", 1);             /* (schar) */
+    sfo_schar(nhfp, &d_bubble->dy, parent, "dy", 1);             /* (schar) */
+    sfo_uchar(nhfp, d_bubble->bm, parent, "bm", MAX_BMASK + 2);  /* (uchar) */
+    sfo_genericptr(nhfp, (genericptr_t) &d_bubble->prev, parent, "prev", 1);/* (struct bubble *) */
+    sfo_genericptr(nhfp, (genericptr_t) &d_bubble->next, parent, "next", 1);/* (struct bubble *) */
+    sfo_genericptr(nhfp, (genericptr_t) &d_bubble->cons, parent, "cons", 1);/* (struct container *) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "bubble", 1);
+}
+
+void
+sfo_cemetery(nhfp, d_cemetery, myparent, myname, cnt)
+NHFILE *nhfp;
+struct cemetery *d_cemetery;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "cemetery";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "cemetery", 1);
+
+    sfo_genericptr(nhfp, (genericptr_t) &d_cemetery->next, parent, "next", 1);/* (struct cemetery *) */
+    sfo_char(nhfp, d_cemetery->who, parent, "who", PL_NSIZ + 4 * (1 + 3) + 1);/* (char) */
+    sfo_char(nhfp, d_cemetery->how, parent, "how", 100 + 1);     /* (char) */
+    sfo_char(nhfp, d_cemetery->when, parent, "when", 4 + 2 + 2 + 2 + 2 + 2 + 1);/* (char) */
+    sfo_schar(nhfp, &d_cemetery->frpx, parent, "frpx", 1);       /* (schar) */
+    sfo_schar(nhfp, &d_cemetery->frpy, parent, "frpy", 1);       /* (schar) */
+    sfo_boolean(nhfp, &d_cemetery->bonesknown, parent, "bonesknown", 1);/* (boolean) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "cemetery", 1);
+}
+
+void
+sfo_context_info(nhfp, d_context_info, myparent, myname, cnt)
+NHFILE *nhfp;
+struct context_info *d_context_info;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "context_info";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "context_info", 1);
+
+    sfo_unsigned(nhfp, &d_context_info->ident, parent, "ident", 1);/* (unsigned) */
+    sfo_unsigned(nhfp, &d_context_info->no_of_wizards, parent, "no_of_wizards", 1);/* (unsigned) */
+    sfo_unsigned(nhfp, &d_context_info->run, parent, "run", 1);  /* (unsigned) */
+    sfo_unsigned(nhfp, &d_context_info->startingpet_mid, parent, "startingpet_mid", 1);/* (unsigned) */
+    sfo_int(nhfp, &d_context_info->current_fruit, parent, "current_fruit", 1);/* (int) */
+    sfo_int(nhfp, &d_context_info->warnlevel, parent, "warnlevel", 1);/* (int) */
+    sfo_int(nhfp, &d_context_info->rndencode, parent, "rndencode", 1);/* (int) */
+    sfo_long(nhfp, &d_context_info->next_attrib_check, parent, "next_attrib_check", 1);/* (long) */
+    sfo_long(nhfp, &d_context_info->stethoscope_move, parent, "stethoscope_move", 1);/* (long) */
+    sfo_short(nhfp, &d_context_info->stethoscope_movement, parent, "stethoscope_movement", 1);/* (short) */
+    sfo_boolean(nhfp, &d_context_info->travel, parent, "travel", 1);/* (boolean) */
+    sfo_boolean(nhfp, &d_context_info->travel1, parent, "travel1", 1);/* (boolean) */
+    sfo_boolean(nhfp, &d_context_info->forcefight, parent, "forcefight", 1);/* (boolean) */
+    sfo_boolean(nhfp, &d_context_info->nopick, parent, "nopick", 1);/* (boolean) */
+    sfo_boolean(nhfp, &d_context_info->made_amulet, parent, "made_amulet", 1);/* (boolean) */
+    sfo_boolean(nhfp, &d_context_info->mon_moving, parent, "mon_moving", 1);/* (boolean) */
+    sfo_boolean(nhfp, &d_context_info->move, parent, "move", 1); /* (boolean) */
+    sfo_boolean(nhfp, &d_context_info->mv, parent, "mv", 1);     /* (boolean) */
+    sfo_boolean(nhfp, &d_context_info->bypasses, parent, "bypasses", 1);/* (boolean) */
+    sfo_boolean(nhfp, &d_context_info->botl, parent, "botl", 1); /* (boolean) */
+    sfo_boolean(nhfp, &d_context_info->botlx, parent, "botlx", 1);/* (boolean) */
+    sfo_boolean(nhfp, &d_context_info->door_opened, parent, "door_opened", 1);/* (boolean) */
+    sfo_dig_info(nhfp, &d_context_info->digging, parent, "digging", 1);/* (dig_info) */
+    sfo_victual_info(nhfp, &d_context_info->victual, parent, "victual", 1);/* (victual_info) */
+    sfo_tin_info(nhfp, &d_context_info->tin, parent, "tin", 1);  /* (tin_info) */
+    sfo_book_info(nhfp, &d_context_info->spbook, parent, "spbook", 1);/* (book_info) */
+    sfo_takeoff_info(nhfp, &d_context_info->takeoff, parent, "takeoff", 1);/* (takeoff_info) */
+    sfo_warntype_info(nhfp, &d_context_info->warntype, parent, "warntype", 1);/* (warntype_info) */
+    sfo_polearm_info(nhfp, &d_context_info->polearm, parent, "polearm", 1);/* (polearm_info) */
+    sfo_obj_split(nhfp, &d_context_info->objsplit, parent, "objsplit", 1);/* (obj_split) */
+    sfo_tribute_info(nhfp, &d_context_info->tribute, parent, "tribute", 1);/* (tribute_info) */
+    sfo_novel_tracking(nhfp, &d_context_info->novel, parent, "novel", 1);/* (novel_tracking) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "context_info", 1);
+}
+
+void
+sfo_d_flags(nhfp, d_d_flags, myparent, myname, cnt)
+NHFILE *nhfp;
+struct d_flags *d_d_flags;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "d_flags";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "d_flags", 1);
+
+    bitfield = d_d_flags->town;                                  /* (Bitfield(town, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "town",  1);
+    bitfield = d_d_flags->hellish;                               /* (Bitfield(hellish, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "hellish",  1);
+    bitfield = d_d_flags->maze_like;                             /* (Bitfield(maze_like, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "maze_like",  1);
+    bitfield = d_d_flags->rogue_like;                            /* (Bitfield(rogue_like, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "rogue_like",  1);
+    bitfield = d_d_flags->align;                                 /* (Bitfield(align, 3)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "align",  3);
+    bitfield = d_d_flags->unused;                                /* (Bitfield(unused, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "unused",  1);
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "d_flags", 1);
+}
+
+void
+sfo_d_level(nhfp, d_d_level, myparent, myname, cnt)
+NHFILE *nhfp;
+struct d_level *d_d_level;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "d_level";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "d_level", 1);
+
+    sfo_xchar(nhfp, &d_d_level->dnum, parent, "dnum", 1);        /* (xchar) */
+    sfo_xchar(nhfp, &d_d_level->dlevel, parent, "dlevel", 1);    /* (xchar) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "d_level", 1);
+}
+
+void
+sfo_damage(nhfp, d_damage, myparent, myname, cnt)
+NHFILE *nhfp;
+struct damage *d_damage;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "damage";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "damage", 1);
+
+    sfo_genericptr(nhfp, (genericptr_t) &d_damage->next, parent, "next", 1);/* (struct damage *) */
+    sfo_long(nhfp, &d_damage->when, parent, "when", 1);          /* (long) */
+    sfo_long(nhfp, &d_damage->cost, parent, "cost", 1);          /* (long) */
+    sfo_nhcoord(nhfp, &d_damage->place, parent, "place", 1);     /* (nhcoord) */
+    sfo_schar(nhfp, &d_damage->typ, parent, "typ", 1);           /* (schar) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "damage", 1);
+}
+
+void
+sfo_dest_area(nhfp, d_dest_area, myparent, myname, cnt)
+NHFILE *nhfp;
+struct dest_area *d_dest_area;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "dest_area";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "dest_area", 1);
+
+    sfo_xchar(nhfp, &d_dest_area->lx, parent, "lx", 1);          /* (xchar) */
+    sfo_xchar(nhfp, &d_dest_area->ly, parent, "ly", 1);          /* (xchar) */
+    sfo_xchar(nhfp, &d_dest_area->hx, parent, "hx", 1);          /* (xchar) */
+    sfo_xchar(nhfp, &d_dest_area->hy, parent, "hy", 1);          /* (xchar) */
+    sfo_xchar(nhfp, &d_dest_area->nlx, parent, "nlx", 1);        /* (xchar) */
+    sfo_xchar(nhfp, &d_dest_area->nly, parent, "nly", 1);        /* (xchar) */
+    sfo_xchar(nhfp, &d_dest_area->nhx, parent, "nhx", 1);        /* (xchar) */
+    sfo_xchar(nhfp, &d_dest_area->nhy, parent, "nhy", 1);        /* (xchar) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "dest_area", 1);
+}
+
+void
+sfo_dgn_topology(nhfp, d_dgn_topology, myparent, myname, cnt)
+NHFILE *nhfp;
+struct dgn_topology *d_dgn_topology;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "dgn_topology";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "dgn_topology", 1);
+
+    sfo_d_level(nhfp, &d_dgn_topology->d_oracle_level, parent, "d_oracle_level", 1);/* (d_level) */
+    sfo_d_level(nhfp, &d_dgn_topology->d_bigroom_level, parent, "d_bigroom_level", 1);/* (d_level) */
+    sfo_d_level(nhfp, &d_dgn_topology->d_rogue_level, parent, "d_rogue_level", 1);/* (d_level) */
+    sfo_d_level(nhfp, &d_dgn_topology->d_medusa_level, parent, "d_medusa_level", 1);/* (d_level) */
+    sfo_d_level(nhfp, &d_dgn_topology->d_stronghold_level, parent, "d_stronghold_level", 1);/* (d_level) */
+    sfo_d_level(nhfp, &d_dgn_topology->d_valley_level, parent, "d_valley_level", 1);/* (d_level) */
+    sfo_d_level(nhfp, &d_dgn_topology->d_wiz1_level, parent, "d_wiz1_level", 1);/* (d_level) */
+    sfo_d_level(nhfp, &d_dgn_topology->d_wiz2_level, parent, "d_wiz2_level", 1);/* (d_level) */
+    sfo_d_level(nhfp, &d_dgn_topology->d_wiz3_level, parent, "d_wiz3_level", 1);/* (d_level) */
+    sfo_d_level(nhfp, &d_dgn_topology->d_juiblex_level, parent, "d_juiblex_level", 1);/* (d_level) */
+    sfo_d_level(nhfp, &d_dgn_topology->d_orcus_level, parent, "d_orcus_level", 1);/* (d_level) */
+    sfo_d_level(nhfp, &d_dgn_topology->d_baalzebub_level, parent, "d_baalzebub_level", 1);/* (d_level) */
+    sfo_d_level(nhfp, &d_dgn_topology->d_asmodeus_level, parent, "d_asmodeus_level", 1);/* (d_level) */
+    sfo_d_level(nhfp, &d_dgn_topology->d_portal_level, parent, "d_portal_level", 1);/* (d_level) */
+    sfo_d_level(nhfp, &d_dgn_topology->d_sanctum_level, parent, "d_sanctum_level", 1);/* (d_level) */
+    sfo_d_level(nhfp, &d_dgn_topology->d_earth_level, parent, "d_earth_level", 1);/* (d_level) */
+    sfo_d_level(nhfp, &d_dgn_topology->d_water_level, parent, "d_water_level", 1);/* (d_level) */
+    sfo_d_level(nhfp, &d_dgn_topology->d_fire_level, parent, "d_fire_level", 1);/* (d_level) */
+    sfo_d_level(nhfp, &d_dgn_topology->d_air_level, parent, "d_air_level", 1);/* (d_level) */
+    sfo_d_level(nhfp, &d_dgn_topology->d_astral_level, parent, "d_astral_level", 1);/* (d_level) */
+    sfo_xchar(nhfp, &d_dgn_topology->d_tower_dnum, parent, "d_tower_dnum", 1);/* (xchar) */
+    sfo_xchar(nhfp, &d_dgn_topology->d_sokoban_dnum, parent, "d_sokoban_dnum", 1);/* (xchar) */
+    sfo_xchar(nhfp, &d_dgn_topology->d_mines_dnum, parent, "d_mines_dnum", 1);/* (xchar) */
+    sfo_xchar(nhfp, &d_dgn_topology->d_quest_dnum, parent, "d_quest_dnum", 1);/* (xchar) */
+    sfo_d_level(nhfp, &d_dgn_topology->d_qstart_level, parent, "d_qstart_level", 1);/* (d_level) */
+    sfo_d_level(nhfp, &d_dgn_topology->d_qlocate_level, parent, "d_qlocate_level", 1);/* (d_level) */
+    sfo_d_level(nhfp, &d_dgn_topology->d_nemesis_level, parent, "d_nemesis_level", 1);/* (d_level) */
+    sfo_d_level(nhfp, &d_dgn_topology->d_knox_level, parent, "d_knox_level", 1);/* (d_level) */
+    sfo_d_level(nhfp, &d_dgn_topology->d_mineend_level, parent, "d_mineend_level", 1);/* (d_level) */
+    sfo_d_level(nhfp, &d_dgn_topology->d_sokoend_level, parent, "d_sokoend_level", 1);/* (d_level) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "dgn_topology", 1);
+}
+
+void
+sfo_dig_info(nhfp, d_dig_info, myparent, myname, cnt)
+NHFILE *nhfp;
+struct dig_info *d_dig_info;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "dig_info";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "dig_info", 1);
+
+    sfo_int(nhfp, &d_dig_info->effort, parent, "effort", 1);     /* (int) */
+    sfo_d_level(nhfp, &d_dig_info->level, parent, "level", 1);   /* (d_level) */
+    sfo_nhcoord(nhfp, &d_dig_info->pos, parent, "pos", 1);       /* (nhcoord) */
+    sfo_long(nhfp, &d_dig_info->lastdigtime, parent, "lastdigtime", 1);/* (long) */
+    sfo_boolean(nhfp, &d_dig_info->down, parent, "down", 1);     /* (boolean) */
+    sfo_boolean(nhfp, &d_dig_info->chew, parent, "chew", 1);     /* (boolean) */
+    sfo_boolean(nhfp, &d_dig_info->warned, parent, "warned", 1); /* (boolean) */
+    sfo_boolean(nhfp, &d_dig_info->quiet, parent, "quiet", 1);   /* (boolean) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "dig_info", 1);
+}
+
+void
+sfo_dungeon(nhfp, d_dungeon, myparent, myname, cnt)
+NHFILE *nhfp;
+struct dungeon *d_dungeon;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "dungeon";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "dungeon", 1);
+
+    sfo_char(nhfp, d_dungeon->dname, parent, "dname", 24);       /* (char) */
+    sfo_char(nhfp, d_dungeon->proto, parent, "proto", 15);       /* (char) */
+    sfo_char(nhfp, &d_dungeon->boneid, parent, "boneid", 1);     /* (char) */
+    sfo_d_flags(nhfp, &d_dungeon->flags, parent, "flags", 1);    /* (d_flags) */
+    sfo_xchar(nhfp, &d_dungeon->entry_lev, parent, "entry_lev", 1);/* (xchar) */
+    sfo_xchar(nhfp, &d_dungeon->num_dunlevs, parent, "num_dunlevs", 1);/* (xchar) */
+    sfo_xchar(nhfp, &d_dungeon->dunlev_ureached, parent, "dunlev_ureached", 1);/* (xchar) */
+    sfo_int(nhfp, &d_dungeon->ledger_start, parent, "ledger_start", 1);/* (int) */
+    sfo_int(nhfp, &d_dungeon->depth_start, parent, "depth_start", 1);/* (int) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "dungeon", 1);
+}
+
+void
+sfo_edog(nhfp, d_edog, myparent, myname, cnt)
+NHFILE *nhfp;
+struct edog *d_edog;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "edog";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "edog", 1);
+
+    sfo_long(nhfp, &d_edog->droptime, parent, "droptime", 1);    /* (long) */
+    sfo_unsigned(nhfp, &d_edog->dropdist, parent, "dropdist", 1);/* (unsigned) */
+    sfo_int(nhfp, &d_edog->apport, parent, "apport", 1);         /* (int) */
+    sfo_long(nhfp, &d_edog->whistletime, parent, "whistletime", 1);/* (long) */
+    sfo_long(nhfp, &d_edog->hungrytime, parent, "hungrytime", 1);/* (long) */
+    sfo_nhcoord(nhfp, &d_edog->ogoal, parent, "ogoal", 1);       /* (nhcoord) */
+    sfo_int(nhfp, &d_edog->abuse, parent, "abuse", 1);           /* (int) */
+    sfo_int(nhfp, &d_edog->revivals, parent, "revivals", 1);     /* (int) */
+    sfo_int(nhfp, &d_edog->mhpmax_penalty, parent, "mhpmax_penalty", 1);/* (int) */
+    bitfield = d_edog->killed_by_u;                              /* (Bitfield(killed_by_u, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "killed_by_u",  1);
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "edog", 1);
+}
+
+void
+sfo_egd(nhfp, d_egd, myparent, myname, cnt)
+NHFILE *nhfp;
+struct egd *d_egd;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "egd";
+    int i;
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "egd", 1);
+
+    sfo_int(nhfp, &d_egd->fcbeg, parent, "fcbeg", 1);            /* (int) */
+    sfo_int(nhfp, &d_egd->fcend, parent, "fcend", 1);            /* (int) */
+    sfo_int(nhfp, &d_egd->vroom, parent, "vroom", 1);            /* (int) */
+    sfo_xchar(nhfp, &d_egd->gdx, parent, "gdx", 1);              /* (xchar) */
+    sfo_xchar(nhfp, &d_egd->gdy, parent, "gdy", 1);              /* (xchar) */
+    sfo_xchar(nhfp, &d_egd->ogx, parent, "ogx", 1);              /* (xchar) */
+    sfo_xchar(nhfp, &d_egd->ogy, parent, "ogy", 1);              /* (xchar) */
+    sfo_d_level(nhfp, &d_egd->gdlevel, parent, "gdlevel", 1);    /* (d_level) */
+    sfo_xchar(nhfp, &d_egd->warncnt, parent, "warncnt", 1);      /* (xchar) */
+    bitfield = d_egd->gddone;                                    /* (Bitfield(gddone, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "gddone",  1);
+    bitfield = d_egd->witness;                                   /* (Bitfield(witness, 2)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "witness",  2);
+    bitfield = d_egd->unused;                                    /* (Bitfield(unused, 5)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "unused",  5);
+    for (i = 0; i < FCSIZ; ++i)
+        sfo_fakecorridor(nhfp, &d_egd->fakecorr[i], parent, "fakecorr", 1);/* (fakecorridor) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "egd", 1);
+}
+
+void
+sfo_emin(nhfp, d_emin, myparent, myname, cnt)
+NHFILE *nhfp;
+struct emin *d_emin;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "emin";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "emin", 1);
+
+    sfo_aligntyp(nhfp, &d_emin->min_align, parent, "min_align", 1);/* (aligntyp) */
+    sfo_boolean(nhfp, &d_emin->renegade, parent, "renegade", 1); /* (boolean) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "emin", 1);
+}
+
+void
+sfo_engr(nhfp, d_engr, myparent, myname, cnt)
+NHFILE *nhfp;
+struct engr *d_engr;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "engr";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "engr", 1);
+
+    sfo_genericptr(nhfp, (genericptr_t) &d_engr->nxt_engr, parent, "nxt_engr", 1);/* (struct engr *) */
+    sfo_genericptr(nhfp, (genericptr_t) &d_engr->engr_txt, parent, "engr_txt", 1);/* (char *) */
+    sfo_xchar(nhfp, &d_engr->engr_x, parent, "engr_x", 1);       /* (xchar) */
+    sfo_xchar(nhfp, &d_engr->engr_y, parent, "engr_y", 1);       /* (xchar) */
+    sfo_unsigned(nhfp, &d_engr->engr_lth, parent, "engr_lth", 1);/* (unsigned) */
+    sfo_long(nhfp, &d_engr->engr_time, parent, "engr_time", 1);  /* (long) */
+    sfo_xchar(nhfp, &d_engr->engr_type, parent, "engr_type", 1); /* (xchar) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "engr", 1);
+}
+
+void
+sfo_epri(nhfp, d_epri, myparent, myname, cnt)
+NHFILE *nhfp;
+struct epri *d_epri;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "epri";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "epri", 1);
+
+    sfo_aligntyp(nhfp, &d_epri->shralign, parent, "shralign", 1);/* (aligntyp) */
+    sfo_schar(nhfp, &d_epri->shroom, parent, "shroom", 1);       /* (schar) */
+    sfo_nhcoord(nhfp, &d_epri->shrpos, parent, "shrpos", 1);     /* (nhcoord) */
+    sfo_d_level(nhfp, &d_epri->shrlevel, parent, "shrlevel", 1); /* (d_level) */
+    sfo_long(nhfp, &d_epri->intone_time, parent, "intone_time", 1);/* (long) */
+    sfo_long(nhfp, &d_epri->enter_time, parent, "enter_time", 1);/* (long) */
+    sfo_long(nhfp, &d_epri->hostile_time, parent, "hostile_time", 1);/* (long) */
+    sfo_long(nhfp, &d_epri->peaceful_time, parent, "peaceful_time", 1);/* (long) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "epri", 1);
+}
+
+void
+sfo_eshk(nhfp, d_eshk, myparent, myname, cnt)
+NHFILE *nhfp;
+struct eshk *d_eshk;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "eshk";
+    int i;
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "eshk", 1);
+
+    sfo_long(nhfp, &d_eshk->robbed, parent, "robbed", 1);        /* (long) */
+    sfo_long(nhfp, &d_eshk->credit, parent, "credit", 1);        /* (long) */
+    sfo_long(nhfp, &d_eshk->debit, parent, "debit", 1);          /* (long) */
+    sfo_long(nhfp, &d_eshk->loan, parent, "loan", 1);            /* (long) */
+    sfo_int(nhfp, &d_eshk->shoptype, parent, "shoptype", 1);     /* (int) */
+    sfo_schar(nhfp, &d_eshk->shoproom, parent, "shoproom", 1);   /* (schar) */
+    sfo_schar(nhfp, &d_eshk->unused, parent, "unused", 1);       /* (schar) */
+    sfo_boolean(nhfp, &d_eshk->following, parent, "following", 1);/* (boolean) */
+    sfo_boolean(nhfp, &d_eshk->surcharge, parent, "surcharge", 1);/* (boolean) */
+    sfo_boolean(nhfp, &d_eshk->dismiss_kops, parent, "dismiss_kops", 1);/* (boolean) */
+    sfo_nhcoord(nhfp, &d_eshk->shk, parent, "shk", 1);           /* (nhcoord) */
+    sfo_nhcoord(nhfp, &d_eshk->shd, parent, "shd", 1);           /* (nhcoord) */
+    sfo_d_level(nhfp, &d_eshk->shoplevel, parent, "shoplevel", 1);/* (d_level) */
+    sfo_int(nhfp, &d_eshk->billct, parent, "billct", 1);         /* (int) */
+    for (i = 0; i < BILLSZ; ++i)
+        sfo_bill_x(nhfp, &d_eshk->bill[i], parent, "bill", 1);   /* (bill_x) */
+    sfo_genericptr(nhfp, (genericptr_t) &d_eshk->bill_p, parent, "bill_p", 1);/* (struct bill_x *) */
+    sfo_int(nhfp, &d_eshk->visitct, parent, "visitct", 1);       /* (int) */
+    sfo_char(nhfp, d_eshk->customer, parent, "customer", PL_NSIZ);/* (char) */
+    sfo_char(nhfp, d_eshk->shknam, parent, "shknam", PL_NSIZ);   /* (char) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "eshk", 1);
+}
+
+void
+sfo_fakecorridor(nhfp, d_fakecorridor, myparent, myname, cnt)
+NHFILE *nhfp;
+struct fakecorridor *d_fakecorridor;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "fakecorridor";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "fakecorridor", 1);
+
+    sfo_xchar(nhfp, &d_fakecorridor->fx, parent, "fx", 1);       /* (xchar) */
+    sfo_xchar(nhfp, &d_fakecorridor->fy, parent, "fy", 1);       /* (xchar) */
+    sfo_xchar(nhfp, &d_fakecorridor->ftyp, parent, "ftyp", 1);   /* (xchar) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "fakecorridor", 1);
+}
+
+void
+sfo_fe(nhfp, d_fe, myparent, myname, cnt)
+NHFILE *nhfp;
+struct fe *d_fe;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "fe";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "fe", 1);
+
+    sfo_genericptr(nhfp, (genericptr_t) &d_fe->next, parent, "next", 1);/* (struct fe *) */
+    sfo_long(nhfp, &d_fe->timeout, parent, "timeout", 1);        /* (long) */
+    sfo_ulong(nhfp, &d_fe->tid, parent, "tid", 1);               /* (unsigned long) */
+    sfo_short(nhfp, &d_fe->kind, parent, "kind", 1);             /* (short) */
+    sfo_short(nhfp, &d_fe->func_index, parent, "func_index", 1); /* (short) */
+    sfo_any(nhfp, &d_fe->arg, parent, "arg", 1);                 /* (any) */
+    bitfield = d_fe->needs_fixup;                                /* (Bitfield(needs_fixup, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "needs_fixup",  1);
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "fe", 1);
+}
+
+void
+sfo_flag(nhfp, d_flag, myparent, myname, cnt)
+NHFILE *nhfp;
+struct flag *d_flag;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "flag";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "flag", 1);
+
+    sfo_boolean(nhfp, &d_flag->acoustics, parent, "acoustics", 1);/* (boolean) */
+    sfo_boolean(nhfp, &d_flag->autodig, parent, "autodig", 1);   /* (boolean) */
+    sfo_boolean(nhfp, &d_flag->autoquiver, parent, "autoquiver", 1);/* (boolean) */
+    sfo_boolean(nhfp, &d_flag->autoopen, parent, "autoopen", 1); /* (boolean) */
+    sfo_boolean(nhfp, &d_flag->beginner, parent, "beginner", 1); /* (boolean) */
+    sfo_boolean(nhfp, &d_flag->biff, parent, "biff", 1);         /* (boolean) */
+    sfo_boolean(nhfp, &d_flag->bones, parent, "bones", 1);       /* (boolean) */
+    sfo_boolean(nhfp, &d_flag->confirm, parent, "confirm", 1);   /* (boolean) */
+    sfo_boolean(nhfp, &d_flag->dark_room, parent, "dark_room", 1);/* (boolean) */
+    sfo_boolean(nhfp, &d_flag->debug, parent, "debug", 1);       /* (boolean) */
+    sfo_boolean(nhfp, &d_flag->end_own, parent, "end_own", 1);   /* (boolean) */
+    sfo_boolean(nhfp, &d_flag->explore, parent, "explore", 1);   /* (boolean) */
+    sfo_boolean(nhfp, &d_flag->female, parent, "female", 1);     /* (boolean) */
+    sfo_boolean(nhfp, &d_flag->friday13, parent, "friday13", 1); /* (boolean) */
+    sfo_boolean(nhfp, &d_flag->help, parent, "help", 1);         /* (boolean) */
+    sfo_boolean(nhfp, &d_flag->ignintr, parent, "ignintr", 1);   /* (boolean) */
+    sfo_boolean(nhfp, &d_flag->ins_chkpt, parent, "ins_chkpt", 1);/* (boolean) */
+    sfo_boolean(nhfp, &d_flag->invlet_constant, parent, "invlet_constant", 1);/* (boolean) */
+    sfo_boolean(nhfp, &d_flag->legacy, parent, "legacy", 1);     /* (boolean) */
+    sfo_boolean(nhfp, &d_flag->lit_corridor, parent, "lit_corridor", 1);/* (boolean) */
+    sfo_boolean(nhfp, &d_flag->nap, parent, "nap", 1);           /* (boolean) */
+    sfo_boolean(nhfp, &d_flag->null, parent, "null", 1);         /* (boolean) */
+    sfo_boolean(nhfp, &d_flag->p__obsolete, parent, "p__obsolete", 1);/* (boolean) */
+    sfo_boolean(nhfp, &d_flag->pickup, parent, "pickup", 1);     /* (boolean) */
+    sfo_boolean(nhfp, &d_flag->pickup_thrown, parent, "pickup_thrown", 1);/* (boolean) */
+    sfo_boolean(nhfp, &d_flag->pushweapon, parent, "pushweapon", 1);/* (boolean) */
+    sfo_boolean(nhfp, &d_flag->rest_on_space, parent, "rest_on_space", 1);/* (boolean) */
+    sfo_boolean(nhfp, &d_flag->safe_dog, parent, "safe_dog", 1); /* (boolean) */
+    sfo_boolean(nhfp, &d_flag->showexp, parent, "showexp", 1);   /* (boolean) */
+    sfo_boolean(nhfp, &d_flag->showscore, parent, "showscore", 1);/* (boolean) */
+    sfo_boolean(nhfp, &d_flag->silent, parent, "silent", 1);     /* (boolean) */
+    sfo_xchar(nhfp, &d_flag->sortloot, parent, "sortloot", 1);   /* (xchar) */
+    sfo_char(nhfp, &d_flag->sortloot, parent, "sortloot", 1);    /* (char) */
+    sfo_boolean(nhfp, &d_flag->sortpack, parent, "sortpack", 1); /* (boolean) */
+    sfo_boolean(nhfp, &d_flag->sparkle, parent, "sparkle", 1);   /* (boolean) */
+    sfo_boolean(nhfp, &d_flag->standout, parent, "standout", 1); /* (boolean) */
+    sfo_boolean(nhfp, &d_flag->time, parent, "time", 1);         /* (boolean) */
+    sfo_boolean(nhfp, &d_flag->tombstone, parent, "tombstone", 1);/* (boolean) */
+    sfo_boolean(nhfp, &d_flag->verbose, parent, "verbose", 1);   /* (boolean) */
+    sfo_int(nhfp, &d_flag->end_top, parent, "end_top", 1);       /* (int) */
+    sfo_int(nhfp, &d_flag->end_around, parent, "end_around", 1); /* (int) */
+    sfo_unsigned(nhfp, &d_flag->moonphase, parent, "moonphase", 1);/* (unsigned) */
+    sfo_ulong(nhfp, &d_flag->suppress_alert, parent, "suppress_alert", 1);/* (unsigned long) */
+    sfo_unsigned(nhfp, &d_flag->paranoia_bits, parent, "paranoia_bits", 1);/* (unsigned) */
+    sfo_int(nhfp, &d_flag->pickup_burden, parent, "pickup_burden", 1);/* (int) */
+    sfo_int(nhfp, &d_flag->pile_limit, parent, "pile_limit", 1); /* (int) */
+    sfo_char(nhfp, d_flag->inv_order, parent, "inv_order", MAXOCLASSES);/* (char) */
+    sfo_char(nhfp, d_flag->pickup_types, parent, "pickup_types", MAXOCLASSES);/* (char) */
+    sfo_char(nhfp, d_flag->end_disclose, parent, "end_disclose", NUM_DISCLOSURE_OPTIONS + 1);/* (char) */
+    sfo_char(nhfp, &d_flag->menu_style, parent, "menu_style", 1);/* (char) */
+    sfo_boolean(nhfp, &d_flag->made_fruit, parent, "made_fruit", 1);/* (boolean) */
+    sfo_int(nhfp, &d_flag->initrole, parent, "initrole", 1);     /* (int) */
+    sfo_int(nhfp, &d_flag->initrace, parent, "initrace", 1);     /* (int) */
+    sfo_int(nhfp, &d_flag->initgend, parent, "initgend", 1);     /* (int) */
+    sfo_int(nhfp, &d_flag->initalign, parent, "initalign", 1);   /* (int) */
+    sfo_int(nhfp, &d_flag->randomall, parent, "randomall", 1);   /* (int) */
+    sfo_int(nhfp, &d_flag->pantheon, parent, "pantheon", 1);     /* (int) */
+    sfo_boolean(nhfp, &d_flag->lootabc, parent, "lootabc", 1);   /* (boolean) */
+    sfo_boolean(nhfp, &d_flag->showrace, parent, "showrace", 1); /* (boolean) */
+    sfo_boolean(nhfp, &d_flag->travelcmd, parent, "travelcmd", 1);/* (boolean) */
+    sfo_int(nhfp, &d_flag->runmode, parent, "runmode", 1);       /* (int) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "flag", 1);
+}
+
+void
+sfo_fruit(nhfp, d_fruit, myparent, myname, cnt)
+NHFILE *nhfp;
+struct fruit *d_fruit;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "fruit";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "fruit", 1);
+
+    sfo_char(nhfp, d_fruit->fname, parent, "fname", PL_FSIZ);    /* (char) */
+    sfo_int(nhfp, &d_fruit->fid, parent, "fid", 1);              /* (int) */
+    sfo_genericptr(nhfp, (genericptr_t) &d_fruit->nextf, parent, "nextf", 1);/* (struct fruit *) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "fruit", 1);
+}
+
+void
+sfo_kinfo(nhfp, d_kinfo, myparent, myname, cnt)
+NHFILE *nhfp;
+struct kinfo *d_kinfo;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "kinfo";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "kinfo", 1);
+
+    sfo_genericptr(nhfp, (genericptr_t) &d_kinfo->next, parent, "next", 1);/* (struct kinfo *) */
+    sfo_int(nhfp, &d_kinfo->id, parent, "id", 1);                /* (int) */
+    sfo_int(nhfp, &d_kinfo->format, parent, "format", 1);        /* (int) */
+    sfo_char(nhfp, d_kinfo->name, parent, "name", BUFSZ);        /* (char) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "kinfo", 1);
+}
+
+void
+sfo_levelflags(nhfp, d_levelflags, myparent, myname, cnt)
+NHFILE *nhfp;
+struct levelflags *d_levelflags;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "levelflags";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "levelflags", 1);
+
+    sfo_uchar(nhfp, &d_levelflags->nfountains, parent, "nfountains", 1);/* (uchar) */
+    sfo_uchar(nhfp, &d_levelflags->nsinks, parent, "nsinks", 1); /* (uchar) */
+    bitfield = d_levelflags->has_shop;                           /* (Bitfield(has_shop, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "has_shop",  1);
+    bitfield = d_levelflags->has_vault;                          /* (Bitfield(has_vault, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "has_vault",  1);
+    bitfield = d_levelflags->has_zoo;                            /* (Bitfield(has_zoo, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "has_zoo",  1);
+    bitfield = d_levelflags->has_court;                          /* (Bitfield(has_court, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "has_court",  1);
+    bitfield = d_levelflags->has_morgue;                         /* (Bitfield(has_morgue, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "has_morgue",  1);
+    bitfield = d_levelflags->has_beehive;                        /* (Bitfield(has_beehive, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "has_beehive",  1);
+    bitfield = d_levelflags->has_barracks;                       /* (Bitfield(has_barracks, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "has_barracks",  1);
+    bitfield = d_levelflags->has_temple;                         /* (Bitfield(has_temple, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "has_temple",  1);
+    bitfield = d_levelflags->has_swamp;                          /* (Bitfield(has_swamp, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "has_swamp",  1);
+    bitfield = d_levelflags->noteleport;                         /* (Bitfield(noteleport, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "noteleport",  1);
+    bitfield = d_levelflags->hardfloor;                          /* (Bitfield(hardfloor, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "hardfloor",  1);
+    bitfield = d_levelflags->nommap;                             /* (Bitfield(nommap, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "nommap",  1);
+    bitfield = d_levelflags->hero_memory;                        /* (Bitfield(hero_memory, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "hero_memory",  1);
+    bitfield = d_levelflags->shortsighted;                       /* (Bitfield(shortsighted, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "shortsighted",  1);
+    bitfield = d_levelflags->graveyard;                          /* (Bitfield(graveyard, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "graveyard",  1);
+    bitfield = d_levelflags->sokoban_rules;                      /* (Bitfield(sokoban_rules, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "sokoban_rules",  1);
+    bitfield = d_levelflags->is_maze_lev;                        /* (Bitfield(is_maze_lev, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "is_maze_lev",  1);
+    bitfield = d_levelflags->is_cavernous_lev;                   /* (Bitfield(is_cavernous_lev, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "is_cavernous_lev",  1);
+    bitfield = d_levelflags->arboreal;                           /* (Bitfield(arboreal, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "arboreal",  1);
+    bitfield = d_levelflags->wizard_bones;                       /* (Bitfield(wizard_bones, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "wizard_bones",  1);
+    bitfield = d_levelflags->corrmaze;                           /* (Bitfield(corrmaze, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "corrmaze",  1);
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "levelflags", 1);
+}
+
+void
+sfo_linfo(nhfp, d_linfo, myparent, myname, cnt)
+NHFILE *nhfp;
+struct linfo *d_linfo;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "linfo";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "linfo", 1);
+
+    sfo_uchar(nhfp, &d_linfo->flags, parent, "flags", 1);        /* (unsigned char) */
+#ifdef MFLOPPY
+    sfo_int(nhfp, &d_linfo->where, parent, "where", 1);          /* (int) */
+    sfo_long(nhfp, &d_linfo->time, parent, "time", 1);           /* (long) */
+    sfo_long(nhfp, &d_linfo->size, parent, "size", 1);           /* (long) */
+#endif /*MFLOPPY*/
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "linfo", 1);
+}
+
+void
+sfo_ls_t(nhfp, d_ls_t, myparent, myname, cnt)
+NHFILE *nhfp;
+struct ls_t *d_ls_t;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "ls_t";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "ls_t", 1);
+
+    sfo_genericptr(nhfp, (genericptr_t) &d_ls_t->next, parent, "next", 1);/* (struct ls_t *) */
+    sfo_xchar(nhfp, &d_ls_t->x, parent, "x", 1);                 /* (xchar) */
+    sfo_xchar(nhfp, &d_ls_t->y, parent, "y", 1);                 /* (xchar) */
+    sfo_short(nhfp, &d_ls_t->range, parent, "range", 1);         /* (short) */
+    sfo_short(nhfp, &d_ls_t->flags, parent, "flags", 1);         /* (short) */
+    sfo_short(nhfp, &d_ls_t->type, parent, "type", 1);           /* (short) */
+    sfo_any(nhfp, &d_ls_t->id, parent, "id", 1);                 /* (any) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "ls_t", 1);
+}
+
+void
+sfo_mapseen_feat(nhfp, d_mapseen_feat, myparent, myname, cnt)
+NHFILE *nhfp;
+struct mapseen_feat *d_mapseen_feat;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "mapseen_feat";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "mapseen_feat", 1);
+
+    bitfield = d_mapseen_feat->nfount;                           /* (Bitfield(nfount, 2)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "nfount",  2);
+    bitfield = d_mapseen_feat->nsink;                            /* (Bitfield(nsink, 2)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "nsink",  2);
+    bitfield = d_mapseen_feat->naltar;                           /* (Bitfield(naltar, 2)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "naltar",  2);
+    bitfield = d_mapseen_feat->nthrone;                          /* (Bitfield(nthrone, 2)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "nthrone",  2);
+    bitfield = d_mapseen_feat->ngrave;                           /* (Bitfield(ngrave, 2)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "ngrave",  2);
+    bitfield = d_mapseen_feat->ntree;                            /* (Bitfield(ntree, 2)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "ntree",  2);
+    bitfield = d_mapseen_feat->water;                            /* (Bitfield(water, 2)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "water",  2);
+    bitfield = d_mapseen_feat->lava;                             /* (Bitfield(lava, 2)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "lava",  2);
+    bitfield = d_mapseen_feat->ice;                              /* (Bitfield(ice, 2)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "ice",  2);
+    bitfield = d_mapseen_feat->nshop;                            /* (Bitfield(nshop, 2)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "nshop",  2);
+    bitfield = d_mapseen_feat->ntemple;                          /* (Bitfield(ntemple, 2)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "ntemple",  2);
+    bitfield = d_mapseen_feat->msalign;                          /* (Bitfield(msalign, 2)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "msalign",  2);
+    bitfield = d_mapseen_feat->shoptype;                         /* (Bitfield(shoptype, 5)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "shoptype",  5);
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "mapseen_feat", 1);
+}
+
+void
+sfo_mapseen_flags(nhfp, d_mapseen_flags, myparent, myname, cnt)
+NHFILE *nhfp;
+struct mapseen_flags *d_mapseen_flags;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "mapseen_flags";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "mapseen_flags", 1);
+
+    bitfield = d_mapseen_flags->unreachable;                     /* (Bitfield(unreachable, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "unreachable",  1);
+    bitfield = d_mapseen_flags->forgot;                          /* (Bitfield(forgot, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "forgot",  1);
+    bitfield = d_mapseen_flags->knownbones;                      /* (Bitfield(knownbones, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "knownbones",  1);
+    bitfield = d_mapseen_flags->oracle;                          /* (Bitfield(oracle, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "oracle",  1);
+    bitfield = d_mapseen_flags->sokosolved;                      /* (Bitfield(sokosolved, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "sokosolved",  1);
+    bitfield = d_mapseen_flags->bigroom;                         /* (Bitfield(bigroom, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "bigroom",  1);
+    bitfield = d_mapseen_flags->castle;                          /* (Bitfield(castle, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "castle",  1);
+    bitfield = d_mapseen_flags->castletune;                      /* (Bitfield(castletune, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "castletune",  1);
+    bitfield = d_mapseen_flags->valley;                          /* (Bitfield(valley, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "valley",  1);
+    bitfield = d_mapseen_flags->msanctum;                        /* (Bitfield(msanctum, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "msanctum",  1);
+    bitfield = d_mapseen_flags->ludios;                          /* (Bitfield(ludios, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "ludios",  1);
+    bitfield = d_mapseen_flags->roguelevel;                      /* (Bitfield(roguelevel, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "roguelevel",  1);
+    bitfield = d_mapseen_flags->quest_summons;                   /* (Bitfield(quest_summons, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "quest_summons",  1);
+    bitfield = d_mapseen_flags->questing;                        /* (Bitfield(questing, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "questing",  1);
+    bitfield = d_mapseen_flags->vibrating_square;                /* (Bitfield(vibrating_square, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "vibrating_square",  1);
+    bitfield = d_mapseen_flags->spare1;                          /* (Bitfield(spare1, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "spare1",  1);
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "mapseen_flags", 1);
+}
+
+void
+sfo_mapseen_rooms(nhfp, d_mapseen_rooms, myparent, myname, cnt)
+NHFILE *nhfp;
+struct mapseen_rooms *d_mapseen_rooms;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "mapseen_rooms";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "mapseen_rooms", 1);
+
+    bitfield = d_mapseen_rooms->seen;                            /* (Bitfield(seen, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "seen",  1);
+    bitfield = d_mapseen_rooms->untended;                        /* (Bitfield(untended, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "untended",  1);
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "mapseen_rooms", 1);
+}
+
+void
+sfo_mapseen(nhfp, d_mapseen, myparent, myname, cnt)
+NHFILE *nhfp;
+struct mapseen *d_mapseen;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "mapseen";
+    int i;
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "mapseen", 1);
+
+    sfo_genericptr(nhfp, (genericptr_t) &d_mapseen->next, parent, "next", 1);/* (struct mapseen *) */
+    sfo_branch(nhfp, d_mapseen->br, parent, "br", 1);            /* (branch *) */
+    sfo_d_level(nhfp, &d_mapseen->lev, parent, "lev", 1);        /* (d_level) */
+    sfo_mapseen_feat(nhfp, &d_mapseen->feat, parent, "feat", 1); /* (}) */
+    sfo_mapseen_flags(nhfp, &d_mapseen->flags, parent, "flags", 1);/* (}) */
+    sfo_char(nhfp, d_mapseen->custom, parent, "custom", 1);      /* (char *) */
+    sfo_unsigned(nhfp, &d_mapseen->custom_lth, parent, "custom_lth", 1);/* (unsigned) */
+    for (i = 0; i < (MAXNROFROOMS + 1) * 2; ++i)
+        sfo_mapseen_rooms(nhfp, &d_mapseen->msrooms[i], parent, "msrooms", 1);/* (}) */
+    sfo_genericptr(nhfp, (genericptr_t) &d_mapseen->final_resting_place, parent, "final_resting_place", 1);/* (struct cemetery *) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "mapseen", 1);
+}
+
+void
+sfo_mextra(nhfp, d_mextra, myparent, myname, cnt)
+NHFILE *nhfp;
+struct mextra *d_mextra;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "mextra";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "mextra", 1);
+
+    sfo_char(nhfp, d_mextra->mname, parent, "mname", 1);         /* (char *) */
+    sfo_egd(nhfp, d_mextra->egd, parent, "egd", 1);              /* (struct egd *) */
+    sfo_epri(nhfp, d_mextra->epri, parent, "epri", 1);           /* (struct epri *) */
+    sfo_eshk(nhfp, d_mextra->eshk, parent, "eshk", 1);           /* (struct eshk *) */
+    sfo_emin(nhfp, d_mextra->emin, parent, "emin", 1);           /* (struct emin *) */
+    sfo_edog(nhfp, d_mextra->edog, parent, "edog", 1);           /* (struct edog *) */
+    sfo_int(nhfp, &d_mextra->mcorpsenm, parent, "mcorpsenm", 1); /* (int) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "mextra", 1);
+}
+
+void
+sfo_mkroom(nhfp, d_mkroom, myparent, myname, cnt)
+NHFILE *nhfp;
+struct mkroom *d_mkroom;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "mkroom";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "mkroom", 1);
+
+    sfo_schar(nhfp, &d_mkroom->lx, parent, "lx", 1);             /* (schar) */
+    sfo_schar(nhfp, &d_mkroom->hx, parent, "hx", 1);             /* (schar) */
+    sfo_schar(nhfp, &d_mkroom->ly, parent, "ly", 1);             /* (schar) */
+    sfo_schar(nhfp, &d_mkroom->hy, parent, "hy", 1);             /* (schar) */
+    sfo_schar(nhfp, &d_mkroom->rtype, parent, "rtype", 1);       /* (schar) */
+    sfo_schar(nhfp, &d_mkroom->orig_rtype, parent, "orig_rtype", 1);/* (schar) */
+    sfo_schar(nhfp, &d_mkroom->rlit, parent, "rlit", 1);         /* (schar) */
+    sfo_schar(nhfp, &d_mkroom->needfill, parent, "needfill", 1); /* (schar) */
+    sfo_schar(nhfp, &d_mkroom->needjoining, parent, "needjoining", 1);/* (schar) */
+    sfo_schar(nhfp, &d_mkroom->doorct, parent, "doorct", 1);     /* (schar) */
+    sfo_schar(nhfp, &d_mkroom->fdoor, parent, "fdoor", 1);       /* (schar) */
+    sfo_schar(nhfp, &d_mkroom->nsubrooms, parent, "nsubrooms", 1);/* (schar) */
+    sfo_boolean(nhfp, &d_mkroom->irregular, parent, "irregular", 1);/* (boolean) */
+    sfo_genericptr(nhfp, (genericptr_t) &d_mkroom->sbrooms[0], parent, "sbrooms", MAX_SUBROOMS);/* (struct mkroom *) */
+    sfo_genericptr(nhfp, (genericptr_t) &d_mkroom->resident, parent, "resident", 1);/* (struct monst *) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "mkroom", 1);
+}
+
+void
+sfo_monst(nhfp, d_monst, myparent, myname, cnt)
+NHFILE *nhfp;
+struct monst *d_monst;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "monst";
+    int i;
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "monst", 1);
+
+    sfo_genericptr(nhfp, (genericptr_t) &d_monst->nmon, parent, "nmon", 1);/* (struct monst *) */
+    sfo_genericptr(nhfp, (genericptr_t) &d_monst->data, parent, "data", 1);/* (struct permonst *) */
+    sfo_unsigned(nhfp, &d_monst->m_id, parent, "m_id", 1);       /* (unsigned) */
+    sfo_short(nhfp, &d_monst->mnum, parent, "mnum", 1);          /* (short) */
+    sfo_short(nhfp, &d_monst->cham, parent, "cham", 1);          /* (short) */
+    sfo_short(nhfp, &d_monst->movement, parent, "movement", 1);  /* (short) */
+    sfo_uchar(nhfp, &d_monst->m_lev, parent, "m_lev", 1);        /* (uchar) */
+    sfo_aligntyp(nhfp, &d_monst->malign, parent, "malign", 1);   /* (aligntyp) */
+    sfo_xchar(nhfp, &d_monst->mx, parent, "mx", 1);              /* (xchar) */
+    sfo_xchar(nhfp, &d_monst->my, parent, "my", 1);              /* (xchar) */
+    sfo_xchar(nhfp, &d_monst->mux, parent, "mux", 1);            /* (xchar) */
+    sfo_xchar(nhfp, &d_monst->muy, parent, "muy", 1);            /* (xchar) */
+    for (i = 0; i < MTSZ; ++i)
+        sfo_nhcoord(nhfp, &d_monst->mtrack[i], parent, "mtrack", 1);/* (nhcoord) */
+    sfo_int(nhfp, &d_monst->mhp, parent, "mhp", 1);              /* (int) */
+    sfo_int(nhfp, &d_monst->mhpmax, parent, "mhpmax", 1);        /* (int) */
+    sfo_unsigned(nhfp, &d_monst->mappearance, parent, "mappearance", 1);/* (unsigned) */
+    sfo_uchar(nhfp, &d_monst->m_ap_type, parent, "m_ap_type", 1);/* (uchar) */
+    sfo_schar(nhfp, &d_monst->mtame, parent, "mtame", 1);        /* (schar) */
+    sfo_ushort(nhfp, &d_monst->mextrinsics, parent, "mextrinsics", 1);/* (unsigned short) */
+    sfo_int(nhfp, &d_monst->mspec_used, parent, "mspec_used", 1);/* (int) */
+    bitfield = d_monst->female;                                  /* (Bitfield(female, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "female",  1);
+    bitfield = d_monst->minvis;                                  /* (Bitfield(minvis, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "minvis",  1);
+    bitfield = d_monst->invis_blkd;                              /* (Bitfield(invis_blkd, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "invis_blkd",  1);
+    bitfield = d_monst->perminvis;                               /* (Bitfield(perminvis, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "perminvis",  1);
+    bitfield = d_monst->mcan;                                    /* (Bitfield(mcan, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "mcan",  1);
+    bitfield = d_monst->mburied;                                 /* (Bitfield(mburied, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "mburied",  1);
+    bitfield = d_monst->mundetected;                             /* (Bitfield(mundetected, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "mundetected",  1);
+    bitfield = d_monst->mcansee;                                 /* (Bitfield(mcansee, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "mcansee",  1);
+    bitfield = d_monst->mspeed;                                  /* (Bitfield(mspeed, 2)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "mspeed",  2);
+    bitfield = d_monst->permspeed;                               /* (Bitfield(permspeed, 2)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "permspeed",  2);
+    bitfield = d_monst->mrevived;                                /* (Bitfield(mrevived, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "mrevived",  1);
+    bitfield = d_monst->mcloned;                                 /* (Bitfield(mcloned, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "mcloned",  1);
+    bitfield = d_monst->mavenge;                                 /* (Bitfield(mavenge, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "mavenge",  1);
+    bitfield = d_monst->mflee;                                   /* (Bitfield(mflee, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "mflee",  1);
+    bitfield = d_monst->mfleetim;                                /* (Bitfield(mfleetim, 7)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "mfleetim",  7);
+    bitfield = d_monst->msleeping;                               /* (Bitfield(msleeping, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "msleeping",  1);
+    bitfield = d_monst->mblinded;                                /* (Bitfield(mblinded, 7)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "mblinded",  7);
+    bitfield = d_monst->mstun;                                   /* (Bitfield(mstun, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "mstun",  1);
+    bitfield = d_monst->mfrozen;                                 /* (Bitfield(mfrozen, 7)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "mfrozen",  7);
+    bitfield = d_monst->mcanmove;                                /* (Bitfield(mcanmove, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "mcanmove",  1);
+    bitfield = d_monst->mconf;                                   /* (Bitfield(mconf, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "mconf",  1);
+    bitfield = d_monst->mpeaceful;                               /* (Bitfield(mpeaceful, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "mpeaceful",  1);
+    bitfield = d_monst->mtrapped;                                /* (Bitfield(mtrapped, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "mtrapped",  1);
+    bitfield = d_monst->mleashed;                                /* (Bitfield(mleashed, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "mleashed",  1);
+    bitfield = d_monst->isshk;                                   /* (Bitfield(isshk, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "isshk",  1);
+    bitfield = d_monst->isminion;                                /* (Bitfield(isminion, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "isminion",  1);
+    bitfield = d_monst->isgd;                                    /* (Bitfield(isgd, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "isgd",  1);
+    bitfield = d_monst->ispriest;                                /* (Bitfield(ispriest, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "ispriest",  1);
+    bitfield = d_monst->iswiz;                                   /* (Bitfield(iswiz, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "iswiz",  1);
+    bitfield = d_monst->wormno;                                  /* (Bitfield(wormno, 5)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "wormno",  5);
+    bitfield = d_monst->mtemplit;                                /* (Bitfield(mtemplit, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "mtemplit",  1);
+    sfo_ulong(nhfp, &d_monst->mstrategy, parent, "mstrategy", 1);/* (unsigned long) */
+    sfo_long(nhfp, &d_monst->mtrapseen, parent, "mtrapseen", 1); /* (long) */
+    sfo_long(nhfp, &d_monst->mlstmv, parent, "mlstmv", 1);       /* (long) */
+    sfo_long(nhfp, &d_monst->mspare1, parent, "mspare1", 1);     /* (long) */
+    sfo_genericptr(nhfp, (genericptr_t) &d_monst->minvent, parent, "minvent", 1);/* (struct obj *) */
+    sfo_genericptr(nhfp, (genericptr_t) &d_monst->mw, parent, "mw", 1);/* (struct obj *) */
+    sfo_long(nhfp, &d_monst->misc_worn_check, parent, "misc_worn_check", 1);/* (long) */
+    sfo_xchar(nhfp, &d_monst->weapon_check, parent, "weapon_check", 1);/* (xchar) */
+    sfo_int(nhfp, &d_monst->meating, parent, "meating", 1);      /* (int) */
+    sfo_genericptr(nhfp, (genericptr_t) &d_monst->mextra, parent, "mextra", 1);/* (struct mextra *) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "monst", 1);
+}
+
+void
+sfo_mvitals(nhfp, d_mvitals, myparent, myname, cnt)
+NHFILE *nhfp;
+struct mvitals *d_mvitals;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "mvitals";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "mvitals", 1);
+
+    sfo_uchar(nhfp, &d_mvitals->born, parent, "born", 1);        /* (uchar) */
+    sfo_uchar(nhfp, &d_mvitals->died, parent, "died", 1);        /* (uchar) */
+    sfo_uchar(nhfp, &d_mvitals->mvflags, parent, "mvflags", 1);  /* (uchar) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "mvitals", 1);
+}
+
+void
+sfo_nhcoord(nhfp, d_nhcoord, myparent, myname, cnt)
+NHFILE *nhfp;
+struct nhcoord *d_nhcoord;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "nhcoord";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "nhcoord", 1);
+
+    sfo_xchar(nhfp, &d_nhcoord->x, parent, "x", 1);              /* (xchar) */
+    sfo_xchar(nhfp, &d_nhcoord->y, parent, "y", 1);              /* (xchar) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "nhcoord", 1);
+}
+
+void
+sfo_nhrect(nhfp, d_nhrect, myparent, myname, cnt)
+NHFILE *nhfp;
+struct nhrect *d_nhrect;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "nhrect";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "nhrect", 1);
+
+    sfo_xchar(nhfp, &d_nhrect->lx, parent, "lx", 1);             /* (xchar) */
+    sfo_xchar(nhfp, &d_nhrect->ly, parent, "ly", 1);             /* (xchar) */
+    sfo_xchar(nhfp, &d_nhrect->hx, parent, "hx", 1);             /* (xchar) */
+    sfo_xchar(nhfp, &d_nhrect->hy, parent, "hy", 1);             /* (xchar) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "nhrect", 1);
+}
+
+void
+sfo_novel_tracking(nhfp, d_novel_tracking, myparent, myname, cnt)
+NHFILE *nhfp;
+struct novel_tracking *d_novel_tracking;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "novel_tracking";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "novel_tracking", 1);
+
+    sfo_unsigned(nhfp, &d_novel_tracking->id, parent, "id", 1);  /* (unsigned) */
+    sfo_int(nhfp, &d_novel_tracking->count, parent, "count", 1); /* (int) */
+    sfo_xchar(nhfp, d_novel_tracking->pasg, parent, "pasg", 30); /* (xchar) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "novel_tracking", 1);
+}
+
+void
+sfo_obj(nhfp, d_obj, myparent, myname, cnt)
+NHFILE *nhfp;
+struct obj *d_obj;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "obj";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "obj", 1);
+
+    sfo_genericptr(nhfp, (genericptr_t) &d_obj->nobj, parent, "nobj", 1);/* (struct obj *) */
+    sfo_vptrs(nhfp, &d_obj->v, parent, "v", 1);                  /* (vptrs) */
+    sfo_genericptr(nhfp, (genericptr_t) &d_obj->cobj, parent, "cobj", 1);/* (struct obj *) */
+    sfo_unsigned(nhfp, &d_obj->o_id, parent, "o_id", 1);         /* (unsigned) */
+    sfo_xchar(nhfp, &d_obj->ox, parent, "ox", 1);                /* (xchar) */
+    sfo_xchar(nhfp, &d_obj->oy, parent, "oy", 1);                /* (xchar) */
+    sfo_short(nhfp, &d_obj->otyp, parent, "otyp", 1);            /* (short) */
+    sfo_unsigned(nhfp, &d_obj->owt, parent, "owt", 1);           /* (unsigned) */
+    sfo_long(nhfp, &d_obj->quan, parent, "quan", 1);             /* (long) */
+    sfo_schar(nhfp, &d_obj->spe, parent, "spe", 1);              /* (schar) */
+    sfo_char(nhfp, &d_obj->oclass, parent, "oclass", 1);         /* (char) */
+    sfo_char(nhfp, &d_obj->invlet, parent, "invlet", 1);         /* (char) */
+    sfo_char(nhfp, &d_obj->oartifact, parent, "oartifact", 1);   /* (char) */
+    sfo_xchar(nhfp, &d_obj->where, parent, "where", 1);          /* (xchar) */
+    sfo_xchar(nhfp, &d_obj->timed, parent, "timed", 1);          /* (xchar) */
+    bitfield = d_obj->cursed;                                    /* (Bitfield(cursed, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "cursed",  1);
+    bitfield = d_obj->blessed;                                   /* (Bitfield(blessed, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "blessed",  1);
+    bitfield = d_obj->unpaid;                                    /* (Bitfield(unpaid, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "unpaid",  1);
+    bitfield = d_obj->no_charge;                                 /* (Bitfield(no_charge, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "no_charge",  1);
+    bitfield = d_obj->known;                                     /* (Bitfield(known, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "known",  1);
+    bitfield = d_obj->dknown;                                    /* (Bitfield(dknown, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "dknown",  1);
+    bitfield = d_obj->bknown;                                    /* (Bitfield(bknown, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "bknown",  1);
+    bitfield = d_obj->rknown;                                    /* (Bitfield(rknown, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "rknown",  1);
+    bitfield = d_obj->oeroded;                                   /* (Bitfield(oeroded, 2)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "oeroded",  2);
+    bitfield = d_obj->oeroded2;                                  /* (Bitfield(oeroded2, 2)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "oeroded2",  2);
+    bitfield = d_obj->oerodeproof;                               /* (Bitfield(oerodeproof, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "oerodeproof",  1);
+    bitfield = d_obj->olocked;                                   /* (Bitfield(olocked, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "olocked",  1);
+    bitfield = d_obj->obroken;                                   /* (Bitfield(obroken, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "obroken",  1);
+    bitfield = d_obj->otrapped;                                  /* (Bitfield(otrapped, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "otrapped",  1);
+    bitfield = d_obj->recharged;                                 /* (Bitfield(recharged, 3)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "recharged",  3);
+    bitfield = d_obj->lamplit;                                   /* (Bitfield(lamplit, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "lamplit",  1);
+    bitfield = d_obj->globby;                                    /* (Bitfield(globby, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "globby",  1);
+    bitfield = d_obj->greased;                                   /* (Bitfield(greased, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "greased",  1);
+    bitfield = d_obj->nomerge;                                   /* (Bitfield(nomerge, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "nomerge",  1);
+    bitfield = d_obj->was_thrown;                                /* (Bitfield(was_thrown, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "was_thrown",  1);
+    bitfield = d_obj->in_use;                                    /* (Bitfield(in_use, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "in_use",  1);
+    bitfield = d_obj->bypass;                                    /* (Bitfield(bypass, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "bypass",  1);
+    bitfield = d_obj->cknown;                                    /* (Bitfield(cknown, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "cknown",  1);
+    bitfield = d_obj->lknown;                                    /* (Bitfield(lknown, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "lknown",  1);
+    sfo_int(nhfp, &d_obj->corpsenm, parent, "corpsenm", 1);      /* (int) */
+    sfo_int(nhfp, &d_obj->usecount, parent, "usecount", 1);      /* (int) */
+    sfo_unsigned(nhfp, &d_obj->oeaten, parent, "oeaten", 1);     /* (unsigned) */
+    sfo_long(nhfp, &d_obj->age, parent, "age", 1);               /* (long) */
+    sfo_long(nhfp, &d_obj->owornmask, parent, "owornmask", 1);   /* (long) */
+    sfo_genericptr(nhfp, (genericptr_t) &d_obj->oextra, parent, "oextra", 1);/* (struct oextra *) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "obj", 1);
+}
+
+void
+sfo_objclass(nhfp, d_objclass, myparent, myname, cnt)
+NHFILE *nhfp;
+struct objclass *d_objclass;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "objclass";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "objclass", 1);
+
+    sfo_short(nhfp, &d_objclass->oc_name_idx, parent, "oc_name_idx", 1);/* (short) */
+    sfo_short(nhfp, &d_objclass->oc_descr_idx, parent, "oc_descr_idx", 1);/* (short) */
+    sfo_genericptr(nhfp, (genericptr_t) &d_objclass->oc_uname, parent, "oc_uname", 1);/* (char *) */
+    bitfield = d_objclass->oc_name_known;                        /* (Bitfield(oc_name_known, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "oc_name_known",  1);
+    bitfield = d_objclass->oc_merge;                             /* (Bitfield(oc_merge, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "oc_merge",  1);
+    bitfield = d_objclass->oc_uses_known;                        /* (Bitfield(oc_uses_known, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "oc_uses_known",  1);
+    bitfield = d_objclass->oc_pre_discovered;                    /* (Bitfield(oc_pre_discovered, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "oc_pre_discovered",  1);
+    bitfield = d_objclass->oc_magic;                             /* (Bitfield(oc_magic, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "oc_magic",  1);
+    bitfield = d_objclass->oc_charged;                           /* (Bitfield(oc_charged, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "oc_charged",  1);
+    bitfield = d_objclass->oc_unique;                            /* (Bitfield(oc_unique, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "oc_unique",  1);
+    bitfield = d_objclass->oc_nowish;                            /* (Bitfield(oc_nowish, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "oc_nowish",  1);
+    bitfield = d_objclass->oc_big;                               /* (Bitfield(oc_big, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "oc_big",  1);
+    bitfield = d_objclass->oc_tough;                             /* (Bitfield(oc_tough, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "oc_tough",  1);
+    bitfield = d_objclass->oc_dir;                               /* (Bitfield(oc_dir, 2)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "oc_dir",  2);
+    bitfield = d_objclass->oc_material;                          /* (Bitfield(oc_material, 5)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "oc_material",  5);
+    sfo_schar(nhfp, &d_objclass->oc_subtyp, parent, "oc_subtyp", 1);/* (schar) */
+    sfo_uchar(nhfp, &d_objclass->oc_oprop, parent, "oc_oprop", 1);/* (uchar) */
+    sfo_char(nhfp, &d_objclass->oc_class, parent, "oc_class", 1);/* (char) */
+    sfo_schar(nhfp, &d_objclass->oc_delay, parent, "oc_delay", 1);/* (schar) */
+    sfo_uchar(nhfp, &d_objclass->oc_color, parent, "oc_color", 1);/* (uchar) */
+    sfo_short(nhfp, &d_objclass->oc_prob, parent, "oc_prob", 1); /* (short) */
+    sfo_ushort(nhfp, &d_objclass->oc_weight, parent, "oc_weight", 1);/* (unsigned short) */
+    sfo_short(nhfp, &d_objclass->oc_cost, parent, "oc_cost", 1); /* (short) */
+    sfo_schar(nhfp, &d_objclass->oc_wsdam, parent, "oc_wsdam", 1);/* (schar) */
+    sfo_schar(nhfp, &d_objclass->oc_wldam, parent, "oc_wldam", 1);/* (schar) */
+    sfo_schar(nhfp, &d_objclass->oc_oc1, parent, "oc_oc1", 1);   /* (schar) */
+    sfo_schar(nhfp, &d_objclass->oc_oc2, parent, "oc_oc2", 1);   /* (schar) */
+    sfo_ushort(nhfp, &d_objclass->oc_nutrition, parent, "oc_nutrition", 1);/* (unsigned short) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "objclass", 1);
+}
+
+void
+sfo_obj_split(nhfp, d_obj_split, myparent, myname, cnt)
+NHFILE *nhfp;
+struct obj_split *d_obj_split;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "obj_split";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "obj_split", 1);
+
+    sfo_unsigned(nhfp, &d_obj_split->parent_oid, parent, "parent_oid", 1);/* (unsigned) */
+    sfo_unsigned(nhfp, &d_obj_split->child_oid, parent, "child_oid", 1);/* (unsigned) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "obj_split", 1);
+}
+
+void
+sfo_oextra(nhfp, d_oextra, myparent, myname, cnt)
+NHFILE *nhfp;
+struct oextra *d_oextra;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "oextra";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "oextra", 1);
+
+    sfo_char(nhfp, d_oextra->oname, parent, "oname", 1);         /* (char *) */
+    sfo_genericptr(nhfp, (genericptr_t) &d_oextra->omonst, parent, "omonst", 1);/* (struct monst *) */
+    sfo_unsigned(nhfp, d_oextra->omid, parent, "omid", 1);       /* (unsigned *) */
+    sfo_long(nhfp, d_oextra->olong, parent, "olong", 1);         /* (long *) */
+    sfo_char(nhfp, d_oextra->omailcmd, parent, "omailcmd", 1);   /* (char *) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "oextra", 1);
+}
+
+void
+sfo_polearm_info(nhfp, d_polearm_info, myparent, myname, cnt)
+NHFILE *nhfp;
+struct polearm_info *d_polearm_info;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "polearm_info";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "polearm_info", 1);
+
+    sfo_genericptr(nhfp, (genericptr_t) &d_polearm_info->hitmon, parent, "hitmon", 1);/* (struct monst *) */
+    sfo_unsigned(nhfp, &d_polearm_info->m_id, parent, "m_id", 1);/* (unsigned) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "polearm_info", 1);
+}
+
+void
+sfo_prop(nhfp, d_prop, myparent, myname, cnt)
+NHFILE *nhfp;
+struct prop *d_prop;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "prop";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "prop", 1);
+
+    sfo_long(nhfp, &d_prop->extrinsic, parent, "extrinsic", 1);  /* (long) */
+    sfo_long(nhfp, &d_prop->blocked, parent, "blocked", 1);      /* (long) */
+    sfo_long(nhfp, &d_prop->intrinsic, parent, "intrinsic", 1);  /* (long) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "prop", 1);
+}
+
+void
+sfo_q_score(nhfp, d_q_score, myparent, myname, cnt)
+NHFILE *nhfp;
+struct q_score *d_q_score;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "q_score";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "q_score", 1);
+
+    bitfield = d_q_score->first_start;                           /* (Bitfield(first_start, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "first_start",  1);
+    bitfield = d_q_score->met_leader;                            /* (Bitfield(met_leader, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "met_leader",  1);
+    bitfield = d_q_score->not_ready;                             /* (Bitfield(not_ready, 3)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "not_ready",  3);
+    bitfield = d_q_score->pissed_off;                            /* (Bitfield(pissed_off, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "pissed_off",  1);
+    bitfield = d_q_score->got_quest;                             /* (Bitfield(got_quest, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "got_quest",  1);
+    bitfield = d_q_score->first_locate;                          /* (Bitfield(first_locate, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "first_locate",  1);
+    bitfield = d_q_score->met_intermed;                          /* (Bitfield(met_intermed, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "met_intermed",  1);
+    bitfield = d_q_score->got_final;                             /* (Bitfield(got_final, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "got_final",  1);
+    bitfield = d_q_score->made_goal;                             /* (Bitfield(made_goal, 3)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "made_goal",  3);
+    bitfield = d_q_score->met_nemesis;                           /* (Bitfield(met_nemesis, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "met_nemesis",  1);
+    bitfield = d_q_score->killed_nemesis;                        /* (Bitfield(killed_nemesis, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "killed_nemesis",  1);
+    bitfield = d_q_score->in_battle;                             /* (Bitfield(in_battle, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "in_battle",  1);
+    bitfield = d_q_score->cheater;                               /* (Bitfield(cheater, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "cheater",  1);
+    bitfield = d_q_score->touched_artifact;                      /* (Bitfield(touched_artifact, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "touched_artifact",  1);
+    bitfield = d_q_score->offered_artifact;                      /* (Bitfield(offered_artifact, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "offered_artifact",  1);
+    bitfield = d_q_score->got_thanks;                            /* (Bitfield(got_thanks, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "got_thanks",  1);
+    bitfield = d_q_score->ldrgend;                               /* (Bitfield(ldrgend, 2)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "ldrgend",  2);
+    bitfield = d_q_score->nemgend;                               /* (Bitfield(nemgend, 2)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "nemgend",  2);
+    bitfield = d_q_score->godgend;                               /* (Bitfield(godgend, 2)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "godgend",  2);
+    bitfield = d_q_score->leader_is_dead;                        /* (Bitfield(leader_is_dead, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "leader_is_dead",  1);
+    sfo_unsigned(nhfp, &d_q_score->leader_m_id, parent, "leader_m_id", 1);/* (unsigned) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "q_score", 1);
+}
+
+void
+sfo_rm(nhfp, d_rm, myparent, myname, cnt)
+NHFILE *nhfp;
+struct rm *d_rm;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "rm";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "rm", 1);
+
+    sfo_int(nhfp, &d_rm->glyph, parent, "glyph", 1);             /* (int) */
+    sfo_schar(nhfp, &d_rm->typ, parent, "typ", 1);               /* (schar) */
+    sfo_uchar(nhfp, &d_rm->seenv, parent, "seenv", 1);           /* (uchar) */
+    bitfield = d_rm->flags;                                      /* (Bitfield(flags, 5)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "flags",  5);
+    bitfield = d_rm->horizontal;                                 /* (Bitfield(horizontal, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "horizontal",  1);
+    bitfield = d_rm->lit;                                        /* (Bitfield(lit, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "lit",  1);
+    bitfield = d_rm->waslit;                                     /* (Bitfield(waslit, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "waslit",  1);
+    bitfield = d_rm->roomno;                                     /* (Bitfield(roomno, 6)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "roomno",  6);
+    bitfield = d_rm->edge;                                       /* (Bitfield(edge, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "edge",  1);
+    bitfield = d_rm->candig;                                     /* (Bitfield(candig, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "candig",  1);
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "rm", 1);
+}
+
+void
+sfo_s_level(nhfp, d_s_level, myparent, myname, cnt)
+NHFILE *nhfp;
+struct s_level *d_s_level;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "s_level";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "s_level", 1);
+
+    sfo_genericptr(nhfp, (genericptr_t) &d_s_level->next, parent, "next", 1);/* (struct s_level *) */
+    sfo_d_level(nhfp, &d_s_level->dlevel, parent, "dlevel", 1);  /* (d_level) */
+    sfo_char(nhfp, d_s_level->proto, parent, "proto", 15);       /* (char) */
+    sfo_char(nhfp, &d_s_level->boneid, parent, "boneid", 1);     /* (char) */
+    sfo_uchar(nhfp, &d_s_level->rndlevs, parent, "rndlevs", 1);  /* (uchar) */
+    sfo_d_flags(nhfp, &d_s_level->flags, parent, "flags", 1);    /* (d_flags) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "s_level", 1);
+}
+
+void
+sfo_savefile_info(nhfp, d_savefile_info, myparent, myname, cnt)
+NHFILE *nhfp;
+struct savefile_info *d_savefile_info;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "savefile_info";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "savefile_info", 1);
+
+    sfo_ulong(nhfp, &d_savefile_info->sfi1, parent, "sfi1", 1);  /* (unsigned long) */
+    sfo_ulong(nhfp, &d_savefile_info->sfi2, parent, "sfi2", 1);  /* (unsigned long) */
+    sfo_ulong(nhfp, &d_savefile_info->sfi3, parent, "sfi3", 1);  /* (unsigned long) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "savefile_info", 1);
+}
+
+void
+sfo_skills(nhfp, d_skills, myparent, myname, cnt)
+NHFILE *nhfp;
+struct skills *d_skills;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "skills";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "skills", 1);
+
+    sfo_xchar(nhfp, &d_skills->skill, parent, "skill", 1);       /* (xchar) */
+    sfo_xchar(nhfp, &d_skills->max_skill, parent, "max_skill", 1);/* (xchar) */
+    sfo_ushort(nhfp, &d_skills->advance, parent, "advance", 1);  /* (unsigned short) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "skills", 1);
+}
+
+void
+sfo_spell(nhfp, d_spell, myparent, myname, cnt)
+NHFILE *nhfp;
+struct spell *d_spell;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "spell";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "spell", 1);
+
+    sfo_short(nhfp, &d_spell->sp_id, parent, "sp_id", 1);        /* (short) */
+    sfo_xchar(nhfp, &d_spell->sp_lev, parent, "sp_lev", 1);      /* (xchar) */
+    sfo_int(nhfp, &d_spell->sp_know, parent, "sp_know", 1);      /* (int) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "spell", 1);
+}
+
+void
+sfo_stairway(nhfp, d_stairway, myparent, myname, cnt)
+NHFILE *nhfp;
+struct stairway *d_stairway;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "stairway";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "stairway", 1);
+
+    sfo_xchar(nhfp, &d_stairway->sx, parent, "sx", 1);           /* (xchar) */
+    sfo_xchar(nhfp, &d_stairway->sy, parent, "sy", 1);           /* (xchar) */
+    sfo_d_level(nhfp, &d_stairway->tolev, parent, "tolev", 1);   /* (d_level) */
+    sfo_char(nhfp, &d_stairway->up, parent, "up", 1);            /* (char) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "stairway", 1);
+}
+
+void
+sfo_takeoff_info(nhfp, d_takeoff_info, myparent, myname, cnt)
+NHFILE *nhfp;
+struct takeoff_info *d_takeoff_info;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "takeoff_info";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "takeoff_info", 1);
+
+    sfo_long(nhfp, &d_takeoff_info->mask, parent, "mask", 1);    /* (long) */
+    sfo_long(nhfp, &d_takeoff_info->what, parent, "what", 1);    /* (long) */
+    sfo_int(nhfp, &d_takeoff_info->delay, parent, "delay", 1);   /* (int) */
+    sfo_boolean(nhfp, &d_takeoff_info->cancelled_don, parent, "cancelled_don", 1);/* (boolean) */
+    sfo_char(nhfp, d_takeoff_info->disrobing, parent, "disrobing", CONTEXTVERBSZ + 1);/* (char) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "takeoff_info", 1);
+}
+
+void
+sfo_tin_info(nhfp, d_tin_info, myparent, myname, cnt)
+NHFILE *nhfp;
+struct tin_info *d_tin_info;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "tin_info";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "tin_info", 1);
+
+    sfo_genericptr(nhfp, (genericptr_t) &d_tin_info->tin, parent, "tin", 1);/* (struct obj *) */
+    sfo_unsigned(nhfp, &d_tin_info->o_id, parent, "o_id", 1);    /* (unsigned) */
+    sfo_int(nhfp, &d_tin_info->usedtime, parent, "usedtime", 1); /* (int) */
+    sfo_int(nhfp, &d_tin_info->reqtime, parent, "reqtime", 1);   /* (int) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "tin_info", 1);
+}
+
+void
+sfo_trap(nhfp, d_trap, myparent, myname, cnt)
+NHFILE *nhfp;
+struct trap *d_trap;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "trap";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "trap", 1);
+
+    sfo_genericptr(nhfp, (genericptr_t) &d_trap->ntrap, parent, "ntrap", 1);/* (struct trap *) */
+    sfo_xchar(nhfp, &d_trap->tx, parent, "tx", 1);               /* (xchar) */
+    sfo_xchar(nhfp, &d_trap->ty, parent, "ty", 1);               /* (xchar) */
+    sfo_d_level(nhfp, &d_trap->dst, parent, "dst", 1);           /* (d_level) */
+    sfo_nhcoord(nhfp, &d_trap->launch, parent, "launch", 1);     /* (nhcoord) */
+    bitfield = d_trap->ttyp;                                     /* (Bitfield(ttyp, 5)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "ttyp",  5);
+    bitfield = d_trap->tseen;                                    /* (Bitfield(tseen, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "tseen",  1);
+    bitfield = d_trap->once;                                     /* (Bitfield(once, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "once",  1);
+    bitfield = d_trap->madeby_u;                                 /* (Bitfield(madeby_u, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "madeby_u",  1);
+    sfo_vlaunchinfo(nhfp, &d_trap->vl, parent, "vl", 1);         /* (vlaunchinfo) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "trap", 1);
+}
+
+void
+sfo_tribute_info(nhfp, d_tribute_info, myparent, myname, cnt)
+NHFILE *nhfp;
+struct tribute_info *d_tribute_info;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "tribute_info";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "tribute_info", 1);
+
+    sfo_size_t(nhfp, &d_tribute_info->tributesz, parent, "tributesz", 1);/* (size_t) */
+    sfo_boolean(nhfp, &d_tribute_info->enabled, parent, "enabled", 1);/* (boolean) */
+    bitfield = d_tribute_info->bookstock;                        /* (Bitfield(bookstock, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "bookstock",  1);
+    bitfield = d_tribute_info->Deathnotice;                      /* (Bitfield(Deathnotice,1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "Deathnotice", 1);
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "tribute_info", 1);
+}
+
+void
+sfo_u_achieve(nhfp, d_u_achieve, myparent, myname, cnt)
+NHFILE *nhfp;
+struct u_achieve *d_u_achieve;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "u_achieve";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "u_achieve", 1);
+
+    bitfield = d_u_achieve->amulet;                              /* (Bitfield(amulet, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "amulet",  1);
+    bitfield = d_u_achieve->bell;                                /* (Bitfield(bell, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "bell",  1);
+    bitfield = d_u_achieve->book;                                /* (Bitfield(book, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "book",  1);
+    bitfield = d_u_achieve->menorah;                             /* (Bitfield(menorah, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "menorah",  1);
+    bitfield = d_u_achieve->enter_gehennom;                      /* (Bitfield(enter_gehennom,1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "enter_gehennom", 1);
+    bitfield = d_u_achieve->ascended;                            /* (Bitfield(ascended, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "ascended",  1);
+    bitfield = d_u_achieve->mines_luckstone;                     /* (Bitfield(mines_luckstone, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "mines_luckstone",  1);
+    bitfield = d_u_achieve->finish_sokoban;                      /* (Bitfield(finish_sokoban, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "finish_sokoban",  1);
+    bitfield = d_u_achieve->killed_medusa;                       /* (Bitfield(killed_medusa, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "killed_medusa",  1);
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "u_achieve", 1);
+}
+
+void
+sfo_u_conduct(nhfp, d_u_conduct, myparent, myname, cnt)
+NHFILE *nhfp;
+struct u_conduct *d_u_conduct;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "u_conduct";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "u_conduct", 1);
+
+    sfo_long(nhfp, &d_u_conduct->unvegetarian, parent, "unvegetarian", 1);/* (long) */
+    sfo_long(nhfp, &d_u_conduct->unvegan, parent, "unvegan", 1); /* (long) */
+    sfo_long(nhfp, &d_u_conduct->food, parent, "food", 1);       /* (long) */
+    sfo_long(nhfp, &d_u_conduct->gnostic, parent, "gnostic", 1); /* (long) */
+    sfo_long(nhfp, &d_u_conduct->weaphit, parent, "weaphit", 1); /* (long) */
+    sfo_long(nhfp, &d_u_conduct->killer, parent, "killer", 1);   /* (long) */
+    sfo_long(nhfp, &d_u_conduct->literate, parent, "literate", 1);/* (long) */
+    sfo_long(nhfp, &d_u_conduct->polypiles, parent, "polypiles", 1);/* (long) */
+    sfo_long(nhfp, &d_u_conduct->polyselfs, parent, "polyselfs", 1);/* (long) */
+    sfo_long(nhfp, &d_u_conduct->wishes, parent, "wishes", 1);   /* (long) */
+    sfo_long(nhfp, &d_u_conduct->wisharti, parent, "wisharti", 1);/* (long) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "u_conduct", 1);
+}
+
+void
+sfo_u_event(nhfp, d_u_event, myparent, myname, cnt)
+NHFILE *nhfp;
+struct u_event *d_u_event;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "u_event";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "u_event", 1);
+
+    bitfield = d_u_event->minor_oracle;                          /* (Bitfield(minor_oracle, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "minor_oracle",  1);
+    bitfield = d_u_event->major_oracle;                          /* (Bitfield(major_oracle, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "major_oracle",  1);
+    bitfield = d_u_event->read_tribute;                          /* (Bitfield(read_tribute, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "read_tribute",  1);
+    bitfield = d_u_event->qcalled;                               /* (Bitfield(qcalled, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "qcalled",  1);
+    bitfield = d_u_event->qexpelled;                             /* (Bitfield(qexpelled, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "qexpelled",  1);
+    bitfield = d_u_event->qcompleted;                            /* (Bitfield(qcompleted, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "qcompleted",  1);
+    bitfield = d_u_event->uheard_tune;                           /* (Bitfield(uheard_tune, 2)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "uheard_tune",  2);
+    bitfield = d_u_event->uopened_dbridge;                       /* (Bitfield(uopened_dbridge, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "uopened_dbridge",  1);
+    bitfield = d_u_event->invoked;                               /* (Bitfield(invoked, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "invoked",  1);
+    bitfield = d_u_event->gehennom_entered;                      /* (Bitfield(gehennom_entered, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "gehennom_entered",  1);
+    bitfield = d_u_event->uhand_of_elbereth;                     /* (Bitfield(uhand_of_elbereth, 2)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "uhand_of_elbereth",  2);
+    bitfield = d_u_event->udemigod;                              /* (Bitfield(udemigod, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "udemigod",  1);
+    bitfield = d_u_event->uvibrated;                             /* (Bitfield(uvibrated, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "uvibrated",  1);
+    bitfield = d_u_event->ascended;                              /* (Bitfield(ascended, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "ascended",  1);
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "u_event", 1);
+}
+
+void
+sfo_u_have(nhfp, d_u_have, myparent, myname, cnt)
+NHFILE *nhfp;
+struct u_have *d_u_have;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "u_have";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "u_have", 1);
+
+    bitfield = d_u_have->amulet;                                 /* (Bitfield(amulet, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "amulet",  1);
+    bitfield = d_u_have->bell;                                   /* (Bitfield(bell, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "bell",  1);
+    bitfield = d_u_have->book;                                   /* (Bitfield(book, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "book",  1);
+    bitfield = d_u_have->menorah;                                /* (Bitfield(menorah, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "menorah",  1);
+    bitfield = d_u_have->questart;                               /* (Bitfield(questart, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "questart",  1);
+    bitfield = d_u_have->unused;                                 /* (Bitfield(unused, 3)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "unused",  3);
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "u_have", 1);
+}
+
+void
+sfo_u_realtime(nhfp, d_u_realtime, myparent, myname, cnt)
+NHFILE *nhfp;
+struct u_realtime *d_u_realtime;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "u_realtime";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "u_realtime", 1);
+
+    sfo_long(nhfp, &d_u_realtime->realtime, parent, "realtime", 1);/* (long) */
+    sfo_time_t(nhfp, &d_u_realtime->start_timing, parent, "start_timing", 1);/* (time_t) */
+    sfo_time_t(nhfp, &d_u_realtime->finish_time, parent, "finish_time", 1);/* (time_t) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "u_realtime", 1);
+}
+
+void
+sfo_u_roleplay(nhfp, d_u_roleplay, myparent, myname, cnt)
+NHFILE *nhfp;
+struct u_roleplay *d_u_roleplay;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "u_roleplay";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "u_roleplay", 1);
+
+    sfo_boolean(nhfp, &d_u_roleplay->blind, parent, "blind", 1); /* (boolean) */
+    sfo_boolean(nhfp, &d_u_roleplay->nudist, parent, "nudist", 1);/* (boolean) */
+    sfo_long(nhfp, &d_u_roleplay->numbones, parent, "numbones", 1);/* (long) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "u_roleplay", 1);
+}
+
+void
+sfo_version_info(nhfp, d_version_info, myparent, myname, cnt)
+NHFILE *nhfp;
+struct version_info *d_version_info;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "version_info";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "version_info", 1);
+
+    sfo_ulong(nhfp, &d_version_info->incarnation, parent, "incarnation", 1);/* (unsigned long) */
+    sfo_ulong(nhfp, &d_version_info->feature_set, parent, "feature_set", 1);/* (unsigned long) */
+    sfo_ulong(nhfp, &d_version_info->entity_count, parent, "entity_count", 1);/* (unsigned long) */
+    sfo_ulong(nhfp, &d_version_info->struct_sizes1, parent, "struct_sizes1", 1);/* (unsigned long) */
+    sfo_ulong(nhfp, &d_version_info->struct_sizes2, parent, "struct_sizes2", 1);/* (unsigned long) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "version_info", 1);
+}
+
+void
+sfo_victual_info(nhfp, d_victual_info, myparent, myname, cnt)
+NHFILE *nhfp;
+struct victual_info *d_victual_info;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "victual_info";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "victual_info", 1);
+
+    sfo_genericptr(nhfp, (genericptr_t) &d_victual_info->piece, parent, "piece", 1);/* (struct obj *) */
+    sfo_unsigned(nhfp, &d_victual_info->o_id, parent, "o_id", 1);/* (unsigned) */
+    sfo_int(nhfp, &d_victual_info->usedtime, parent, "usedtime", 1);/* (int) */
+    sfo_int(nhfp, &d_victual_info->reqtime, parent, "reqtime", 1);/* (int) */
+    sfo_int(nhfp, &d_victual_info->nmod, parent, "nmod", 1);     /* (int) */
+    bitfield = d_victual_info->canchoke;                         /* (Bitfield(canchoke, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "canchoke",  1);
+    bitfield = d_victual_info->fullwarn;                         /* (Bitfield(fullwarn, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "fullwarn",  1);
+    bitfield = d_victual_info->eating;                           /* (Bitfield(eating, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "eating",  1);
+    bitfield = d_victual_info->doreset;                          /* (Bitfield(doreset, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "doreset",  1);
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "victual_info", 1);
+}
+
+void
+sfo_vlaunchinfo(nhfp, d_vlaunchinfo, myparent, myname, cnt)
+NHFILE *nhfp;
+union vlaunchinfo *d_vlaunchinfo;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "vlaunchinfo";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "vlaunchinfo", 1);
+
+    sfo_short(nhfp, &d_vlaunchinfo->v_launch_otyp, parent, "v_launch_otyp", 1);/* (short) */
+    sfo_nhcoord(nhfp, &d_vlaunchinfo->v_launch2, parent, "v_launch2", 1);/* (nhcoord) */
+    sfo_uchar(nhfp, &d_vlaunchinfo->v_conjoined, parent, "v_conjoined", 1);/* (uchar) */
+    sfo_short(nhfp, &d_vlaunchinfo->v_tnote, parent, "v_tnote", 1);/* (short) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "vlaunchinfo", 1);
+}
+
+void
+sfo_vptrs(nhfp, d_vptrs, myparent, myname, cnt)
+NHFILE *nhfp;
+union vptrs *d_vptrs;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "vptrs";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "vptrs", 1);
+
+    sfo_genericptr(nhfp, (genericptr_t) &d_vptrs->v_nexthere, parent, "v_nexthere", 1);/* (struct obj *) */
+    sfo_genericptr(nhfp, (genericptr_t) &d_vptrs->v_ocontainer, parent, "v_ocontainer", 1);/* (struct obj *) */
+    sfo_genericptr(nhfp, (genericptr_t) &d_vptrs->v_ocarry, parent, "v_ocarry", 1);/* (struct monst *) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "vptrs", 1);
+}
+
+void
+sfo_warntype_info(nhfp, d_warntype_info, myparent, myname, cnt)
+NHFILE *nhfp;
+struct warntype_info *d_warntype_info;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "warntype_info";
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "warntype_info", 1);
+
+    sfo_ulong(nhfp, &d_warntype_info->obj, parent, "obj", 1);    /* (unsigned long) */
+    sfo_ulong(nhfp, &d_warntype_info->polyd, parent, "polyd", 1);/* (unsigned long) */
+    sfo_genericptr(nhfp, (genericptr_t) &d_warntype_info->species, parent, "species", 1);/* (struct permonst *) */
+    sfo_short(nhfp, &d_warntype_info->speciesidx, parent, "speciesidx", 1);/* (short) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "warntype_info", 1);
+}
+
+void
+sfo_you(nhfp, d_you, myparent, myname, cnt)
+NHFILE *nhfp;
+struct you *d_you;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "you";
+    int i;
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "start", "you", 1);
+
+    sfo_xchar(nhfp, &d_you->ux, parent, "ux", 1);                /* (xchar) */
+    sfo_xchar(nhfp, &d_you->uy, parent, "uy", 1);                /* (xchar) */
+    sfo_schar(nhfp, &d_you->dx, parent, "dx", 1);                /* (schar) */
+    sfo_schar(nhfp, &d_you->dy, parent, "dy", 1);                /* (schar) */
+    sfo_schar(nhfp, &d_you->dz, parent, "dz", 1);                /* (schar) */
+    sfo_schar(nhfp, &d_you->di, parent, "di", 1);                /* (schar) */
+    sfo_xchar(nhfp, &d_you->tx, parent, "tx", 1);                /* (xchar) */
+    sfo_xchar(nhfp, &d_you->ty, parent, "ty", 1);                /* (xchar) */
+    sfo_xchar(nhfp, &d_you->ux0, parent, "ux0", 1);              /* (xchar) */
+    sfo_xchar(nhfp, &d_you->uy0, parent, "uy0", 1);              /* (xchar) */
+    sfo_d_level(nhfp, &d_you->uz, parent, "uz", 1);              /* (d_level) */
+    sfo_d_level(nhfp, &d_you->uz0, parent, "uz0", 1);            /* (d_level) */
+    sfo_d_level(nhfp, &d_you->utolev, parent, "utolev", 1);      /* (d_level) */
+    sfo_uchar(nhfp, &d_you->utotype, parent, "utotype", 1);      /* (uchar) */
+    sfo_boolean(nhfp, &d_you->umoved, parent, "umoved", 1);      /* (boolean) */
+    sfo_int(nhfp, &d_you->last_str_turn, parent, "last_str_turn", 1);/* (int) */
+    sfo_int(nhfp, &d_you->ulevel, parent, "ulevel", 1);          /* (int) */
+    sfo_int(nhfp, &d_you->ulevelmax, parent, "ulevelmax", 1);    /* (int) */
+    sfo_unsigned(nhfp, &d_you->utrap, parent, "utrap", 1);       /* (unsigned) */
+    sfo_unsigned(nhfp, &d_you->utraptype, parent, "utraptype", 1);/* (unsigned) */
+    sfo_char(nhfp, d_you->urooms, parent, "urooms", 5);          /* (char) */
+    sfo_char(nhfp, d_you->urooms0, parent, "urooms0", 5);        /* (char) */
+    sfo_char(nhfp, d_you->uentered, parent, "uentered", 5);      /* (char) */
+    sfo_char(nhfp, d_you->ushops, parent, "ushops", 5);          /* (char) */
+    sfo_char(nhfp, d_you->ushops0, parent, "ushops0", 5);        /* (char) */
+    sfo_char(nhfp, d_you->ushops_entered, parent, "ushops_entered", 5);/* (char) */
+    sfo_char(nhfp, d_you->ushops_left, parent, "ushops_left", 5);/* (char) */
+    sfo_int(nhfp, &d_you->uhunger, parent, "uhunger", 1);        /* (int) */
+    sfo_unsigned(nhfp, &d_you->uhs, parent, "uhs", 1);           /* (unsigned) */
+    sfo_prop(nhfp, d_you->uprops, parent, "uprops", LAST_PROP + 1);/* (prop) */
+    sfo_unsigned(nhfp, &d_you->umconf, parent, "umconf", 1);     /* (unsigned) */
+    bitfield = d_you->usick_type;                                /* (Bitfield(usick_type, 2)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "usick_type",  2);
+    sfo_int(nhfp, &d_you->nv_range, parent, "nv_range", 1);      /* (int) */
+    sfo_int(nhfp, &d_you->xray_range, parent, "xray_range", 1);  /* (int) */
+    sfo_int(nhfp, &d_you->bglyph, parent, "bglyph", 1);          /* (int) */
+    sfo_int(nhfp, &d_you->cglyph, parent, "cglyph", 1);          /* (int) */
+    sfo_int(nhfp, &d_you->bc_order, parent, "bc_order", 1);      /* (int) */
+    sfo_int(nhfp, &d_you->bc_felt, parent, "bc_felt", 1);        /* (int) */
+    sfo_int(nhfp, &d_you->umonster, parent, "umonster", 1);      /* (int) */
+    sfo_int(nhfp, &d_you->umonnum, parent, "umonnum", 1);        /* (int) */
+    sfo_int(nhfp, &d_you->mh, parent, "mh", 1);                  /* (int) */
+    sfo_int(nhfp, &d_you->mhmax, parent, "mhmax", 1);            /* (int) */
+    sfo_int(nhfp, &d_you->mtimedone, parent, "mtimedone", 1);    /* (int) */
+    sfo_attribs(nhfp, &d_you->macurr, parent, "macurr", 1);      /* (attribs) */
+    sfo_attribs(nhfp, &d_you->mamax, parent, "mamax", 1);        /* (attribs) */
+    sfo_int(nhfp, &d_you->ulycn, parent, "ulycn", 1);            /* (int) */
+    sfo_unsigned(nhfp, &d_you->ucreamed, parent, "ucreamed", 1); /* (unsigned) */
+    sfo_unsigned(nhfp, &d_you->uswldtim, parent, "uswldtim", 1); /* (unsigned) */
+    bitfield = d_you->uswallow;                                  /* (Bitfield(uswallow, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "uswallow",  1);
+    bitfield = d_you->uinwater;                                  /* (Bitfield(uinwater, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "uinwater",  1);
+    bitfield = d_you->uundetected;                               /* (Bitfield(uundetected, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "uundetected",  1);
+    bitfield = d_you->mfemale;                                   /* (Bitfield(mfemale, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "mfemale",  1);
+    bitfield = d_you->uinvulnerable;                             /* (Bitfield(uinvulnerable, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "uinvulnerable",  1);
+    bitfield = d_you->uburied;                                   /* (Bitfield(uburied, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "uburied",  1);
+    bitfield = d_you->uedibility;                                /* (Bitfield(uedibility, 1)) */
+    sfo_bitfield(nhfp, &bitfield, parent, "uedibility",  1);
+    sfo_unsigned(nhfp, &d_you->udg_cnt, parent, "udg_cnt", 1);   /* (unsigned) */
+    sfo_u_achieve(nhfp, &d_you->uachieve, parent, "uachieve", 1);/* (u_achieve) */
+    sfo_u_event(nhfp, &d_you->uevent, parent, "uevent", 1);      /* (u_event) */
+    sfo_u_have(nhfp, &d_you->uhave, parent, "uhave", 1);         /* (u_have) */
+    sfo_u_conduct(nhfp, &d_you->uconduct, parent, "uconduct", 1);/* (u_conduct) */
+    sfo_u_roleplay(nhfp, &d_you->uroleplay, parent, "uroleplay", 1);/* (u_roleplay) */
+    sfo_attribs(nhfp, &d_you->acurr, parent, "acurr", 1);        /* (attribs) */
+    sfo_attribs(nhfp, &d_you->aexe, parent, "aexe", 1);          /* (attribs) */
+    sfo_attribs(nhfp, &d_you->abon, parent, "abon", 1);          /* (attribs) */
+    sfo_attribs(nhfp, &d_you->amax, parent, "amax", 1);          /* (attribs) */
+    sfo_attribs(nhfp, &d_you->atemp, parent, "atemp", 1);        /* (attribs) */
+    sfo_attribs(nhfp, &d_you->atime, parent, "atime", 1);        /* (attribs) */
+    sfo_align(nhfp, &d_you->ualign, parent, "ualign", 1);        /* (align) */
+    for (i = 0; i < CONVERT; ++i)
+        sfo_aligntyp(nhfp, &d_you->ualignbase[i], parent, "ualignbase", 1);/* (aligntyp) */
+    sfo_schar(nhfp, &d_you->uluck, parent, "uluck", 1);          /* (schar) */
+    sfo_schar(nhfp, &d_you->moreluck, parent, "moreluck", 1);    /* (schar) */
+    sfo_schar(nhfp, &d_you->uhitinc, parent, "uhitinc", 1);      /* (schar) */
+    sfo_schar(nhfp, &d_you->udaminc, parent, "udaminc", 1);      /* (schar) */
+    sfo_schar(nhfp, &d_you->uac, parent, "uac", 1);              /* (schar) */
+    sfo_uchar(nhfp, &d_you->uspellprot, parent, "uspellprot", 1);/* (uchar) */
+    sfo_uchar(nhfp, &d_you->usptime, parent, "usptime", 1);      /* (uchar) */
+    sfo_uchar(nhfp, &d_you->uspmtime, parent, "uspmtime", 1);    /* (uchar) */
+    sfo_int(nhfp, &d_you->uhp, parent, "uhp", 1);                /* (int) */
+    sfo_int(nhfp, &d_you->uhpmax, parent, "uhpmax", 1);          /* (int) */
+    sfo_int(nhfp, &d_you->uen, parent, "uen", 1);                /* (int) */
+    sfo_int(nhfp, &d_you->uenmax, parent, "uenmax", 1);          /* (int) */
+    sfo_xchar(nhfp, d_you->uhpinc, parent, "uhpinc", MAXULEV);   /* (xchar) */
+    sfo_xchar(nhfp, d_you->ueninc, parent, "ueninc", MAXULEV);   /* (xchar) */
+    sfo_int(nhfp, &d_you->ugangr, parent, "ugangr", 1);          /* (int) */
+    sfo_int(nhfp, &d_you->ugifts, parent, "ugifts", 1);          /* (int) */
+    sfo_int(nhfp, &d_you->ublessed, parent, "ublessed", 1);      /* (int) */
+    sfo_int(nhfp, &d_you->ublesscnt, parent, "ublesscnt", 1);    /* (int) */
+    sfo_long(nhfp, &d_you->umoney0, parent, "umoney0", 1);       /* (long) */
+    sfo_long(nhfp, &d_you->uspare1, parent, "uspare1", 1);       /* (long) */
+    sfo_long(nhfp, &d_you->uexp, parent, "uexp", 1);             /* (long) */
+    sfo_long(nhfp, &d_you->urexp, parent, "urexp", 1);           /* (long) */
+    sfo_long(nhfp, &d_you->ucleansed, parent, "ucleansed", 1);   /* (long) */
+    sfo_long(nhfp, &d_you->usleep, parent, "usleep", 1);         /* (long) */
+    sfo_int(nhfp, &d_you->uinvault, parent, "uinvault", 1);      /* (int) */
+    sfo_genericptr(nhfp, (genericptr_t) &d_you->ustuck, parent, "ustuck", 1);/* (struct monst *) */
+    sfo_genericptr(nhfp, (genericptr_t) &d_you->usteed, parent, "usteed", 1);/* (struct monst *) */
+    sfo_long(nhfp, &d_you->ugallop, parent, "ugallop", 1);       /* (long) */
+    sfo_int(nhfp, &d_you->urideturns, parent, "urideturns", 1);  /* (int) */
+    sfo_int(nhfp, &d_you->umortality, parent, "umortality", 1);  /* (int) */
+    sfo_int(nhfp, &d_you->ugrave_arise, parent, "ugrave_arise", 1);/* (int) */
+    sfo_int(nhfp, &d_you->weapon_slots, parent, "weapon_slots", 1);/* (int) */
+    sfo_int(nhfp, &d_you->skills_advanced, parent, "skills_advanced", 1);/* (int) */
+    sfo_xchar(nhfp, d_you->skill_record, parent, "skill_record", P_SKILL_LIMIT);/* (xchar) */
+    for (i = 0; i < P_NUM_SKILLS; ++i)
+        sfo_skills(nhfp, &d_you->weapon_skills[i], parent, "weapon_skills", 1);/* (skills) */
+    sfo_boolean(nhfp, &d_you->twoweap, parent, "twoweap", 1);    /* (boolean) */
+    sfo_short(nhfp, &d_you->mcham, parent, "mcham", 1);          /* (short) */
+
+    if (nhfp->addinfo)
+        sfo_addinfo(nhfp, myparent, "end", "you", 1);
+}
+
+void
+sfi_align(nhfp, d_align, myparent, myname, cnt)
+NHFILE *nhfp;
+struct align *d_align;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "align";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "align", 1);
+
+    sfi_aligntyp(nhfp, &d_align->type, parent, "type", 1);
+    sfi_int(nhfp, &d_align->record, parent, "record", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "align", 1);
+}
+
+void
+sfi_attribs(nhfp, d_attribs, myparent, myname, cnt)
+NHFILE *nhfp;
+struct attribs *d_attribs;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "attribs";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "attribs", 1);
+
+    sfi_schar(nhfp, d_attribs->a, parent, "a", A_MAX);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "attribs", 1);
+}
+
+void
+sfi_bill_x(nhfp, d_bill_x, myparent, myname, cnt)
+NHFILE *nhfp;
+struct bill_x *d_bill_x;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "bill_x";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "bill_x", 1);
+
+    sfi_unsigned(nhfp, &d_bill_x->bo_id, parent, "bo_id", 1);
+    sfi_boolean(nhfp, &d_bill_x->useup, parent, "useup", 1);
+    sfi_long(nhfp, &d_bill_x->price, parent, "price", 1);
+    sfi_long(nhfp, &d_bill_x->bquan, parent, "bquan", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "bill_x", 1);
+}
+
+void
+sfi_book_info(nhfp, d_book_info, myparent, myname, cnt)
+NHFILE *nhfp;
+struct book_info *d_book_info;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "book_info";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "book_info", 1);
+
+    sfi_genericptr(nhfp, (genericptr_t) &d_book_info->book, parent, "book", 1);
+    sfi_unsigned(nhfp, &d_book_info->o_id, parent, "o_id", 1);
+    sfi_schar(nhfp, &d_book_info->delay, parent, "delay", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "book_info", 1);
+}
+
+void
+sfi_branch(nhfp, d_branch, myparent, myname, cnt)
+NHFILE *nhfp;
+struct branch *d_branch;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "branch";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "branch", 1);
+
+    sfi_genericptr(nhfp, (genericptr_t) &d_branch->next, parent, "next", 1);
+    sfi_int(nhfp, &d_branch->id, parent, "id", 1);
+    sfi_int(nhfp, &d_branch->type, parent, "type", 1);
+    sfi_d_level(nhfp, &d_branch->end1, parent, "end1", 1);
+    sfi_d_level(nhfp, &d_branch->end2, parent, "end2", 1);
+    sfi_boolean(nhfp, &d_branch->end1_up, parent, "end1_up", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "branch", 1);
+}
+
+void
+sfi_bubble(nhfp, d_bubble, myparent, myname, cnt)
+NHFILE *nhfp;
+struct bubble *d_bubble;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "bubble";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "bubble", 1);
+
+    sfi_xchar(nhfp, &d_bubble->x, parent, "x", 1);
+    sfi_xchar(nhfp, &d_bubble->y, parent, "y", 1);
+    sfi_schar(nhfp, &d_bubble->dx, parent, "dx", 1);
+    sfi_schar(nhfp, &d_bubble->dy, parent, "dy", 1);
+    sfi_uchar(nhfp, d_bubble->bm, parent, "bm", MAX_BMASK + 2);
+    sfi_genericptr(nhfp, (genericptr_t) &d_bubble->prev, parent, "prev", 1);
+    sfi_genericptr(nhfp, (genericptr_t) &d_bubble->next, parent, "next", 1);
+    sfi_genericptr(nhfp, (genericptr_t) &d_bubble->cons, parent, "cons", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "bubble", 1);
+}
+
+void
+sfi_cemetery(nhfp, d_cemetery, myparent, myname, cnt)
+NHFILE *nhfp;
+struct cemetery *d_cemetery;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "cemetery";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "cemetery", 1);
+
+    sfi_genericptr(nhfp, (genericptr_t) &d_cemetery->next, parent, "next", 1);
+    sfi_char(nhfp, d_cemetery->who, parent, "who", PL_NSIZ + 4 * (1 + 3) + 1);
+    sfi_char(nhfp, d_cemetery->how, parent, "how", 100 + 1);
+    sfi_char(nhfp, d_cemetery->when, parent, "when", 4 + 2 + 2 + 2 + 2 + 2 + 1);
+    sfi_schar(nhfp, &d_cemetery->frpx, parent, "frpx", 1);
+    sfi_schar(nhfp, &d_cemetery->frpy, parent, "frpy", 1);
+    sfi_boolean(nhfp, &d_cemetery->bonesknown, parent, "bonesknown", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "cemetery", 1);
+}
+
+void
+sfi_context_info(nhfp, d_context_info, myparent, myname, cnt)
+NHFILE *nhfp;
+struct context_info *d_context_info;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "context_info";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "context_info", 1);
+
+    sfi_unsigned(nhfp, &d_context_info->ident, parent, "ident", 1);
+    sfi_unsigned(nhfp, &d_context_info->no_of_wizards, parent, "no_of_wizards", 1);
+    sfi_unsigned(nhfp, &d_context_info->run, parent, "run", 1);
+    sfi_unsigned(nhfp, &d_context_info->startingpet_mid, parent, "startingpet_mid", 1);
+    sfi_int(nhfp, &d_context_info->current_fruit, parent, "current_fruit", 1);
+    sfi_int(nhfp, &d_context_info->warnlevel, parent, "warnlevel", 1);
+    sfi_int(nhfp, &d_context_info->rndencode, parent, "rndencode", 1);
+    sfi_long(nhfp, &d_context_info->next_attrib_check, parent, "next_attrib_check", 1);
+    sfi_long(nhfp, &d_context_info->stethoscope_move, parent, "stethoscope_move", 1);
+    sfi_short(nhfp, &d_context_info->stethoscope_movement, parent, "stethoscope_movement", 1);
+    sfi_boolean(nhfp, &d_context_info->travel, parent, "travel", 1);
+    sfi_boolean(nhfp, &d_context_info->travel1, parent, "travel1", 1);
+    sfi_boolean(nhfp, &d_context_info->forcefight, parent, "forcefight", 1);
+    sfi_boolean(nhfp, &d_context_info->nopick, parent, "nopick", 1);
+    sfi_boolean(nhfp, &d_context_info->made_amulet, parent, "made_amulet", 1);
+    sfi_boolean(nhfp, &d_context_info->mon_moving, parent, "mon_moving", 1);
+    sfi_boolean(nhfp, &d_context_info->move, parent, "move", 1);
+    sfi_boolean(nhfp, &d_context_info->mv, parent, "mv", 1);
+    sfi_boolean(nhfp, &d_context_info->bypasses, parent, "bypasses", 1);
+    sfi_boolean(nhfp, &d_context_info->botl, parent, "botl", 1);
+    sfi_boolean(nhfp, &d_context_info->botlx, parent, "botlx", 1);
+    sfi_boolean(nhfp, &d_context_info->door_opened, parent, "door_opened", 1);
+    sfi_dig_info(nhfp, &d_context_info->digging, parent, "digging", 1);
+    sfi_victual_info(nhfp, &d_context_info->victual, parent, "victual", 1);
+    sfi_tin_info(nhfp, &d_context_info->tin, parent, "tin", 1);
+    sfi_book_info(nhfp, &d_context_info->spbook, parent, "spbook", 1);
+    sfi_takeoff_info(nhfp, &d_context_info->takeoff, parent, "takeoff", 1);
+    sfi_warntype_info(nhfp, &d_context_info->warntype, parent, "warntype", 1);
+    sfi_polearm_info(nhfp, &d_context_info->polearm, parent, "polearm", 1);
+    sfi_obj_split(nhfp, &d_context_info->objsplit, parent, "objsplit", 1);
+    sfi_tribute_info(nhfp, &d_context_info->tribute, parent, "tribute", 1);
+    sfi_novel_tracking(nhfp, &d_context_info->novel, parent, "novel", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "context_info", 1);
+}
+
+void
+sfi_d_flags(nhfp, d_d_flags, myparent, myname, cnt)
+NHFILE *nhfp;
+struct d_flags *d_d_flags;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "d_flags";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "d_flags", 1);
+
+    bitfield = d_d_flags->town;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "town",  1);
+    d_d_flags->town = bitfield;
+
+    bitfield = d_d_flags->hellish;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "hellish",  1);
+    d_d_flags->hellish = bitfield;
+
+    bitfield = d_d_flags->maze_like;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "maze_like",  1);
+    d_d_flags->maze_like = bitfield;
+
+    bitfield = d_d_flags->rogue_like;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "rogue_like",  1);
+    d_d_flags->rogue_like = bitfield;
+
+    bitfield = d_d_flags->align;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "align",  3);
+    d_d_flags->align = bitfield;
+
+    bitfield = d_d_flags->unused;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "unused",  1);
+    d_d_flags->unused = bitfield;
+
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "d_flags", 1);
+}
+
+void
+sfi_d_level(nhfp, d_d_level, myparent, myname, cnt)
+NHFILE *nhfp;
+struct d_level *d_d_level;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "d_level";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "d_level", 1);
+
+    sfi_xchar(nhfp, &d_d_level->dnum, parent, "dnum", 1);
+    sfi_xchar(nhfp, &d_d_level->dlevel, parent, "dlevel", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "d_level", 1);
+}
+
+void
+sfi_damage(nhfp, d_damage, myparent, myname, cnt)
+NHFILE *nhfp;
+struct damage *d_damage;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "damage";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "damage", 1);
+
+    sfi_genericptr(nhfp, (genericptr_t) &d_damage->next, parent, "next", 1);
+    sfi_long(nhfp, &d_damage->when, parent, "when", 1);
+    sfi_long(nhfp, &d_damage->cost, parent, "cost", 1);
+    sfi_nhcoord(nhfp, &d_damage->place, parent, "place", 1);
+    sfi_schar(nhfp, &d_damage->typ, parent, "typ", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "damage", 1);
+}
+
+void
+sfi_dest_area(nhfp, d_dest_area, myparent, myname, cnt)
+NHFILE *nhfp;
+struct dest_area *d_dest_area;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "dest_area";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "dest_area", 1);
+
+    sfi_xchar(nhfp, &d_dest_area->lx, parent, "lx", 1);
+    sfi_xchar(nhfp, &d_dest_area->ly, parent, "ly", 1);
+    sfi_xchar(nhfp, &d_dest_area->hx, parent, "hx", 1);
+    sfi_xchar(nhfp, &d_dest_area->hy, parent, "hy", 1);
+    sfi_xchar(nhfp, &d_dest_area->nlx, parent, "nlx", 1);
+    sfi_xchar(nhfp, &d_dest_area->nly, parent, "nly", 1);
+    sfi_xchar(nhfp, &d_dest_area->nhx, parent, "nhx", 1);
+    sfi_xchar(nhfp, &d_dest_area->nhy, parent, "nhy", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "dest_area", 1);
+}
+
+void
+sfi_dgn_topology(nhfp, d_dgn_topology, myparent, myname, cnt)
+NHFILE *nhfp;
+struct dgn_topology *d_dgn_topology;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "dgn_topology";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "dgn_topology", 1);
+
+    sfi_d_level(nhfp, &d_dgn_topology->d_oracle_level, parent, "d_oracle_level", 1);
+    sfi_d_level(nhfp, &d_dgn_topology->d_bigroom_level, parent, "d_bigroom_level", 1);
+    sfi_d_level(nhfp, &d_dgn_topology->d_rogue_level, parent, "d_rogue_level", 1);
+    sfi_d_level(nhfp, &d_dgn_topology->d_medusa_level, parent, "d_medusa_level", 1);
+    sfi_d_level(nhfp, &d_dgn_topology->d_stronghold_level, parent, "d_stronghold_level", 1);
+    sfi_d_level(nhfp, &d_dgn_topology->d_valley_level, parent, "d_valley_level", 1);
+    sfi_d_level(nhfp, &d_dgn_topology->d_wiz1_level, parent, "d_wiz1_level", 1);
+    sfi_d_level(nhfp, &d_dgn_topology->d_wiz2_level, parent, "d_wiz2_level", 1);
+    sfi_d_level(nhfp, &d_dgn_topology->d_wiz3_level, parent, "d_wiz3_level", 1);
+    sfi_d_level(nhfp, &d_dgn_topology->d_juiblex_level, parent, "d_juiblex_level", 1);
+    sfi_d_level(nhfp, &d_dgn_topology->d_orcus_level, parent, "d_orcus_level", 1);
+    sfi_d_level(nhfp, &d_dgn_topology->d_baalzebub_level, parent, "d_baalzebub_level", 1);
+    sfi_d_level(nhfp, &d_dgn_topology->d_asmodeus_level, parent, "d_asmodeus_level", 1);
+    sfi_d_level(nhfp, &d_dgn_topology->d_portal_level, parent, "d_portal_level", 1);
+    sfi_d_level(nhfp, &d_dgn_topology->d_sanctum_level, parent, "d_sanctum_level", 1);
+    sfi_d_level(nhfp, &d_dgn_topology->d_earth_level, parent, "d_earth_level", 1);
+    sfi_d_level(nhfp, &d_dgn_topology->d_water_level, parent, "d_water_level", 1);
+    sfi_d_level(nhfp, &d_dgn_topology->d_fire_level, parent, "d_fire_level", 1);
+    sfi_d_level(nhfp, &d_dgn_topology->d_air_level, parent, "d_air_level", 1);
+    sfi_d_level(nhfp, &d_dgn_topology->d_astral_level, parent, "d_astral_level", 1);
+    sfi_xchar(nhfp, &d_dgn_topology->d_tower_dnum, parent, "d_tower_dnum", 1);
+    sfi_xchar(nhfp, &d_dgn_topology->d_sokoban_dnum, parent, "d_sokoban_dnum", 1);
+    sfi_xchar(nhfp, &d_dgn_topology->d_mines_dnum, parent, "d_mines_dnum", 1);
+    sfi_xchar(nhfp, &d_dgn_topology->d_quest_dnum, parent, "d_quest_dnum", 1);
+    sfi_d_level(nhfp, &d_dgn_topology->d_qstart_level, parent, "d_qstart_level", 1);
+    sfi_d_level(nhfp, &d_dgn_topology->d_qlocate_level, parent, "d_qlocate_level", 1);
+    sfi_d_level(nhfp, &d_dgn_topology->d_nemesis_level, parent, "d_nemesis_level", 1);
+    sfi_d_level(nhfp, &d_dgn_topology->d_knox_level, parent, "d_knox_level", 1);
+    sfi_d_level(nhfp, &d_dgn_topology->d_mineend_level, parent, "d_mineend_level", 1);
+    sfi_d_level(nhfp, &d_dgn_topology->d_sokoend_level, parent, "d_sokoend_level", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "dgn_topology", 1);
+}
+
+void
+sfi_dig_info(nhfp, d_dig_info, myparent, myname, cnt)
+NHFILE *nhfp;
+struct dig_info *d_dig_info;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "dig_info";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "dig_info", 1);
+
+    sfi_int(nhfp, &d_dig_info->effort, parent, "effort", 1);
+    sfi_d_level(nhfp, &d_dig_info->level, parent, "level", 1);
+    sfi_nhcoord(nhfp, &d_dig_info->pos, parent, "pos", 1);
+    sfi_long(nhfp, &d_dig_info->lastdigtime, parent, "lastdigtime", 1);
+    sfi_boolean(nhfp, &d_dig_info->down, parent, "down", 1);
+    sfi_boolean(nhfp, &d_dig_info->chew, parent, "chew", 1);
+    sfi_boolean(nhfp, &d_dig_info->warned, parent, "warned", 1);
+    sfi_boolean(nhfp, &d_dig_info->quiet, parent, "quiet", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "dig_info", 1);
+}
+
+void
+sfi_dungeon(nhfp, d_dungeon, myparent, myname, cnt)
+NHFILE *nhfp;
+struct dungeon *d_dungeon;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "dungeon";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "dungeon", 1);
+
+    sfi_char(nhfp, d_dungeon->dname, parent, "dname", 24);
+    sfi_char(nhfp, d_dungeon->proto, parent, "proto", 15);
+    sfi_char(nhfp, &d_dungeon->boneid, parent, "boneid", 1);
+    sfi_d_flags(nhfp, &d_dungeon->flags, parent, "flags", 1);
+    sfi_xchar(nhfp, &d_dungeon->entry_lev, parent, "entry_lev", 1);
+    sfi_xchar(nhfp, &d_dungeon->num_dunlevs, parent, "num_dunlevs", 1);
+    sfi_xchar(nhfp, &d_dungeon->dunlev_ureached, parent, "dunlev_ureached", 1);
+    sfi_int(nhfp, &d_dungeon->ledger_start, parent, "ledger_start", 1);
+    sfi_int(nhfp, &d_dungeon->depth_start, parent, "depth_start", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "dungeon", 1);
+}
+
+void
+sfi_edog(nhfp, d_edog, myparent, myname, cnt)
+NHFILE *nhfp;
+struct edog *d_edog;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "edog";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "edog", 1);
+
+    sfi_long(nhfp, &d_edog->droptime, parent, "droptime", 1);
+    sfi_unsigned(nhfp, &d_edog->dropdist, parent, "dropdist", 1);
+    sfi_int(nhfp, &d_edog->apport, parent, "apport", 1);
+    sfi_long(nhfp, &d_edog->whistletime, parent, "whistletime", 1);
+    sfi_long(nhfp, &d_edog->hungrytime, parent, "hungrytime", 1);
+    sfi_nhcoord(nhfp, &d_edog->ogoal, parent, "ogoal", 1);
+    sfi_int(nhfp, &d_edog->abuse, parent, "abuse", 1);
+    sfi_int(nhfp, &d_edog->revivals, parent, "revivals", 1);
+    sfi_int(nhfp, &d_edog->mhpmax_penalty, parent, "mhpmax_penalty", 1);
+    bitfield = d_edog->killed_by_u;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "killed_by_u",  1);
+    d_edog->killed_by_u = bitfield;
+
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "edog", 1);
+}
+
+void
+sfi_egd(nhfp, d_egd, myparent, myname, cnt)
+NHFILE *nhfp;
+struct egd *d_egd;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "egd";
+    int i;
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "egd", 1);
+
+    sfi_int(nhfp, &d_egd->fcbeg, parent, "fcbeg", 1);
+    sfi_int(nhfp, &d_egd->fcend, parent, "fcend", 1);
+    sfi_int(nhfp, &d_egd->vroom, parent, "vroom", 1);
+    sfi_xchar(nhfp, &d_egd->gdx, parent, "gdx", 1);
+    sfi_xchar(nhfp, &d_egd->gdy, parent, "gdy", 1);
+    sfi_xchar(nhfp, &d_egd->ogx, parent, "ogx", 1);
+    sfi_xchar(nhfp, &d_egd->ogy, parent, "ogy", 1);
+    sfi_d_level(nhfp, &d_egd->gdlevel, parent, "gdlevel", 1);
+    sfi_xchar(nhfp, &d_egd->warncnt, parent, "warncnt", 1);
+    bitfield = d_egd->gddone;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "gddone",  1);
+    d_egd->gddone = bitfield;
+
+    bitfield = d_egd->witness;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "witness",  2);
+    d_egd->witness = bitfield;
+
+    bitfield = d_egd->unused;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "unused",  5);
+    d_egd->unused = bitfield;
+
+    for (i = 0; i < FCSIZ; ++i)
+        sfi_fakecorridor(nhfp, &d_egd->fakecorr[i], parent, "fakecorr", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "egd", 1);
+}
+
+void
+sfi_emin(nhfp, d_emin, myparent, myname, cnt)
+NHFILE *nhfp;
+struct emin *d_emin;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "emin";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "emin", 1);
+
+    sfi_aligntyp(nhfp, &d_emin->min_align, parent, "min_align", 1);
+    sfi_boolean(nhfp, &d_emin->renegade, parent, "renegade", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "emin", 1);
+}
+
+void
+sfi_engr(nhfp, d_engr, myparent, myname, cnt)
+NHFILE *nhfp;
+struct engr *d_engr;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "engr";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "engr", 1);
+
+    sfi_genericptr(nhfp, (genericptr_t) &d_engr->nxt_engr, parent, "nxt_engr", 1);
+    sfi_genericptr(nhfp, (genericptr_t) &d_engr->engr_txt, parent, "engr_txt", 1);
+    sfi_xchar(nhfp, &d_engr->engr_x, parent, "engr_x", 1);
+    sfi_xchar(nhfp, &d_engr->engr_y, parent, "engr_y", 1);
+    sfi_unsigned(nhfp, &d_engr->engr_lth, parent, "engr_lth", 1);
+    sfi_long(nhfp, &d_engr->engr_time, parent, "engr_time", 1);
+    sfi_xchar(nhfp, &d_engr->engr_type, parent, "engr_type", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "engr", 1);
+}
+
+void
+sfi_epri(nhfp, d_epri, myparent, myname, cnt)
+NHFILE *nhfp;
+struct epri *d_epri;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "epri";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "epri", 1);
+
+    sfi_aligntyp(nhfp, &d_epri->shralign, parent, "shralign", 1);
+    sfi_schar(nhfp, &d_epri->shroom, parent, "shroom", 1);
+    sfi_nhcoord(nhfp, &d_epri->shrpos, parent, "shrpos", 1);
+    sfi_d_level(nhfp, &d_epri->shrlevel, parent, "shrlevel", 1);
+    sfi_long(nhfp, &d_epri->intone_time, parent, "intone_time", 1);
+    sfi_long(nhfp, &d_epri->enter_time, parent, "enter_time", 1);
+    sfi_long(nhfp, &d_epri->hostile_time, parent, "hostile_time", 1);
+    sfi_long(nhfp, &d_epri->peaceful_time, parent, "peaceful_time", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "epri", 1);
+}
+
+void
+sfi_eshk(nhfp, d_eshk, myparent, myname, cnt)
+NHFILE *nhfp;
+struct eshk *d_eshk;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "eshk";
+    int i;
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "eshk", 1);
+
+    sfi_long(nhfp, &d_eshk->robbed, parent, "robbed", 1);
+    sfi_long(nhfp, &d_eshk->credit, parent, "credit", 1);
+    sfi_long(nhfp, &d_eshk->debit, parent, "debit", 1);
+    sfi_long(nhfp, &d_eshk->loan, parent, "loan", 1);
+    sfi_int(nhfp, &d_eshk->shoptype, parent, "shoptype", 1);
+    sfi_schar(nhfp, &d_eshk->shoproom, parent, "shoproom", 1);
+    sfi_schar(nhfp, &d_eshk->unused, parent, "unused", 1);
+    sfi_boolean(nhfp, &d_eshk->following, parent, "following", 1);
+    sfi_boolean(nhfp, &d_eshk->surcharge, parent, "surcharge", 1);
+    sfi_boolean(nhfp, &d_eshk->dismiss_kops, parent, "dismiss_kops", 1);
+    sfi_nhcoord(nhfp, &d_eshk->shk, parent, "shk", 1);
+    sfi_nhcoord(nhfp, &d_eshk->shd, parent, "shd", 1);
+    sfi_d_level(nhfp, &d_eshk->shoplevel, parent, "shoplevel", 1);
+    sfi_int(nhfp, &d_eshk->billct, parent, "billct", 1);
+    for (i = 0; i < BILLSZ; ++i)
+        sfi_bill_x(nhfp, &d_eshk->bill[i], parent, "bill", 1);
+    sfi_genericptr(nhfp, (genericptr_t) &d_eshk->bill_p, parent, "bill_p", 1);
+    sfi_int(nhfp, &d_eshk->visitct, parent, "visitct", 1);
+    sfi_char(nhfp, d_eshk->customer, parent, "customer", PL_NSIZ);
+    sfi_char(nhfp, d_eshk->shknam, parent, "shknam", PL_NSIZ);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "eshk", 1);
+}
+
+void
+sfi_fakecorridor(nhfp, d_fakecorridor, myparent, myname, cnt)
+NHFILE *nhfp;
+struct fakecorridor *d_fakecorridor;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "fakecorridor";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "fakecorridor", 1);
+
+    sfi_xchar(nhfp, &d_fakecorridor->fx, parent, "fx", 1);
+    sfi_xchar(nhfp, &d_fakecorridor->fy, parent, "fy", 1);
+    sfi_xchar(nhfp, &d_fakecorridor->ftyp, parent, "ftyp", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "fakecorridor", 1);
+}
+
+void
+sfi_fe(nhfp, d_fe, myparent, myname, cnt)
+NHFILE *nhfp;
+struct fe *d_fe;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "fe";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "fe", 1);
+
+    sfi_genericptr(nhfp, (genericptr_t) &d_fe->next, parent, "next", 1);
+    sfi_long(nhfp, &d_fe->timeout, parent, "timeout", 1);
+    sfi_ulong(nhfp, &d_fe->tid, parent, "tid", 1);
+    sfi_short(nhfp, &d_fe->kind, parent, "kind", 1);
+    sfi_short(nhfp, &d_fe->func_index, parent, "func_index", 1);
+    sfi_any(nhfp, &d_fe->arg, parent, "arg", 1);
+    bitfield = d_fe->needs_fixup;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "needs_fixup",  1);
+    d_fe->needs_fixup = bitfield;
+
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "fe", 1);
+}
+
+void
+sfi_flag(nhfp, d_flag, myparent, myname, cnt)
+NHFILE *nhfp;
+struct flag *d_flag;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "flag";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "flag", 1);
+
+    sfi_boolean(nhfp, &d_flag->acoustics, parent, "acoustics", 1);
+    sfi_boolean(nhfp, &d_flag->autodig, parent, "autodig", 1);
+    sfi_boolean(nhfp, &d_flag->autoquiver, parent, "autoquiver", 1);
+    sfi_boolean(nhfp, &d_flag->autoopen, parent, "autoopen", 1);
+    sfi_boolean(nhfp, &d_flag->beginner, parent, "beginner", 1);
+    sfi_boolean(nhfp, &d_flag->biff, parent, "biff", 1);
+    sfi_boolean(nhfp, &d_flag->bones, parent, "bones", 1);
+    sfi_boolean(nhfp, &d_flag->confirm, parent, "confirm", 1);
+    sfi_boolean(nhfp, &d_flag->dark_room, parent, "dark_room", 1);
+    sfi_boolean(nhfp, &d_flag->debug, parent, "debug", 1);
+    sfi_boolean(nhfp, &d_flag->end_own, parent, "end_own", 1);
+    sfi_boolean(nhfp, &d_flag->explore, parent, "explore", 1);
+    sfi_boolean(nhfp, &d_flag->female, parent, "female", 1);
+    sfi_boolean(nhfp, &d_flag->friday13, parent, "friday13", 1);
+    sfi_boolean(nhfp, &d_flag->help, parent, "help", 1);
+    sfi_boolean(nhfp, &d_flag->ignintr, parent, "ignintr", 1);
+    sfi_boolean(nhfp, &d_flag->ins_chkpt, parent, "ins_chkpt", 1);
+    sfi_boolean(nhfp, &d_flag->invlet_constant, parent, "invlet_constant", 1);
+    sfi_boolean(nhfp, &d_flag->legacy, parent, "legacy", 1);
+    sfi_boolean(nhfp, &d_flag->lit_corridor, parent, "lit_corridor", 1);
+    sfi_boolean(nhfp, &d_flag->nap, parent, "nap", 1);
+    sfi_boolean(nhfp, &d_flag->null, parent, "null", 1);
+    sfi_boolean(nhfp, &d_flag->p__obsolete, parent, "p__obsolete", 1);
+    sfi_boolean(nhfp, &d_flag->pickup, parent, "pickup", 1);
+    sfi_boolean(nhfp, &d_flag->pickup_thrown, parent, "pickup_thrown", 1);
+    sfi_boolean(nhfp, &d_flag->pushweapon, parent, "pushweapon", 1);
+    sfi_boolean(nhfp, &d_flag->rest_on_space, parent, "rest_on_space", 1);
+    sfi_boolean(nhfp, &d_flag->safe_dog, parent, "safe_dog", 1);
+    sfi_boolean(nhfp, &d_flag->showexp, parent, "showexp", 1);
+    sfi_boolean(nhfp, &d_flag->showscore, parent, "showscore", 1);
+    sfi_boolean(nhfp, &d_flag->silent, parent, "silent", 1);
+    sfi_xchar(nhfp, &d_flag->sortloot, parent, "sortloot", 1);
+    sfi_char(nhfp, &d_flag->sortloot, parent, "sortloot", 1);
+    sfi_boolean(nhfp, &d_flag->sortpack, parent, "sortpack", 1);
+    sfi_boolean(nhfp, &d_flag->sparkle, parent, "sparkle", 1);
+    sfi_boolean(nhfp, &d_flag->standout, parent, "standout", 1);
+    sfi_boolean(nhfp, &d_flag->time, parent, "time", 1);
+    sfi_boolean(nhfp, &d_flag->tombstone, parent, "tombstone", 1);
+    sfi_boolean(nhfp, &d_flag->verbose, parent, "verbose", 1);
+    sfi_int(nhfp, &d_flag->end_top, parent, "end_top", 1);
+    sfi_int(nhfp, &d_flag->end_around, parent, "end_around", 1);
+    sfi_unsigned(nhfp, &d_flag->moonphase, parent, "moonphase", 1);
+    sfi_ulong(nhfp, &d_flag->suppress_alert, parent, "suppress_alert", 1);
+    sfi_unsigned(nhfp, &d_flag->paranoia_bits, parent, "paranoia_bits", 1);
+    sfi_int(nhfp, &d_flag->pickup_burden, parent, "pickup_burden", 1);
+    sfi_int(nhfp, &d_flag->pile_limit, parent, "pile_limit", 1);
+    sfi_char(nhfp, d_flag->inv_order, parent, "inv_order", MAXOCLASSES);
+    sfi_char(nhfp, d_flag->pickup_types, parent, "pickup_types", MAXOCLASSES);
+    sfi_char(nhfp, d_flag->end_disclose, parent, "end_disclose", NUM_DISCLOSURE_OPTIONS + 1);
+    sfi_char(nhfp, &d_flag->menu_style, parent, "menu_style", 1);
+    sfi_boolean(nhfp, &d_flag->made_fruit, parent, "made_fruit", 1);
+    sfi_int(nhfp, &d_flag->initrole, parent, "initrole", 1);
+    sfi_int(nhfp, &d_flag->initrace, parent, "initrace", 1);
+    sfi_int(nhfp, &d_flag->initgend, parent, "initgend", 1);
+    sfi_int(nhfp, &d_flag->initalign, parent, "initalign", 1);
+    sfi_int(nhfp, &d_flag->randomall, parent, "randomall", 1);
+    sfi_int(nhfp, &d_flag->pantheon, parent, "pantheon", 1);
+    sfi_boolean(nhfp, &d_flag->lootabc, parent, "lootabc", 1);
+    sfi_boolean(nhfp, &d_flag->showrace, parent, "showrace", 1);
+    sfi_boolean(nhfp, &d_flag->travelcmd, parent, "travelcmd", 1);
+    sfi_int(nhfp, &d_flag->runmode, parent, "runmode", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "flag", 1);
+}
+
+void
+sfi_fruit(nhfp, d_fruit, myparent, myname, cnt)
+NHFILE *nhfp;
+struct fruit *d_fruit;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "fruit";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "fruit", 1);
+
+    sfi_char(nhfp, d_fruit->fname, parent, "fname", PL_FSIZ);
+    sfi_int(nhfp, &d_fruit->fid, parent, "fid", 1);
+    sfi_genericptr(nhfp, (genericptr_t) &d_fruit->nextf, parent, "nextf", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "fruit", 1);
+}
+
+void
+sfi_kinfo(nhfp, d_kinfo, myparent, myname, cnt)
+NHFILE *nhfp;
+struct kinfo *d_kinfo;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "kinfo";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "kinfo", 1);
+
+    sfi_genericptr(nhfp, (genericptr_t) &d_kinfo->next, parent, "next", 1);
+    sfi_int(nhfp, &d_kinfo->id, parent, "id", 1);
+    sfi_int(nhfp, &d_kinfo->format, parent, "format", 1);
+    sfi_char(nhfp, d_kinfo->name, parent, "name", BUFSZ);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "kinfo", 1);
+}
+
+void
+sfi_levelflags(nhfp, d_levelflags, myparent, myname, cnt)
+NHFILE *nhfp;
+struct levelflags *d_levelflags;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "levelflags";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "levelflags", 1);
+
+    sfi_uchar(nhfp, &d_levelflags->nfountains, parent, "nfountains", 1);
+    sfi_uchar(nhfp, &d_levelflags->nsinks, parent, "nsinks", 1);
+    bitfield = d_levelflags->has_shop;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "has_shop",  1);
+    d_levelflags->has_shop = bitfield;
+
+    bitfield = d_levelflags->has_vault;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "has_vault",  1);
+    d_levelflags->has_vault = bitfield;
+
+    bitfield = d_levelflags->has_zoo;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "has_zoo",  1);
+    d_levelflags->has_zoo = bitfield;
+
+    bitfield = d_levelflags->has_court;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "has_court",  1);
+    d_levelflags->has_court = bitfield;
+
+    bitfield = d_levelflags->has_morgue;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "has_morgue",  1);
+    d_levelflags->has_morgue = bitfield;
+
+    bitfield = d_levelflags->has_beehive;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "has_beehive",  1);
+    d_levelflags->has_beehive = bitfield;
+
+    bitfield = d_levelflags->has_barracks;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "has_barracks",  1);
+    d_levelflags->has_barracks = bitfield;
+
+    bitfield = d_levelflags->has_temple;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "has_temple",  1);
+    d_levelflags->has_temple = bitfield;
+
+    bitfield = d_levelflags->has_swamp;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "has_swamp",  1);
+    d_levelflags->has_swamp = bitfield;
+
+    bitfield = d_levelflags->noteleport;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "noteleport",  1);
+    d_levelflags->noteleport = bitfield;
+
+    bitfield = d_levelflags->hardfloor;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "hardfloor",  1);
+    d_levelflags->hardfloor = bitfield;
+
+    bitfield = d_levelflags->nommap;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "nommap",  1);
+    d_levelflags->nommap = bitfield;
+
+    bitfield = d_levelflags->hero_memory;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "hero_memory",  1);
+    d_levelflags->hero_memory = bitfield;
+
+    bitfield = d_levelflags->shortsighted;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "shortsighted",  1);
+    d_levelflags->shortsighted = bitfield;
+
+    bitfield = d_levelflags->graveyard;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "graveyard",  1);
+    d_levelflags->graveyard = bitfield;
+
+    bitfield = d_levelflags->sokoban_rules;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "sokoban_rules",  1);
+    d_levelflags->sokoban_rules = bitfield;
+
+    bitfield = d_levelflags->is_maze_lev;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "is_maze_lev",  1);
+    d_levelflags->is_maze_lev = bitfield;
+
+    bitfield = d_levelflags->is_cavernous_lev;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "is_cavernous_lev",  1);
+    d_levelflags->is_cavernous_lev = bitfield;
+
+    bitfield = d_levelflags->arboreal;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "arboreal",  1);
+    d_levelflags->arboreal = bitfield;
+
+    bitfield = d_levelflags->wizard_bones;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "wizard_bones",  1);
+    d_levelflags->wizard_bones = bitfield;
+
+    bitfield = d_levelflags->corrmaze;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "corrmaze",  1);
+    d_levelflags->corrmaze = bitfield;
+
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "levelflags", 1);
+}
+
+void
+sfi_linfo(nhfp, d_linfo, myparent, myname, cnt)
+NHFILE *nhfp;
+struct linfo *d_linfo;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "linfo";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "linfo", 1);
+
+    sfi_uchar(nhfp, &d_linfo->flags, parent, "flags", 1);
+#ifdef MFLOPPY
+    sfi_int(nhfp, &d_linfo->where, parent, "where", 1);
+    sfi_long(nhfp, &d_linfo->time, parent, "time", 1);
+    sfi_long(nhfp, &d_linfo->size, parent, "size", 1);
+#endif /*MFLOPPY*/
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "linfo", 1);
+}
+
+void
+sfi_ls_t(nhfp, d_ls_t, myparent, myname, cnt)
+NHFILE *nhfp;
+struct ls_t *d_ls_t;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "ls_t";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "ls_t", 1);
+
+    sfi_genericptr(nhfp, (genericptr_t) &d_ls_t->next, parent, "next", 1);
+    sfi_xchar(nhfp, &d_ls_t->x, parent, "x", 1);
+    sfi_xchar(nhfp, &d_ls_t->y, parent, "y", 1);
+    sfi_short(nhfp, &d_ls_t->range, parent, "range", 1);
+    sfi_short(nhfp, &d_ls_t->flags, parent, "flags", 1);
+    sfi_short(nhfp, &d_ls_t->type, parent, "type", 1);
+    sfi_any(nhfp, &d_ls_t->id, parent, "id", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "ls_t", 1);
+}
+
+void
+sfi_mapseen_feat(nhfp, d_mapseen_feat, myparent, myname, cnt)
+NHFILE *nhfp;
+struct mapseen_feat *d_mapseen_feat;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "mapseen_feat";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "mapseen_feat", 1);
+
+    bitfield = d_mapseen_feat->nfount;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "nfount",  2);
+    d_mapseen_feat->nfount = bitfield;
+
+    bitfield = d_mapseen_feat->nsink;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "nsink",  2);
+    d_mapseen_feat->nsink = bitfield;
+
+    bitfield = d_mapseen_feat->naltar;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "naltar",  2);
+    d_mapseen_feat->naltar = bitfield;
+
+    bitfield = d_mapseen_feat->nthrone;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "nthrone",  2);
+    d_mapseen_feat->nthrone = bitfield;
+
+    bitfield = d_mapseen_feat->ngrave;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "ngrave",  2);
+    d_mapseen_feat->ngrave = bitfield;
+
+    bitfield = d_mapseen_feat->ntree;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "ntree",  2);
+    d_mapseen_feat->ntree = bitfield;
+
+    bitfield = d_mapseen_feat->water;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "water",  2);
+    d_mapseen_feat->water = bitfield;
+
+    bitfield = d_mapseen_feat->lava;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "lava",  2);
+    d_mapseen_feat->lava = bitfield;
+
+    bitfield = d_mapseen_feat->ice;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "ice",  2);
+    d_mapseen_feat->ice = bitfield;
+
+    bitfield = d_mapseen_feat->nshop;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "nshop",  2);
+    d_mapseen_feat->nshop = bitfield;
+
+    bitfield = d_mapseen_feat->ntemple;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "ntemple",  2);
+    d_mapseen_feat->ntemple = bitfield;
+
+    bitfield = d_mapseen_feat->msalign;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "msalign",  2);
+    d_mapseen_feat->msalign = bitfield;
+
+    bitfield = d_mapseen_feat->shoptype;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "shoptype",  5);
+    d_mapseen_feat->shoptype = bitfield;
+
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "mapseen_feat", 1);
+}
+
+void
+sfi_mapseen_flags(nhfp, d_mapseen_flags, myparent, myname, cnt)
+NHFILE *nhfp;
+struct mapseen_flags *d_mapseen_flags;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "mapseen_flags";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "mapseen_flags", 1);
+
+    bitfield = d_mapseen_flags->unreachable;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "unreachable",  1);
+    d_mapseen_flags->unreachable = bitfield;
+
+    bitfield = d_mapseen_flags->forgot;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "forgot",  1);
+    d_mapseen_flags->forgot = bitfield;
+
+    bitfield = d_mapseen_flags->knownbones;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "knownbones",  1);
+    d_mapseen_flags->knownbones = bitfield;
+
+    bitfield = d_mapseen_flags->oracle;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "oracle",  1);
+    d_mapseen_flags->oracle = bitfield;
+
+    bitfield = d_mapseen_flags->sokosolved;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "sokosolved",  1);
+    d_mapseen_flags->sokosolved = bitfield;
+
+    bitfield = d_mapseen_flags->bigroom;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "bigroom",  1);
+    d_mapseen_flags->bigroom = bitfield;
+
+    bitfield = d_mapseen_flags->castle;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "castle",  1);
+    d_mapseen_flags->castle = bitfield;
+
+    bitfield = d_mapseen_flags->castletune;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "castletune",  1);
+    d_mapseen_flags->castletune = bitfield;
+
+    bitfield = d_mapseen_flags->valley;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "valley",  1);
+    d_mapseen_flags->valley = bitfield;
+
+    bitfield = d_mapseen_flags->msanctum;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "msanctum",  1);
+    d_mapseen_flags->msanctum = bitfield;
+
+    bitfield = d_mapseen_flags->ludios;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "ludios",  1);
+    d_mapseen_flags->ludios = bitfield;
+
+    bitfield = d_mapseen_flags->roguelevel;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "roguelevel",  1);
+    d_mapseen_flags->roguelevel = bitfield;
+
+    bitfield = d_mapseen_flags->quest_summons;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "quest_summons",  1);
+    d_mapseen_flags->quest_summons = bitfield;
+
+    bitfield = d_mapseen_flags->questing;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "questing",  1);
+    d_mapseen_flags->questing = bitfield;
+
+    bitfield = d_mapseen_flags->vibrating_square;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "vibrating_square",  1);
+    d_mapseen_flags->vibrating_square = bitfield;
+
+    bitfield = d_mapseen_flags->spare1;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "spare1",  1);
+    d_mapseen_flags->spare1 = bitfield;
+
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "mapseen_flags", 1);
+}
+
+void
+sfi_mapseen_rooms(nhfp, d_mapseen_rooms, myparent, myname, cnt)
+NHFILE *nhfp;
+struct mapseen_rooms *d_mapseen_rooms;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "mapseen_rooms";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "mapseen_rooms", 1);
+
+    bitfield = d_mapseen_rooms->seen;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "seen",  1);
+    d_mapseen_rooms->seen = bitfield;
+
+    bitfield = d_mapseen_rooms->untended;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "untended",  1);
+    d_mapseen_rooms->untended = bitfield;
+
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "mapseen_rooms", 1);
+}
+
+void
+sfi_mapseen(nhfp, d_mapseen, myparent, myname, cnt)
+NHFILE *nhfp;
+struct mapseen *d_mapseen;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "mapseen";
+    int i;
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "mapseen", 1);
+
+    sfi_genericptr(nhfp, (genericptr_t) &d_mapseen->next, parent, "next", 1);
+    sfi_branch(nhfp, d_mapseen->br, parent, "br", 1);
+    sfi_d_level(nhfp, &d_mapseen->lev, parent, "lev", 1);
+    sfi_mapseen_feat(nhfp, &d_mapseen->feat, parent, "feat", 1);
+    sfi_mapseen_flags(nhfp, &d_mapseen->flags, parent, "flags", 1);
+    sfi_char(nhfp, d_mapseen->custom, parent, "custom", 1);
+    sfi_unsigned(nhfp, &d_mapseen->custom_lth, parent, "custom_lth", 1);
+    for (i = 0; i < (MAXNROFROOMS + 1) * 2; ++i)
+        sfi_mapseen_rooms(nhfp, &d_mapseen->msrooms[i], parent, "msrooms", 1);
+    sfi_genericptr(nhfp, (genericptr_t) &d_mapseen->final_resting_place, parent, "final_resting_place", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "mapseen", 1);
+}
+
+void
+sfi_mextra(nhfp, d_mextra, myparent, myname, cnt)
+NHFILE *nhfp;
+struct mextra *d_mextra;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "mextra";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "mextra", 1);
+
+    sfi_char(nhfp, d_mextra->mname, parent, "mname", 1);
+    sfi_egd(nhfp, d_mextra->egd, parent, "egd", 1);
+    sfi_epri(nhfp, d_mextra->epri, parent, "epri", 1);
+    sfi_eshk(nhfp, d_mextra->eshk, parent, "eshk", 1);
+    sfi_emin(nhfp, d_mextra->emin, parent, "emin", 1);
+    sfi_edog(nhfp, d_mextra->edog, parent, "edog", 1);
+    sfi_int(nhfp, &d_mextra->mcorpsenm, parent, "mcorpsenm", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "mextra", 1);
+}
+
+void
+sfi_mkroom(nhfp, d_mkroom, myparent, myname, cnt)
+NHFILE *nhfp;
+struct mkroom *d_mkroom;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "mkroom";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "mkroom", 1);
+
+    sfi_schar(nhfp, &d_mkroom->lx, parent, "lx", 1);
+    sfi_schar(nhfp, &d_mkroom->hx, parent, "hx", 1);
+    sfi_schar(nhfp, &d_mkroom->ly, parent, "ly", 1);
+    sfi_schar(nhfp, &d_mkroom->hy, parent, "hy", 1);
+    sfi_schar(nhfp, &d_mkroom->rtype, parent, "rtype", 1);
+    sfi_schar(nhfp, &d_mkroom->orig_rtype, parent, "orig_rtype", 1);
+    sfi_schar(nhfp, &d_mkroom->rlit, parent, "rlit", 1);
+    sfi_schar(nhfp, &d_mkroom->needfill, parent, "needfill", 1);
+    sfi_schar(nhfp, &d_mkroom->needjoining, parent, "needjoining", 1);
+    sfi_schar(nhfp, &d_mkroom->doorct, parent, "doorct", 1);
+    sfi_schar(nhfp, &d_mkroom->fdoor, parent, "fdoor", 1);
+    sfi_schar(nhfp, &d_mkroom->nsubrooms, parent, "nsubrooms", 1);
+    sfi_boolean(nhfp, &d_mkroom->irregular, parent, "irregular", 1);
+    sfi_genericptr(nhfp, (genericptr_t) &d_mkroom->sbrooms[0], parent, "sbrooms", MAX_SUBROOMS);
+    sfi_genericptr(nhfp, (genericptr_t) &d_mkroom->resident, parent, "resident", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "mkroom", 1);
+}
+
+void
+sfi_monst(nhfp, d_monst, myparent, myname, cnt)
+NHFILE *nhfp;
+struct monst *d_monst;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "monst";
+    int i;
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "monst", 1);
+
+    sfi_genericptr(nhfp, (genericptr_t) &d_monst->nmon, parent, "nmon", 1);
+    sfi_genericptr(nhfp, (genericptr_t) &d_monst->data, parent, "data", 1);
+    sfi_unsigned(nhfp, &d_monst->m_id, parent, "m_id", 1);
+    sfi_short(nhfp, &d_monst->mnum, parent, "mnum", 1);
+    sfi_short(nhfp, &d_monst->cham, parent, "cham", 1);
+    sfi_short(nhfp, &d_monst->movement, parent, "movement", 1);
+    sfi_uchar(nhfp, &d_monst->m_lev, parent, "m_lev", 1);
+    sfi_aligntyp(nhfp, &d_monst->malign, parent, "malign", 1);
+    sfi_xchar(nhfp, &d_monst->mx, parent, "mx", 1);
+    sfi_xchar(nhfp, &d_monst->my, parent, "my", 1);
+    sfi_xchar(nhfp, &d_monst->mux, parent, "mux", 1);
+    sfi_xchar(nhfp, &d_monst->muy, parent, "muy", 1);
+    for (i = 0; i < MTSZ; ++i)
+        sfi_nhcoord(nhfp, &d_monst->mtrack[i], parent, "mtrack", 1);
+    sfi_int(nhfp, &d_monst->mhp, parent, "mhp", 1);
+    sfi_int(nhfp, &d_monst->mhpmax, parent, "mhpmax", 1);
+    sfi_unsigned(nhfp, &d_monst->mappearance, parent, "mappearance", 1);
+    sfi_uchar(nhfp, &d_monst->m_ap_type, parent, "m_ap_type", 1);
+    sfi_schar(nhfp, &d_monst->mtame, parent, "mtame", 1);
+    sfi_ushort(nhfp, &d_monst->mextrinsics, parent, "mextrinsics", 1);
+    sfi_int(nhfp, &d_monst->mspec_used, parent, "mspec_used", 1);
+    bitfield = d_monst->female;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "female",  1);
+    d_monst->female = bitfield;
+
+    bitfield = d_monst->minvis;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "minvis",  1);
+    d_monst->minvis = bitfield;
+
+    bitfield = d_monst->invis_blkd;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "invis_blkd",  1);
+    d_monst->invis_blkd = bitfield;
+
+    bitfield = d_monst->perminvis;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "perminvis",  1);
+    d_monst->perminvis = bitfield;
+
+    bitfield = d_monst->mcan;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "mcan",  1);
+    d_monst->mcan = bitfield;
+
+    bitfield = d_monst->mburied;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "mburied",  1);
+    d_monst->mburied = bitfield;
+
+    bitfield = d_monst->mundetected;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "mundetected",  1);
+    d_monst->mundetected = bitfield;
+
+    bitfield = d_monst->mcansee;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "mcansee",  1);
+    d_monst->mcansee = bitfield;
+
+    bitfield = d_monst->mspeed;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "mspeed",  2);
+    d_monst->mspeed = bitfield;
+
+    bitfield = d_monst->permspeed;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "permspeed",  2);
+    d_monst->permspeed = bitfield;
+
+    bitfield = d_monst->mrevived;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "mrevived",  1);
+    d_monst->mrevived = bitfield;
+
+    bitfield = d_monst->mcloned;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "mcloned",  1);
+    d_monst->mcloned = bitfield;
+
+    bitfield = d_monst->mavenge;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "mavenge",  1);
+    d_monst->mavenge = bitfield;
+
+    bitfield = d_monst->mflee;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "mflee",  1);
+    d_monst->mflee = bitfield;
+
+    bitfield = d_monst->mfleetim;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "mfleetim",  7);
+    d_monst->mfleetim = bitfield;
+
+    bitfield = d_monst->msleeping;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "msleeping",  1);
+    d_monst->msleeping = bitfield;
+
+    bitfield = d_monst->mblinded;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "mblinded",  7);
+    d_monst->mblinded = bitfield;
+
+    bitfield = d_monst->mstun;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "mstun",  1);
+    d_monst->mstun = bitfield;
+
+    bitfield = d_monst->mfrozen;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "mfrozen",  7);
+    d_monst->mfrozen = bitfield;
+
+    bitfield = d_monst->mcanmove;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "mcanmove",  1);
+    d_monst->mcanmove = bitfield;
+
+    bitfield = d_monst->mconf;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "mconf",  1);
+    d_monst->mconf = bitfield;
+
+    bitfield = d_monst->mpeaceful;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "mpeaceful",  1);
+    d_monst->mpeaceful = bitfield;
+
+    bitfield = d_monst->mtrapped;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "mtrapped",  1);
+    d_monst->mtrapped = bitfield;
+
+    bitfield = d_monst->mleashed;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "mleashed",  1);
+    d_monst->mleashed = bitfield;
+
+    bitfield = d_monst->isshk;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "isshk",  1);
+    d_monst->isshk = bitfield;
+
+    bitfield = d_monst->isminion;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "isminion",  1);
+    d_monst->isminion = bitfield;
+
+    bitfield = d_monst->isgd;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "isgd",  1);
+    d_monst->isgd = bitfield;
+
+    bitfield = d_monst->ispriest;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "ispriest",  1);
+    d_monst->ispriest = bitfield;
+
+    bitfield = d_monst->iswiz;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "iswiz",  1);
+    d_monst->iswiz = bitfield;
+
+    bitfield = d_monst->wormno;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "wormno",  5);
+    d_monst->wormno = bitfield;
+
+    bitfield = d_monst->mtemplit;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "mtemplit",  1);
+    d_monst->mtemplit = bitfield;
+
+    sfi_ulong(nhfp, &d_monst->mstrategy, parent, "mstrategy", 1);
+    sfi_long(nhfp, &d_monst->mtrapseen, parent, "mtrapseen", 1);
+    sfi_long(nhfp, &d_monst->mlstmv, parent, "mlstmv", 1);
+    sfi_long(nhfp, &d_monst->mspare1, parent, "mspare1", 1);
+    sfi_genericptr(nhfp, (genericptr_t) &d_monst->minvent, parent, "minvent", 1);
+    sfi_genericptr(nhfp, (genericptr_t) &d_monst->mw, parent, "mw", 1);
+    sfi_long(nhfp, &d_monst->misc_worn_check, parent, "misc_worn_check", 1);
+    sfi_xchar(nhfp, &d_monst->weapon_check, parent, "weapon_check", 1);
+    sfi_int(nhfp, &d_monst->meating, parent, "meating", 1);
+    sfi_genericptr(nhfp, (genericptr_t) &d_monst->mextra, parent, "mextra", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "monst", 1);
+}
+
+void
+sfi_mvitals(nhfp, d_mvitals, myparent, myname, cnt)
+NHFILE *nhfp;
+struct mvitals *d_mvitals;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "mvitals";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "mvitals", 1);
+
+    sfi_uchar(nhfp, &d_mvitals->born, parent, "born", 1);
+    sfi_uchar(nhfp, &d_mvitals->died, parent, "died", 1);
+    sfi_uchar(nhfp, &d_mvitals->mvflags, parent, "mvflags", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "mvitals", 1);
+}
+
+void
+sfi_nhcoord(nhfp, d_nhcoord, myparent, myname, cnt)
+NHFILE *nhfp;
+struct nhcoord *d_nhcoord;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "nhcoord";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "nhcoord", 1);
+
+    sfi_xchar(nhfp, &d_nhcoord->x, parent, "x", 1);
+    sfi_xchar(nhfp, &d_nhcoord->y, parent, "y", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "nhcoord", 1);
+}
+
+void
+sfi_nhrect(nhfp, d_nhrect, myparent, myname, cnt)
+NHFILE *nhfp;
+struct nhrect *d_nhrect;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "nhrect";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "nhrect", 1);
+
+    sfi_xchar(nhfp, &d_nhrect->lx, parent, "lx", 1);
+    sfi_xchar(nhfp, &d_nhrect->ly, parent, "ly", 1);
+    sfi_xchar(nhfp, &d_nhrect->hx, parent, "hx", 1);
+    sfi_xchar(nhfp, &d_nhrect->hy, parent, "hy", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "nhrect", 1);
+}
+
+void
+sfi_novel_tracking(nhfp, d_novel_tracking, myparent, myname, cnt)
+NHFILE *nhfp;
+struct novel_tracking *d_novel_tracking;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "novel_tracking";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "novel_tracking", 1);
+
+    sfi_unsigned(nhfp, &d_novel_tracking->id, parent, "id", 1);
+    sfi_int(nhfp, &d_novel_tracking->count, parent, "count", 1);
+    sfi_xchar(nhfp, d_novel_tracking->pasg, parent, "pasg", 30);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "novel_tracking", 1);
+}
+
+void
+sfi_obj(nhfp, d_obj, myparent, myname, cnt)
+NHFILE *nhfp;
+struct obj *d_obj;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "obj";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "obj", 1);
+
+    sfi_genericptr(nhfp, (genericptr_t) &d_obj->nobj, parent, "nobj", 1);
+    sfi_vptrs(nhfp, &d_obj->v, parent, "v", 1);
+    sfi_genericptr(nhfp, (genericptr_t) &d_obj->cobj, parent, "cobj", 1);
+    sfi_unsigned(nhfp, &d_obj->o_id, parent, "o_id", 1);
+    sfi_xchar(nhfp, &d_obj->ox, parent, "ox", 1);
+    sfi_xchar(nhfp, &d_obj->oy, parent, "oy", 1);
+    sfi_short(nhfp, &d_obj->otyp, parent, "otyp", 1);
+    sfi_unsigned(nhfp, &d_obj->owt, parent, "owt", 1);
+    sfi_long(nhfp, &d_obj->quan, parent, "quan", 1);
+    sfi_schar(nhfp, &d_obj->spe, parent, "spe", 1);
+    sfi_char(nhfp, &d_obj->oclass, parent, "oclass", 1);
+    sfi_char(nhfp, &d_obj->invlet, parent, "invlet", 1);
+    sfi_char(nhfp, &d_obj->oartifact, parent, "oartifact", 1);
+    sfi_xchar(nhfp, &d_obj->where, parent, "where", 1);
+    sfi_xchar(nhfp, &d_obj->timed, parent, "timed", 1);
+    bitfield = d_obj->cursed;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "cursed",  1);
+    d_obj->cursed = bitfield;
+
+    bitfield = d_obj->blessed;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "blessed",  1);
+    d_obj->blessed = bitfield;
+
+    bitfield = d_obj->unpaid;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "unpaid",  1);
+    d_obj->unpaid = bitfield;
+
+    bitfield = d_obj->no_charge;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "no_charge",  1);
+    d_obj->no_charge = bitfield;
+
+    bitfield = d_obj->known;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "known",  1);
+    d_obj->known = bitfield;
+
+    bitfield = d_obj->dknown;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "dknown",  1);
+    d_obj->dknown = bitfield;
+
+    bitfield = d_obj->bknown;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "bknown",  1);
+    d_obj->bknown = bitfield;
+
+    bitfield = d_obj->rknown;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "rknown",  1);
+    d_obj->rknown = bitfield;
+
+    bitfield = d_obj->oeroded;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "oeroded",  2);
+    d_obj->oeroded = bitfield;
+
+    bitfield = d_obj->oeroded2;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "oeroded2",  2);
+    d_obj->oeroded2 = bitfield;
+
+    bitfield = d_obj->oerodeproof;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "oerodeproof",  1);
+    d_obj->oerodeproof = bitfield;
+
+    bitfield = d_obj->olocked;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "olocked",  1);
+    d_obj->olocked = bitfield;
+
+    bitfield = d_obj->obroken;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "obroken",  1);
+    d_obj->obroken = bitfield;
+
+    bitfield = d_obj->otrapped;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "otrapped",  1);
+    d_obj->otrapped = bitfield;
+
+    bitfield = d_obj->recharged;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "recharged",  3);
+    d_obj->recharged = bitfield;
+
+    bitfield = d_obj->lamplit;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "lamplit",  1);
+    d_obj->lamplit = bitfield;
+
+    bitfield = d_obj->globby;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "globby",  1);
+    d_obj->globby = bitfield;
+
+    bitfield = d_obj->greased;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "greased",  1);
+    d_obj->greased = bitfield;
+
+    bitfield = d_obj->nomerge;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "nomerge",  1);
+    d_obj->nomerge = bitfield;
+
+    bitfield = d_obj->was_thrown;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "was_thrown",  1);
+    d_obj->was_thrown = bitfield;
+
+    bitfield = d_obj->in_use;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "in_use",  1);
+    d_obj->in_use = bitfield;
+
+    bitfield = d_obj->bypass;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "bypass",  1);
+    d_obj->bypass = bitfield;
+
+    bitfield = d_obj->cknown;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "cknown",  1);
+    d_obj->cknown = bitfield;
+
+    bitfield = d_obj->lknown;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "lknown",  1);
+    d_obj->lknown = bitfield;
+
+    sfi_int(nhfp, &d_obj->corpsenm, parent, "corpsenm", 1);
+    sfi_int(nhfp, &d_obj->usecount, parent, "usecount", 1);
+    sfi_unsigned(nhfp, &d_obj->oeaten, parent, "oeaten", 1);
+    sfi_long(nhfp, &d_obj->age, parent, "age", 1);
+    sfi_long(nhfp, &d_obj->owornmask, parent, "owornmask", 1);
+    sfi_genericptr(nhfp, (genericptr_t) &d_obj->oextra, parent, "oextra", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "obj", 1);
+}
+
+void
+sfi_objclass(nhfp, d_objclass, myparent, myname, cnt)
+NHFILE *nhfp;
+struct objclass *d_objclass;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "objclass";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "objclass", 1);
+
+    sfi_short(nhfp, &d_objclass->oc_name_idx, parent, "oc_name_idx", 1);
+    sfi_short(nhfp, &d_objclass->oc_descr_idx, parent, "oc_descr_idx", 1);
+    sfi_genericptr(nhfp, (genericptr_t) &d_objclass->oc_uname, parent, "oc_uname", 1);
+    bitfield = d_objclass->oc_name_known;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "oc_name_known",  1);
+    d_objclass->oc_name_known = bitfield;
+
+    bitfield = d_objclass->oc_merge;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "oc_merge",  1);
+    d_objclass->oc_merge = bitfield;
+
+    bitfield = d_objclass->oc_uses_known;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "oc_uses_known",  1);
+    d_objclass->oc_uses_known = bitfield;
+
+    bitfield = d_objclass->oc_pre_discovered;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "oc_pre_discovered",  1);
+    d_objclass->oc_pre_discovered = bitfield;
+
+    bitfield = d_objclass->oc_magic;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "oc_magic",  1);
+    d_objclass->oc_magic = bitfield;
+
+    bitfield = d_objclass->oc_charged;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "oc_charged",  1);
+    d_objclass->oc_charged = bitfield;
+
+    bitfield = d_objclass->oc_unique;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "oc_unique",  1);
+    d_objclass->oc_unique = bitfield;
+
+    bitfield = d_objclass->oc_nowish;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "oc_nowish",  1);
+    d_objclass->oc_nowish = bitfield;
+
+    bitfield = d_objclass->oc_big;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "oc_big",  1);
+    d_objclass->oc_big = bitfield;
+
+    bitfield = d_objclass->oc_tough;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "oc_tough",  1);
+    d_objclass->oc_tough = bitfield;
+
+    bitfield = d_objclass->oc_dir;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "oc_dir",  2);
+    d_objclass->oc_dir = bitfield;
+
+    bitfield = d_objclass->oc_material;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "oc_material",  5);
+    d_objclass->oc_material = bitfield;
+
+    sfi_schar(nhfp, &d_objclass->oc_subtyp, parent, "oc_subtyp", 1);
+    sfi_uchar(nhfp, &d_objclass->oc_oprop, parent, "oc_oprop", 1);
+    sfi_char(nhfp, &d_objclass->oc_class, parent, "oc_class", 1);
+    sfi_schar(nhfp, &d_objclass->oc_delay, parent, "oc_delay", 1);
+    sfi_uchar(nhfp, &d_objclass->oc_color, parent, "oc_color", 1);
+    sfi_short(nhfp, &d_objclass->oc_prob, parent, "oc_prob", 1);
+    sfi_ushort(nhfp, &d_objclass->oc_weight, parent, "oc_weight", 1);
+    sfi_short(nhfp, &d_objclass->oc_cost, parent, "oc_cost", 1);
+    sfi_schar(nhfp, &d_objclass->oc_wsdam, parent, "oc_wsdam", 1);
+    sfi_schar(nhfp, &d_objclass->oc_wldam, parent, "oc_wldam", 1);
+    sfi_schar(nhfp, &d_objclass->oc_oc1, parent, "oc_oc1", 1);
+    sfi_schar(nhfp, &d_objclass->oc_oc2, parent, "oc_oc2", 1);
+    sfi_ushort(nhfp, &d_objclass->oc_nutrition, parent, "oc_nutrition", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "objclass", 1);
+}
+
+void
+sfi_obj_split(nhfp, d_obj_split, myparent, myname, cnt)
+NHFILE *nhfp;
+struct obj_split *d_obj_split;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "obj_split";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "obj_split", 1);
+
+    sfi_unsigned(nhfp, &d_obj_split->parent_oid, parent, "parent_oid", 1);
+    sfi_unsigned(nhfp, &d_obj_split->child_oid, parent, "child_oid", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "obj_split", 1);
+}
+
+void
+sfi_oextra(nhfp, d_oextra, myparent, myname, cnt)
+NHFILE *nhfp;
+struct oextra *d_oextra;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "oextra";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "oextra", 1);
+
+    sfi_char(nhfp, d_oextra->oname, parent, "oname", 1);
+    sfi_genericptr(nhfp, (genericptr_t) &d_oextra->omonst, parent, "omonst", 1);
+    sfi_unsigned(nhfp, d_oextra->omid, parent, "omid", 1);
+    sfi_long(nhfp, d_oextra->olong, parent, "olong", 1);
+    sfi_char(nhfp, d_oextra->omailcmd, parent, "omailcmd", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "oextra", 1);
+}
+
+void
+sfi_polearm_info(nhfp, d_polearm_info, myparent, myname, cnt)
+NHFILE *nhfp;
+struct polearm_info *d_polearm_info;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "polearm_info";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "polearm_info", 1);
+
+    sfi_genericptr(nhfp, (genericptr_t) &d_polearm_info->hitmon, parent, "hitmon", 1);
+    sfi_unsigned(nhfp, &d_polearm_info->m_id, parent, "m_id", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "polearm_info", 1);
+}
+
+void
+sfi_prop(nhfp, d_prop, myparent, myname, cnt)
+NHFILE *nhfp;
+struct prop *d_prop;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "prop";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "prop", 1);
+
+    sfi_long(nhfp, &d_prop->extrinsic, parent, "extrinsic", 1);
+    sfi_long(nhfp, &d_prop->blocked, parent, "blocked", 1);
+    sfi_long(nhfp, &d_prop->intrinsic, parent, "intrinsic", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "prop", 1);
+}
+
+void
+sfi_q_score(nhfp, d_q_score, myparent, myname, cnt)
+NHFILE *nhfp;
+struct q_score *d_q_score;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "q_score";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "q_score", 1);
+
+    bitfield = d_q_score->first_start;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "first_start",  1);
+    d_q_score->first_start = bitfield;
+
+    bitfield = d_q_score->met_leader;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "met_leader",  1);
+    d_q_score->met_leader = bitfield;
+
+    bitfield = d_q_score->not_ready;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "not_ready",  3);
+    d_q_score->not_ready = bitfield;
+
+    bitfield = d_q_score->pissed_off;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "pissed_off",  1);
+    d_q_score->pissed_off = bitfield;
+
+    bitfield = d_q_score->got_quest;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "got_quest",  1);
+    d_q_score->got_quest = bitfield;
+
+    bitfield = d_q_score->first_locate;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "first_locate",  1);
+    d_q_score->first_locate = bitfield;
+
+    bitfield = d_q_score->met_intermed;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "met_intermed",  1);
+    d_q_score->met_intermed = bitfield;
+
+    bitfield = d_q_score->got_final;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "got_final",  1);
+    d_q_score->got_final = bitfield;
+
+    bitfield = d_q_score->made_goal;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "made_goal",  3);
+    d_q_score->made_goal = bitfield;
+
+    bitfield = d_q_score->met_nemesis;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "met_nemesis",  1);
+    d_q_score->met_nemesis = bitfield;
+
+    bitfield = d_q_score->killed_nemesis;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "killed_nemesis",  1);
+    d_q_score->killed_nemesis = bitfield;
+
+    bitfield = d_q_score->in_battle;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "in_battle",  1);
+    d_q_score->in_battle = bitfield;
+
+    bitfield = d_q_score->cheater;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "cheater",  1);
+    d_q_score->cheater = bitfield;
+
+    bitfield = d_q_score->touched_artifact;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "touched_artifact",  1);
+    d_q_score->touched_artifact = bitfield;
+
+    bitfield = d_q_score->offered_artifact;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "offered_artifact",  1);
+    d_q_score->offered_artifact = bitfield;
+
+    bitfield = d_q_score->got_thanks;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "got_thanks",  1);
+    d_q_score->got_thanks = bitfield;
+
+    bitfield = d_q_score->ldrgend;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "ldrgend",  2);
+    d_q_score->ldrgend = bitfield;
+
+    bitfield = d_q_score->nemgend;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "nemgend",  2);
+    d_q_score->nemgend = bitfield;
+
+    bitfield = d_q_score->godgend;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "godgend",  2);
+    d_q_score->godgend = bitfield;
+
+    bitfield = d_q_score->leader_is_dead;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "leader_is_dead",  1);
+    d_q_score->leader_is_dead = bitfield;
+
+    sfi_unsigned(nhfp, &d_q_score->leader_m_id, parent, "leader_m_id", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "q_score", 1);
+}
+
+void
+sfi_rm(nhfp, d_rm, myparent, myname, cnt)
+NHFILE *nhfp;
+struct rm *d_rm;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "rm";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "rm", 1);
+
+    sfi_int(nhfp, &d_rm->glyph, parent, "glyph", 1);
+    sfi_schar(nhfp, &d_rm->typ, parent, "typ", 1);
+    sfi_uchar(nhfp, &d_rm->seenv, parent, "seenv", 1);
+    bitfield = d_rm->flags;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "flags",  5);
+    d_rm->flags = bitfield;
+
+    bitfield = d_rm->horizontal;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "horizontal",  1);
+    d_rm->horizontal = bitfield;
+
+    bitfield = d_rm->lit;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "lit",  1);
+    d_rm->lit = bitfield;
+
+    bitfield = d_rm->waslit;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "waslit",  1);
+    d_rm->waslit = bitfield;
+
+    bitfield = d_rm->roomno;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "roomno",  6);
+    d_rm->roomno = bitfield;
+
+    bitfield = d_rm->edge;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "edge",  1);
+    d_rm->edge = bitfield;
+
+    bitfield = d_rm->candig;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "candig",  1);
+    d_rm->candig = bitfield;
+
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "rm", 1);
+}
+
+void
+sfi_s_level(nhfp, d_s_level, myparent, myname, cnt)
+NHFILE *nhfp;
+struct s_level *d_s_level;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "s_level";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "s_level", 1);
+
+    sfi_genericptr(nhfp, (genericptr_t) &d_s_level->next, parent, "next", 1);
+    sfi_d_level(nhfp, &d_s_level->dlevel, parent, "dlevel", 1);
+    sfi_char(nhfp, d_s_level->proto, parent, "proto", 15);
+    sfi_char(nhfp, &d_s_level->boneid, parent, "boneid", 1);
+    sfi_uchar(nhfp, &d_s_level->rndlevs, parent, "rndlevs", 1);
+    sfi_d_flags(nhfp, &d_s_level->flags, parent, "flags", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "s_level", 1);
+}
+
+void
+sfi_savefile_info(nhfp, d_savefile_info, myparent, myname, cnt)
+NHFILE *nhfp;
+struct savefile_info *d_savefile_info;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "savefile_info";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "savefile_info", 1);
+
+    sfi_ulong(nhfp, &d_savefile_info->sfi1, parent, "sfi1", 1);
+    sfi_ulong(nhfp, &d_savefile_info->sfi2, parent, "sfi2", 1);
+    sfi_ulong(nhfp, &d_savefile_info->sfi3, parent, "sfi3", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "savefile_info", 1);
+}
+
+void
+sfi_skills(nhfp, d_skills, myparent, myname, cnt)
+NHFILE *nhfp;
+struct skills *d_skills;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "skills";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "skills", 1);
+
+    sfi_xchar(nhfp, &d_skills->skill, parent, "skill", 1);
+    sfi_xchar(nhfp, &d_skills->max_skill, parent, "max_skill", 1);
+    sfi_ushort(nhfp, &d_skills->advance, parent, "advance", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "skills", 1);
+}
+
+void
+sfi_spell(nhfp, d_spell, myparent, myname, cnt)
+NHFILE *nhfp;
+struct spell *d_spell;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "spell";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "spell", 1);
+
+    sfi_short(nhfp, &d_spell->sp_id, parent, "sp_id", 1);
+    sfi_xchar(nhfp, &d_spell->sp_lev, parent, "sp_lev", 1);
+    sfi_int(nhfp, &d_spell->sp_know, parent, "sp_know", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "spell", 1);
+}
+
+void
+sfi_stairway(nhfp, d_stairway, myparent, myname, cnt)
+NHFILE *nhfp;
+struct stairway *d_stairway;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "stairway";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "stairway", 1);
+
+    sfi_xchar(nhfp, &d_stairway->sx, parent, "sx", 1);
+    sfi_xchar(nhfp, &d_stairway->sy, parent, "sy", 1);
+    sfi_d_level(nhfp, &d_stairway->tolev, parent, "tolev", 1);
+    sfi_char(nhfp, &d_stairway->up, parent, "up", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "stairway", 1);
+}
+
+void
+sfi_takeoff_info(nhfp, d_takeoff_info, myparent, myname, cnt)
+NHFILE *nhfp;
+struct takeoff_info *d_takeoff_info;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "takeoff_info";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "takeoff_info", 1);
+
+    sfi_long(nhfp, &d_takeoff_info->mask, parent, "mask", 1);
+    sfi_long(nhfp, &d_takeoff_info->what, parent, "what", 1);
+    sfi_int(nhfp, &d_takeoff_info->delay, parent, "delay", 1);
+    sfi_boolean(nhfp, &d_takeoff_info->cancelled_don, parent, "cancelled_don", 1);
+    sfi_char(nhfp, d_takeoff_info->disrobing, parent, "disrobing", CONTEXTVERBSZ + 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "takeoff_info", 1);
+}
+
+void
+sfi_tin_info(nhfp, d_tin_info, myparent, myname, cnt)
+NHFILE *nhfp;
+struct tin_info *d_tin_info;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "tin_info";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "tin_info", 1);
+
+    sfi_genericptr(nhfp, (genericptr_t) &d_tin_info->tin, parent, "tin", 1);
+    sfi_unsigned(nhfp, &d_tin_info->o_id, parent, "o_id", 1);
+    sfi_int(nhfp, &d_tin_info->usedtime, parent, "usedtime", 1);
+    sfi_int(nhfp, &d_tin_info->reqtime, parent, "reqtime", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "tin_info", 1);
+}
+
+void
+sfi_trap(nhfp, d_trap, myparent, myname, cnt)
+NHFILE *nhfp;
+struct trap *d_trap;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "trap";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "trap", 1);
+
+    sfi_genericptr(nhfp, (genericptr_t) &d_trap->ntrap, parent, "ntrap", 1);
+    sfi_xchar(nhfp, &d_trap->tx, parent, "tx", 1);
+    sfi_xchar(nhfp, &d_trap->ty, parent, "ty", 1);
+    sfi_d_level(nhfp, &d_trap->dst, parent, "dst", 1);
+    sfi_nhcoord(nhfp, &d_trap->launch, parent, "launch", 1);
+    bitfield = d_trap->ttyp;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "ttyp",  5);
+    d_trap->ttyp = bitfield;
+
+    bitfield = d_trap->tseen;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "tseen",  1);
+    d_trap->tseen = bitfield;
+
+    bitfield = d_trap->once;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "once",  1);
+    d_trap->once = bitfield;
+
+    bitfield = d_trap->madeby_u;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "madeby_u",  1);
+    d_trap->madeby_u = bitfield;
+
+    sfi_vlaunchinfo(nhfp, &d_trap->vl, parent, "vl", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "trap", 1);
+}
+
+void
+sfi_tribute_info(nhfp, d_tribute_info, myparent, myname, cnt)
+NHFILE *nhfp;
+struct tribute_info *d_tribute_info;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "tribute_info";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "tribute_info", 1);
+
+    sfi_size_t(nhfp, &d_tribute_info->tributesz, parent, "tributesz", 1);
+    sfi_boolean(nhfp, &d_tribute_info->enabled, parent, "enabled", 1);
+    bitfield = d_tribute_info->bookstock;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "bookstock",  1);
+    d_tribute_info->bookstock = bitfield;
+
+    bitfield = d_tribute_info->Deathnotice;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "Deathnotice", 1);
+    d_tribute_info->Deathnotice = bitfield;
+
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "tribute_info", 1);
+}
+
+void
+sfi_u_achieve(nhfp, d_u_achieve, myparent, myname, cnt)
+NHFILE *nhfp;
+struct u_achieve *d_u_achieve;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "u_achieve";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "u_achieve", 1);
+
+    bitfield = d_u_achieve->amulet;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "amulet",  1);
+    d_u_achieve->amulet = bitfield;
+
+    bitfield = d_u_achieve->bell;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "bell",  1);
+    d_u_achieve->bell = bitfield;
+
+    bitfield = d_u_achieve->book;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "book",  1);
+    d_u_achieve->book = bitfield;
+
+    bitfield = d_u_achieve->menorah;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "menorah",  1);
+    d_u_achieve->menorah = bitfield;
+
+    bitfield = d_u_achieve->enter_gehennom;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "enter_gehennom", 1);
+    d_u_achieve->enter_gehennom = bitfield;
+
+    bitfield = d_u_achieve->ascended;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "ascended",  1);
+    d_u_achieve->ascended = bitfield;
+
+    bitfield = d_u_achieve->mines_luckstone;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "mines_luckstone",  1);
+    d_u_achieve->mines_luckstone = bitfield;
+
+    bitfield = d_u_achieve->finish_sokoban;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "finish_sokoban",  1);
+    d_u_achieve->finish_sokoban = bitfield;
+
+    bitfield = d_u_achieve->killed_medusa;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "killed_medusa",  1);
+    d_u_achieve->killed_medusa = bitfield;
+
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "u_achieve", 1);
+}
+
+void
+sfi_u_conduct(nhfp, d_u_conduct, myparent, myname, cnt)
+NHFILE *nhfp;
+struct u_conduct *d_u_conduct;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "u_conduct";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "u_conduct", 1);
+
+    sfi_long(nhfp, &d_u_conduct->unvegetarian, parent, "unvegetarian", 1);
+    sfi_long(nhfp, &d_u_conduct->unvegan, parent, "unvegan", 1);
+    sfi_long(nhfp, &d_u_conduct->food, parent, "food", 1);
+    sfi_long(nhfp, &d_u_conduct->gnostic, parent, "gnostic", 1);
+    sfi_long(nhfp, &d_u_conduct->weaphit, parent, "weaphit", 1);
+    sfi_long(nhfp, &d_u_conduct->killer, parent, "killer", 1);
+    sfi_long(nhfp, &d_u_conduct->literate, parent, "literate", 1);
+    sfi_long(nhfp, &d_u_conduct->polypiles, parent, "polypiles", 1);
+    sfi_long(nhfp, &d_u_conduct->polyselfs, parent, "polyselfs", 1);
+    sfi_long(nhfp, &d_u_conduct->wishes, parent, "wishes", 1);
+    sfi_long(nhfp, &d_u_conduct->wisharti, parent, "wisharti", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "u_conduct", 1);
+}
+
+void
+sfi_u_event(nhfp, d_u_event, myparent, myname, cnt)
+NHFILE *nhfp;
+struct u_event *d_u_event;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "u_event";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "u_event", 1);
+
+    bitfield = d_u_event->minor_oracle;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "minor_oracle",  1);
+    d_u_event->minor_oracle = bitfield;
+
+    bitfield = d_u_event->major_oracle;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "major_oracle",  1);
+    d_u_event->major_oracle = bitfield;
+
+    bitfield = d_u_event->read_tribute;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "read_tribute",  1);
+    d_u_event->read_tribute = bitfield;
+
+    bitfield = d_u_event->qcalled;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "qcalled",  1);
+    d_u_event->qcalled = bitfield;
+
+    bitfield = d_u_event->qexpelled;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "qexpelled",  1);
+    d_u_event->qexpelled = bitfield;
+
+    bitfield = d_u_event->qcompleted;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "qcompleted",  1);
+    d_u_event->qcompleted = bitfield;
+
+    bitfield = d_u_event->uheard_tune;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "uheard_tune",  2);
+    d_u_event->uheard_tune = bitfield;
+
+    bitfield = d_u_event->uopened_dbridge;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "uopened_dbridge",  1);
+    d_u_event->uopened_dbridge = bitfield;
+
+    bitfield = d_u_event->invoked;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "invoked",  1);
+    d_u_event->invoked = bitfield;
+
+    bitfield = d_u_event->gehennom_entered;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "gehennom_entered",  1);
+    d_u_event->gehennom_entered = bitfield;
+
+    bitfield = d_u_event->uhand_of_elbereth;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "uhand_of_elbereth",  2);
+    d_u_event->uhand_of_elbereth = bitfield;
+
+    bitfield = d_u_event->udemigod;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "udemigod",  1);
+    d_u_event->udemigod = bitfield;
+
+    bitfield = d_u_event->uvibrated;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "uvibrated",  1);
+    d_u_event->uvibrated = bitfield;
+
+    bitfield = d_u_event->ascended;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "ascended",  1);
+    d_u_event->ascended = bitfield;
+
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "u_event", 1);
+}
+
+void
+sfi_u_have(nhfp, d_u_have, myparent, myname, cnt)
+NHFILE *nhfp;
+struct u_have *d_u_have;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "u_have";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "u_have", 1);
+
+    bitfield = d_u_have->amulet;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "amulet",  1);
+    d_u_have->amulet = bitfield;
+
+    bitfield = d_u_have->bell;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "bell",  1);
+    d_u_have->bell = bitfield;
+
+    bitfield = d_u_have->book;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "book",  1);
+    d_u_have->book = bitfield;
+
+    bitfield = d_u_have->menorah;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "menorah",  1);
+    d_u_have->menorah = bitfield;
+
+    bitfield = d_u_have->questart;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "questart",  1);
+    d_u_have->questart = bitfield;
+
+    bitfield = d_u_have->unused;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "unused",  3);
+    d_u_have->unused = bitfield;
+
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "u_have", 1);
+}
+
+void
+sfi_u_realtime(nhfp, d_u_realtime, myparent, myname, cnt)
+NHFILE *nhfp;
+struct u_realtime *d_u_realtime;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "u_realtime";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "u_realtime", 1);
+
+    sfi_long(nhfp, &d_u_realtime->realtime, parent, "realtime", 1);
+    sfi_time_t(nhfp, &d_u_realtime->start_timing, parent, "start_timing", 1);
+    sfi_time_t(nhfp, &d_u_realtime->finish_time, parent, "finish_time", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "u_realtime", 1);
+}
+
+void
+sfi_u_roleplay(nhfp, d_u_roleplay, myparent, myname, cnt)
+NHFILE *nhfp;
+struct u_roleplay *d_u_roleplay;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "u_roleplay";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "u_roleplay", 1);
+
+    sfi_boolean(nhfp, &d_u_roleplay->blind, parent, "blind", 1);
+    sfi_boolean(nhfp, &d_u_roleplay->nudist, parent, "nudist", 1);
+    sfi_long(nhfp, &d_u_roleplay->numbones, parent, "numbones", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "u_roleplay", 1);
+}
+
+void
+sfi_version_info(nhfp, d_version_info, myparent, myname, cnt)
+NHFILE *nhfp;
+struct version_info *d_version_info;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "version_info";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "version_info", 1);
+
+    sfi_ulong(nhfp, &d_version_info->incarnation, parent, "incarnation", 1);
+    sfi_ulong(nhfp, &d_version_info->feature_set, parent, "feature_set", 1);
+    sfi_ulong(nhfp, &d_version_info->entity_count, parent, "entity_count", 1);
+    sfi_ulong(nhfp, &d_version_info->struct_sizes1, parent, "struct_sizes1", 1);
+    sfi_ulong(nhfp, &d_version_info->struct_sizes2, parent, "struct_sizes2", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "version_info", 1);
+}
+
+void
+sfi_victual_info(nhfp, d_victual_info, myparent, myname, cnt)
+NHFILE *nhfp;
+struct victual_info *d_victual_info;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "victual_info";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "victual_info", 1);
+
+    sfi_genericptr(nhfp, (genericptr_t) &d_victual_info->piece, parent, "piece", 1);
+    sfi_unsigned(nhfp, &d_victual_info->o_id, parent, "o_id", 1);
+    sfi_int(nhfp, &d_victual_info->usedtime, parent, "usedtime", 1);
+    sfi_int(nhfp, &d_victual_info->reqtime, parent, "reqtime", 1);
+    sfi_int(nhfp, &d_victual_info->nmod, parent, "nmod", 1);
+    bitfield = d_victual_info->canchoke;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "canchoke",  1);
+    d_victual_info->canchoke = bitfield;
+
+    bitfield = d_victual_info->fullwarn;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "fullwarn",  1);
+    d_victual_info->fullwarn = bitfield;
+
+    bitfield = d_victual_info->eating;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "eating",  1);
+    d_victual_info->eating = bitfield;
+
+    bitfield = d_victual_info->doreset;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "doreset",  1);
+    d_victual_info->doreset = bitfield;
+
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "victual_info", 1);
+}
+
+void
+sfi_vlaunchinfo(nhfp, d_vlaunchinfo, myparent, myname, cnt)
+NHFILE *nhfp;
+union vlaunchinfo *d_vlaunchinfo;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "vlaunchinfo";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "vlaunchinfo", 1);
+
+    sfi_short(nhfp, &d_vlaunchinfo->v_launch_otyp, parent, "v_launch_otyp", 1);
+    sfi_nhcoord(nhfp, &d_vlaunchinfo->v_launch2, parent, "v_launch2", 1);
+    sfi_uchar(nhfp, &d_vlaunchinfo->v_conjoined, parent, "v_conjoined", 1);
+    sfi_short(nhfp, &d_vlaunchinfo->v_tnote, parent, "v_tnote", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "vlaunchinfo", 1);
+}
+
+void
+sfi_vptrs(nhfp, d_vptrs, myparent, myname, cnt)
+NHFILE *nhfp;
+union vptrs *d_vptrs;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "vptrs";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "vptrs", 1);
+
+    sfi_genericptr(nhfp, (genericptr_t) &d_vptrs->v_nexthere, parent, "v_nexthere", 1);
+    sfi_genericptr(nhfp, (genericptr_t) &d_vptrs->v_ocontainer, parent, "v_ocontainer", 1);
+    sfi_genericptr(nhfp, (genericptr_t) &d_vptrs->v_ocarry, parent, "v_ocarry", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "vptrs", 1);
+}
+
+void
+sfi_warntype_info(nhfp, d_warntype_info, myparent, myname, cnt)
+NHFILE *nhfp;
+struct warntype_info *d_warntype_info;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "warntype_info";
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "warntype_info", 1);
+
+    sfi_ulong(nhfp, &d_warntype_info->obj, parent, "obj", 1);
+    sfi_ulong(nhfp, &d_warntype_info->polyd, parent, "polyd", 1);
+    sfi_genericptr(nhfp, (genericptr_t) &d_warntype_info->species, parent, "species", 1);
+    sfi_short(nhfp, &d_warntype_info->speciesidx, parent, "speciesidx", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "warntype_info", 1);
+}
+
+void
+sfi_you(nhfp, d_you, myparent, myname, cnt)
+NHFILE *nhfp;
+struct you *d_you;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "you";
+    int i;
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "start", "you", 1);
+
+    sfi_xchar(nhfp, &d_you->ux, parent, "ux", 1);
+    sfi_xchar(nhfp, &d_you->uy, parent, "uy", 1);
+    sfi_schar(nhfp, &d_you->dx, parent, "dx", 1);
+    sfi_schar(nhfp, &d_you->dy, parent, "dy", 1);
+    sfi_schar(nhfp, &d_you->dz, parent, "dz", 1);
+    sfi_schar(nhfp, &d_you->di, parent, "di", 1);
+    sfi_xchar(nhfp, &d_you->tx, parent, "tx", 1);
+    sfi_xchar(nhfp, &d_you->ty, parent, "ty", 1);
+    sfi_xchar(nhfp, &d_you->ux0, parent, "ux0", 1);
+    sfi_xchar(nhfp, &d_you->uy0, parent, "uy0", 1);
+    sfi_d_level(nhfp, &d_you->uz, parent, "uz", 1);
+    sfi_d_level(nhfp, &d_you->uz0, parent, "uz0", 1);
+    sfi_d_level(nhfp, &d_you->utolev, parent, "utolev", 1);
+    sfi_uchar(nhfp, &d_you->utotype, parent, "utotype", 1);
+    sfi_boolean(nhfp, &d_you->umoved, parent, "umoved", 1);
+    sfi_int(nhfp, &d_you->last_str_turn, parent, "last_str_turn", 1);
+    sfi_int(nhfp, &d_you->ulevel, parent, "ulevel", 1);
+    sfi_int(nhfp, &d_you->ulevelmax, parent, "ulevelmax", 1);
+    sfi_unsigned(nhfp, &d_you->utrap, parent, "utrap", 1);
+    sfi_unsigned(nhfp, &d_you->utraptype, parent, "utraptype", 1);
+    sfi_char(nhfp, d_you->urooms, parent, "urooms", 5);
+    sfi_char(nhfp, d_you->urooms0, parent, "urooms0", 5);
+    sfi_char(nhfp, d_you->uentered, parent, "uentered", 5);
+    sfi_char(nhfp, d_you->ushops, parent, "ushops", 5);
+    sfi_char(nhfp, d_you->ushops0, parent, "ushops0", 5);
+    sfi_char(nhfp, d_you->ushops_entered, parent, "ushops_entered", 5);
+    sfi_char(nhfp, d_you->ushops_left, parent, "ushops_left", 5);
+    sfi_int(nhfp, &d_you->uhunger, parent, "uhunger", 1);
+    sfi_unsigned(nhfp, &d_you->uhs, parent, "uhs", 1);
+    sfi_prop(nhfp, d_you->uprops, parent, "uprops", LAST_PROP + 1);
+    sfi_unsigned(nhfp, &d_you->umconf, parent, "umconf", 1);
+    bitfield = d_you->usick_type;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "usick_type",  2);
+    d_you->usick_type = bitfield;
+
+    sfi_int(nhfp, &d_you->nv_range, parent, "nv_range", 1);
+    sfi_int(nhfp, &d_you->xray_range, parent, "xray_range", 1);
+    sfi_int(nhfp, &d_you->bglyph, parent, "bglyph", 1);
+    sfi_int(nhfp, &d_you->cglyph, parent, "cglyph", 1);
+    sfi_int(nhfp, &d_you->bc_order, parent, "bc_order", 1);
+    sfi_int(nhfp, &d_you->bc_felt, parent, "bc_felt", 1);
+    sfi_int(nhfp, &d_you->umonster, parent, "umonster", 1);
+    sfi_int(nhfp, &d_you->umonnum, parent, "umonnum", 1);
+    sfi_int(nhfp, &d_you->mh, parent, "mh", 1);
+    sfi_int(nhfp, &d_you->mhmax, parent, "mhmax", 1);
+    sfi_int(nhfp, &d_you->mtimedone, parent, "mtimedone", 1);
+    sfi_attribs(nhfp, &d_you->macurr, parent, "macurr", 1);
+    sfi_attribs(nhfp, &d_you->mamax, parent, "mamax", 1);
+    sfi_int(nhfp, &d_you->ulycn, parent, "ulycn", 1);
+    sfi_unsigned(nhfp, &d_you->ucreamed, parent, "ucreamed", 1);
+    sfi_unsigned(nhfp, &d_you->uswldtim, parent, "uswldtim", 1);
+    bitfield = d_you->uswallow;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "uswallow",  1);
+    d_you->uswallow = bitfield;
+
+    bitfield = d_you->uinwater;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "uinwater",  1);
+    d_you->uinwater = bitfield;
+
+    bitfield = d_you->uundetected;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "uundetected",  1);
+    d_you->uundetected = bitfield;
+
+    bitfield = d_you->mfemale;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "mfemale",  1);
+    d_you->mfemale = bitfield;
+
+    bitfield = d_you->uinvulnerable;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "uinvulnerable",  1);
+    d_you->uinvulnerable = bitfield;
+
+    bitfield = d_you->uburied;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "uburied",  1);
+    d_you->uburied = bitfield;
+
+    bitfield = d_you->uedibility;       /* set it to current value for testing */
+    sfi_bitfield(nhfp, &bitfield, parent, "uedibility",  1);
+    d_you->uedibility = bitfield;
+
+    sfi_unsigned(nhfp, &d_you->udg_cnt, parent, "udg_cnt", 1);
+    sfi_u_achieve(nhfp, &d_you->uachieve, parent, "uachieve", 1);
+    sfi_u_event(nhfp, &d_you->uevent, parent, "uevent", 1);
+    sfi_u_have(nhfp, &d_you->uhave, parent, "uhave", 1);
+    sfi_u_conduct(nhfp, &d_you->uconduct, parent, "uconduct", 1);
+    sfi_u_roleplay(nhfp, &d_you->uroleplay, parent, "uroleplay", 1);
+    sfi_attribs(nhfp, &d_you->acurr, parent, "acurr", 1);
+    sfi_attribs(nhfp, &d_you->aexe, parent, "aexe", 1);
+    sfi_attribs(nhfp, &d_you->abon, parent, "abon", 1);
+    sfi_attribs(nhfp, &d_you->amax, parent, "amax", 1);
+    sfi_attribs(nhfp, &d_you->atemp, parent, "atemp", 1);
+    sfi_attribs(nhfp, &d_you->atime, parent, "atime", 1);
+    sfi_align(nhfp, &d_you->ualign, parent, "ualign", 1);
+    for (i = 0; i < CONVERT; ++i)
+        sfi_aligntyp(nhfp, &d_you->ualignbase[i], parent, "ualignbase", 1);
+    sfi_schar(nhfp, &d_you->uluck, parent, "uluck", 1);
+    sfi_schar(nhfp, &d_you->moreluck, parent, "moreluck", 1);
+    sfi_schar(nhfp, &d_you->uhitinc, parent, "uhitinc", 1);
+    sfi_schar(nhfp, &d_you->udaminc, parent, "udaminc", 1);
+    sfi_schar(nhfp, &d_you->uac, parent, "uac", 1);
+    sfi_uchar(nhfp, &d_you->uspellprot, parent, "uspellprot", 1);
+    sfi_uchar(nhfp, &d_you->usptime, parent, "usptime", 1);
+    sfi_uchar(nhfp, &d_you->uspmtime, parent, "uspmtime", 1);
+    sfi_int(nhfp, &d_you->uhp, parent, "uhp", 1);
+    sfi_int(nhfp, &d_you->uhpmax, parent, "uhpmax", 1);
+    sfi_int(nhfp, &d_you->uen, parent, "uen", 1);
+    sfi_int(nhfp, &d_you->uenmax, parent, "uenmax", 1);
+    sfi_xchar(nhfp, d_you->uhpinc, parent, "uhpinc", MAXULEV);
+    sfi_xchar(nhfp, d_you->ueninc, parent, "ueninc", MAXULEV);
+    sfi_int(nhfp, &d_you->ugangr, parent, "ugangr", 1);
+    sfi_int(nhfp, &d_you->ugifts, parent, "ugifts", 1);
+    sfi_int(nhfp, &d_you->ublessed, parent, "ublessed", 1);
+    sfi_int(nhfp, &d_you->ublesscnt, parent, "ublesscnt", 1);
+    sfi_long(nhfp, &d_you->umoney0, parent, "umoney0", 1);
+    sfi_long(nhfp, &d_you->uspare1, parent, "uspare1", 1);
+    sfi_long(nhfp, &d_you->uexp, parent, "uexp", 1);
+    sfi_long(nhfp, &d_you->urexp, parent, "urexp", 1);
+    sfi_long(nhfp, &d_you->ucleansed, parent, "ucleansed", 1);
+    sfi_long(nhfp, &d_you->usleep, parent, "usleep", 1);
+    sfi_int(nhfp, &d_you->uinvault, parent, "uinvault", 1);
+    sfi_genericptr(nhfp, (genericptr_t) &d_you->ustuck, parent, "ustuck", 1);
+    sfi_genericptr(nhfp, (genericptr_t) &d_you->usteed, parent, "usteed", 1);
+    sfi_long(nhfp, &d_you->ugallop, parent, "ugallop", 1);
+    sfi_int(nhfp, &d_you->urideturns, parent, "urideturns", 1);
+    sfi_int(nhfp, &d_you->umortality, parent, "umortality", 1);
+    sfi_int(nhfp, &d_you->ugrave_arise, parent, "ugrave_arise", 1);
+    sfi_int(nhfp, &d_you->weapon_slots, parent, "weapon_slots", 1);
+    sfi_int(nhfp, &d_you->skills_advanced, parent, "skills_advanced", 1);
+    sfi_xchar(nhfp, d_you->skill_record, parent, "skill_record", P_SKILL_LIMIT);
+    for (i = 0; i < P_NUM_SKILLS; ++i)
+        sfi_skills(nhfp, &d_you->weapon_skills[i], parent, "weapon_skills", 1);
+    sfi_boolean(nhfp, &d_you->twoweap, parent, "twoweap", 1);
+    sfi_short(nhfp, &d_you->mcham, parent, "mcham", 1);
+
+    if (nhfp->addinfo)
+        sfi_addinfo(nhfp, myparent, "end", "you", 1);
+}
+struct nhdatatypes_t nhdatatypes[] = {
+       {NHTYPE_SIMPLE,"any", sizeof(anything)},
+       {NHTYPE_SIMPLE,"genericptr_t", sizeof(genericptr_t)},
+       {NHTYPE_SIMPLE,"aligntyp", sizeof(aligntyp)},
+       {NHTYPE_SIMPLE,"Bitfield", sizeof(uint8_t)},
+       {NHTYPE_SIMPLE,"boolean", sizeof(boolean)},
+       {NHTYPE_SIMPLE,"char", sizeof(char)},
+       {NHTYPE_SIMPLE,"int", sizeof(int)},
+       {NHTYPE_SIMPLE,"long", sizeof(long)},
+       {NHTYPE_SIMPLE,"schar", sizeof(schar)},
+       {NHTYPE_SIMPLE,"short", sizeof(short)},
+       {NHTYPE_SIMPLE,"size_t", sizeof(size_t)},
+       {NHTYPE_SIMPLE,"string", sizeof(uchar)},
+       {NHTYPE_SIMPLE,"time_t", sizeof(time_t)},
+       {NHTYPE_SIMPLE,"uchar", sizeof(uchar)},
+       {NHTYPE_SIMPLE,"unsigned char", sizeof(unsigned char)},
+       {NHTYPE_SIMPLE,"unsigned int", sizeof(unsigned int)},
+       {NHTYPE_SIMPLE,"unsigned long", sizeof(unsigned long)},
+       {NHTYPE_SIMPLE,"unsigned short", sizeof(unsigned short)},
+       {NHTYPE_SIMPLE,"unsigned", sizeof(unsigned)},
+       {NHTYPE_SIMPLE,"xchar", sizeof(xchar)},
+       {NHTYPE_COMPLEX,"align", sizeof(struct align)},
+       {NHTYPE_COMPLEX,"attribs", sizeof(struct attribs)},
+       {NHTYPE_COMPLEX,"dig_info", sizeof(struct dig_info)},
+       {NHTYPE_COMPLEX,"tin_info", sizeof(struct tin_info)},
+       {NHTYPE_COMPLEX,"book_info", sizeof(struct book_info)},
+       {NHTYPE_COMPLEX,"takeoff_info", sizeof(struct takeoff_info)},
+       {NHTYPE_COMPLEX,"victual_info", sizeof(struct victual_info)},
+       {NHTYPE_COMPLEX,"warntype_info", sizeof(struct warntype_info)},
+       {NHTYPE_COMPLEX,"polearm_info", sizeof(struct polearm_info)},
+       {NHTYPE_COMPLEX,"obj_split", sizeof(struct obj_split)},
+       {NHTYPE_COMPLEX,"tribute_info", sizeof(struct tribute_info)},
+       {NHTYPE_COMPLEX,"novel_tracking", sizeof(struct novel_tracking)},
+       {NHTYPE_COMPLEX,"context_info", sizeof(struct context_info)},
+       {NHTYPE_COMPLEX,"nhcoord", sizeof(struct nhcoord)},
+       {NHTYPE_COMPLEX,"dgn_topology", sizeof(struct dgn_topology)},
+       {NHTYPE_COMPLEX,"kinfo", sizeof(struct kinfo)},
+       {NHTYPE_COMPLEX,"mvitals", sizeof(struct mvitals)},
+       {NHTYPE_COMPLEX,"ls_t", sizeof(struct ls_t)},
+       {NHTYPE_COMPLEX,"bubble", sizeof(struct bubble)},
+       {NHTYPE_COMPLEX,"d_flags", sizeof(struct d_flags)},
+       {NHTYPE_COMPLEX,"d_level", sizeof(struct d_level)},
+       {NHTYPE_COMPLEX,"s_level", sizeof(struct s_level)},
+       {NHTYPE_COMPLEX,"stairway", sizeof(struct stairway)},
+       {NHTYPE_COMPLEX,"dest_area", sizeof(struct dest_area)},
+       {NHTYPE_COMPLEX,"dungeon", sizeof(struct dungeon)},
+       {NHTYPE_COMPLEX,"branch", sizeof(struct branch)},
+       {NHTYPE_COMPLEX,"linfo", sizeof(struct linfo)},
+       {NHTYPE_COMPLEX,"mapseen", sizeof(struct mapseen)},
+       {NHTYPE_COMPLEX,"mapseen_feat", sizeof(struct mapseen_feat)},
+       {NHTYPE_COMPLEX,"mapseen_flags", sizeof(struct mapseen_flags)},
+       {NHTYPE_COMPLEX,"mapseen_rooms", sizeof(struct mapseen_rooms)},
+       {NHTYPE_COMPLEX,"engr", sizeof(struct engr)},
+       {NHTYPE_COMPLEX,"flag", sizeof(struct flag)},
+       {NHTYPE_COMPLEX,"version_info", sizeof(struct version_info)},
+       {NHTYPE_COMPLEX,"savefile_info", sizeof(struct savefile_info)},
+       {NHTYPE_COMPLEX,"fakecorridor", sizeof(struct fakecorridor)},
+       {NHTYPE_COMPLEX,"egd", sizeof(struct egd)},
+       {NHTYPE_COMPLEX,"epri", sizeof(struct epri)},
+       {NHTYPE_COMPLEX,"bill_x", sizeof(struct bill_x)},
+       {NHTYPE_COMPLEX,"eshk", sizeof(struct eshk)},
+       {NHTYPE_COMPLEX,"emin", sizeof(struct emin)},
+       {NHTYPE_COMPLEX,"edog", sizeof(struct edog)},
+       {NHTYPE_COMPLEX,"mextra", sizeof(struct mextra)},
+       {NHTYPE_COMPLEX,"mkroom", sizeof(struct mkroom)},
+       {NHTYPE_COMPLEX,"monst", sizeof(struct monst)},
+       {NHTYPE_COMPLEX,"vptrs", sizeof(union vptrs)},
+       {NHTYPE_COMPLEX,"oextra", sizeof(struct oextra)},
+       {NHTYPE_COMPLEX,"obj", sizeof(struct obj)},
+       {NHTYPE_COMPLEX,"objclass", sizeof(struct objclass)},
+       {NHTYPE_COMPLEX,"fruit", sizeof(struct fruit)},
+       {NHTYPE_COMPLEX,"prop", sizeof(struct prop)},
+       {NHTYPE_COMPLEX,"q_score", sizeof(struct q_score)},
+       {NHTYPE_COMPLEX,"nhrect", sizeof(struct nhrect)},
+       {NHTYPE_COMPLEX,"rm", sizeof(struct rm)},
+       {NHTYPE_COMPLEX,"damage", sizeof(struct damage)},
+       {NHTYPE_COMPLEX,"cemetery", sizeof(struct cemetery)},
+       {NHTYPE_COMPLEX,"levelflags", sizeof(struct levelflags)},
+       {NHTYPE_COMPLEX,"skills", sizeof(struct skills)},
+       {NHTYPE_COMPLEX,"spell", sizeof(struct spell)},
+       {NHTYPE_COMPLEX,"fe", sizeof(struct fe)},
+       {NHTYPE_COMPLEX,"vlaunchinfo", sizeof(union vlaunchinfo)},
+       {NHTYPE_COMPLEX,"trap", sizeof(struct trap)},
+       {NHTYPE_COMPLEX,"u_have", sizeof(struct u_have)},
+       {NHTYPE_COMPLEX,"u_event", sizeof(struct u_event)},
+       {NHTYPE_COMPLEX,"u_achieve", sizeof(struct u_achieve)},
+       {NHTYPE_COMPLEX,"u_realtime", sizeof(struct u_realtime)},
+       {NHTYPE_COMPLEX,"u_conduct", sizeof(struct u_conduct)},
+       {NHTYPE_COMPLEX,"u_roleplay", sizeof(struct u_roleplay)},
+       {NHTYPE_COMPLEX,"you", sizeof(struct you)}
+};
+
+int nhdatatypes_size()
+{
+       return SIZE(nhdatatypes);
+}
+
+char *critical_members[] = {
+       "struct align:type:aligntyp",
+       "struct align:record:int",
+       "struct attribs:a:schar",
+       "struct bill_x:bo_id:unsigned",
+       "struct bill_x:useup:boolean",
+       "struct bill_x:price:long",
+       "struct bill_x:bquan:long",
+       "struct book_info:book:struct obj *",
+       "struct book_info:o_id:unsigned",
+       "struct book_info:delay:schar",
+       "struct branch:next:struct branch *",
+       "struct branch:id:int",
+       "struct branch:type:int",
+       "struct branch:end1:d_level",
+       "struct branch:end2:d_level",
+       "struct branch:end1_up:boolean",
+       "struct bubble:x:xchar",
+       "struct bubble:y:xchar",
+       "struct bubble:dx:schar",
+       "struct bubble:dy:schar",
+       "struct bubble:bm:uchar",
+       "struct bubble:prev:struct bubble *",
+       "struct bubble:next:struct bubble *",
+       "struct bubble:cons:struct container *",
+       "struct cemetery:next:struct cemetery *",
+       "struct cemetery:who:char",
+       "struct cemetery:how:char",
+       "struct cemetery:when:char",
+       "struct cemetery:frpx:schar",
+       "struct cemetery:frpy:schar",
+       "struct cemetery:bonesknown:boolean",
+       "struct context_info:ident:unsigned",
+       "struct context_info:no_of_wizards:unsigned",
+       "struct context_info:run:unsigned",
+       "struct context_info:startingpet_mid:unsigned",
+       "struct context_info:current_fruit:int",
+       "struct context_info:warnlevel:int",
+       "struct context_info:rndencode:int",
+       "struct context_info:next_attrib_check:long",
+       "struct context_info:stethoscope_move:long",
+       "struct context_info:stethoscope_movement:short",
+       "struct context_info:travel:boolean",
+       "struct context_info:travel1:boolean",
+       "struct context_info:forcefight:boolean",
+       "struct context_info:nopick:boolean",
+       "struct context_info:made_amulet:boolean",
+       "struct context_info:mon_moving:boolean",
+       "struct context_info:move:boolean",
+       "struct context_info:mv:boolean",
+       "struct context_info:bypasses:boolean",
+       "struct context_info:botl:boolean",
+       "struct context_info:botlx:boolean",
+       "struct context_info:door_opened:boolean",
+       "struct context_info:digging:dig_info",
+       "struct context_info:victual:victual_info",
+       "struct context_info:tin:tin_info",
+       "struct context_info:spbook:book_info",
+       "struct context_info:takeoff:takeoff_info",
+       "struct context_info:warntype:warntype_info",
+       "struct context_info:polearm:polearm_info",
+       "struct context_info:objsplit:obj_split",
+       "struct context_info:tribute:tribute_info",
+       "struct context_info:novel:novel_tracking",
+       "struct d_flags:town:Bitfield(town, 1)",
+       "struct d_flags:hellish:Bitfield(hellish, 1)",
+       "struct d_flags:maze_like:Bitfield(maze_like, 1)",
+       "struct d_flags:rogue_like:Bitfield(rogue_like, 1)",
+       "struct d_flags:align:Bitfield(align, 3)",
+       "struct d_flags:unused:Bitfield(unused, 1)",
+       "struct d_level:dnum:xchar",
+       "struct d_level:dlevel:xchar",
+       "struct damage:next:struct damage *",
+       "struct damage:when:long",
+       "struct damage:cost:long",
+       "struct damage:place:nhcoord",
+       "struct damage:typ:schar",
+       "struct dest_area:lx:xchar",
+       "struct dest_area:ly:xchar",
+       "struct dest_area:hx:xchar",
+       "struct dest_area:hy:xchar",
+       "struct dest_area:nlx:xchar",
+       "struct dest_area:nly:xchar",
+       "struct dest_area:nhx:xchar",
+       "struct dest_area:nhy:xchar",
+       "struct dgn_topology:d_oracle_level:d_level",
+       "struct dgn_topology:d_bigroom_level:d_level",
+       "struct dgn_topology:d_rogue_level:d_level",
+       "struct dgn_topology:d_medusa_level:d_level",
+       "struct dgn_topology:d_stronghold_level:d_level",
+       "struct dgn_topology:d_valley_level:d_level",
+       "struct dgn_topology:d_wiz1_level:d_level",
+       "struct dgn_topology:d_wiz2_level:d_level",
+       "struct dgn_topology:d_wiz3_level:d_level",
+       "struct dgn_topology:d_juiblex_level:d_level",
+       "struct dgn_topology:d_orcus_level:d_level",
+       "struct dgn_topology:d_baalzebub_level:d_level",
+       "struct dgn_topology:d_asmodeus_level:d_level",
+       "struct dgn_topology:d_portal_level:d_level",
+       "struct dgn_topology:d_sanctum_level:d_level",
+       "struct dgn_topology:d_earth_level:d_level",
+       "struct dgn_topology:d_water_level:d_level",
+       "struct dgn_topology:d_fire_level:d_level",
+       "struct dgn_topology:d_air_level:d_level",
+       "struct dgn_topology:d_astral_level:d_level",
+       "struct dgn_topology:d_tower_dnum:xchar",
+       "struct dgn_topology:d_sokoban_dnum:xchar",
+       "struct dgn_topology:d_mines_dnum:xchar",
+       "struct dgn_topology:d_quest_dnum:xchar",
+       "struct dgn_topology:d_qstart_level:d_level",
+       "struct dgn_topology:d_qlocate_level:d_level",
+       "struct dgn_topology:d_nemesis_level:d_level",
+       "struct dgn_topology:d_knox_level:d_level",
+       "struct dgn_topology:d_mineend_level:d_level",
+       "struct dgn_topology:d_sokoend_level:d_level",
+       "struct dig_info:effort:int",
+       "struct dig_info:level:d_level",
+       "struct dig_info:pos:nhcoord",
+       "struct dig_info:lastdigtime:long",
+       "struct dig_info:down:boolean",
+       "struct dig_info:chew:boolean",
+       "struct dig_info:warned:boolean",
+       "struct dig_info:quiet:boolean",
+       "struct dungeon:dname:char",
+       "struct dungeon:proto:char",
+       "struct dungeon:boneid:char",
+       "struct dungeon:flags:d_flags",
+       "struct dungeon:entry_lev:xchar",
+       "struct dungeon:num_dunlevs:xchar",
+       "struct dungeon:dunlev_ureached:xchar",
+       "struct dungeon:ledger_start:int",
+       "struct dungeon:depth_start:int",
+       "struct edog:droptime:long",
+       "struct edog:dropdist:unsigned",
+       "struct edog:apport:int",
+       "struct edog:whistletime:long",
+       "struct edog:hungrytime:long",
+       "struct edog:ogoal:nhcoord",
+       "struct edog:abuse:int",
+       "struct edog:revivals:int",
+       "struct edog:mhpmax_penalty:int",
+       "struct edog:killed_by_u:Bitfield(killed_by_u, 1)",
+       "struct egd:fcbeg:int",
+       "struct egd:fcend:int",
+       "struct egd:vroom:int",
+       "struct egd:gdx:xchar",
+       "struct egd:gdy:xchar",
+       "struct egd:ogx:xchar",
+       "struct egd:ogy:xchar",
+       "struct egd:gdlevel:d_level",
+       "struct egd:warncnt:xchar",
+       "struct egd:gddone:Bitfield(gddone, 1)",
+       "struct egd:witness:Bitfield(witness, 2)",
+       "struct egd:unused:Bitfield(unused, 5)",
+       "struct egd:fakecorr:fakecorridor",
+       "struct emin:min_align:aligntyp",
+       "struct emin:renegade:boolean",
+       "struct engr:nxt_engr:struct engr *",
+       "struct engr:engr_txt:char *",
+       "struct engr:engr_x:xchar",
+       "struct engr:engr_y:xchar",
+       "struct engr:engr_lth:unsigned",
+       "struct engr:engr_time:long",
+       "struct engr:engr_type:xchar",
+       "struct epri:shralign:aligntyp",
+       "struct epri:shroom:schar",
+       "struct epri:shrpos:nhcoord",
+       "struct epri:shrlevel:d_level",
+       "struct epri:intone_time:long",
+       "struct epri:enter_time:long",
+       "struct epri:hostile_time:long",
+       "struct epri:peaceful_time:long",
+       "struct eshk:robbed:long",
+       "struct eshk:credit:long",
+       "struct eshk:debit:long",
+       "struct eshk:loan:long",
+       "struct eshk:shoptype:int",
+       "struct eshk:shoproom:schar",
+       "struct eshk:unused:schar",
+       "struct eshk:following:boolean",
+       "struct eshk:surcharge:boolean",
+       "struct eshk:dismiss_kops:boolean",
+       "struct eshk:shk:nhcoord",
+       "struct eshk:shd:nhcoord",
+       "struct eshk:shoplevel:d_level",
+       "struct eshk:billct:int",
+       "struct eshk:bill:bill_x",
+       "struct eshk:bill_p:struct bill_x *",
+       "struct eshk:visitct:int",
+       "struct eshk:customer:char",
+       "struct eshk:shknam:char",
+       "struct fakecorridor:fx:xchar",
+       "struct fakecorridor:fy:xchar",
+       "struct fakecorridor:ftyp:xchar",
+       "struct fe:next:struct fe *",
+       "struct fe:timeout:long",
+       "struct fe:tid:unsigned long",
+       "struct fe:kind:short",
+       "struct fe:func_index:short",
+       "struct fe:arg:any",
+       "struct fe:needs_fixup:Bitfield(needs_fixup, 1)",
+       "struct flag:acoustics:boolean",
+       "struct flag:autodig:boolean",
+       "struct flag:autoquiver:boolean",
+       "struct flag:autoopen:boolean",
+       "struct flag:beginner:boolean",
+       "struct flag:biff:boolean",
+       "struct flag:bones:boolean",
+       "struct flag:confirm:boolean",
+       "struct flag:dark_room:boolean",
+       "struct flag:debug:boolean",
+       "struct flag:end_own:boolean",
+       "struct flag:explore:boolean",
+       "struct flag:female:boolean",
+       "struct flag:friday13:boolean",
+       "struct flag:help:boolean",
+       "struct flag:ignintr:boolean",
+       "struct flag:ins_chkpt:boolean",
+       "struct flag:invlet_constant:boolean",
+       "struct flag:legacy:boolean",
+       "struct flag:lit_corridor:boolean",
+       "struct flag:nap:boolean",
+       "struct flag:null:boolean",
+       "struct flag:p__obsolete:boolean",
+       "struct flag:pickup:boolean",
+       "struct flag:pickup_thrown:boolean",
+       "struct flag:pushweapon:boolean",
+       "struct flag:rest_on_space:boolean",
+       "struct flag:safe_dog:boolean",
+       "struct flag:showexp:boolean",
+       "struct flag:showscore:boolean",
+       "struct flag:silent:boolean",
+       "struct flag:sortloot:xchar",
+       "struct flag:sortloot:char",
+       "struct flag:sortpack:boolean",
+       "struct flag:sparkle:boolean",
+       "struct flag:standout:boolean",
+       "struct flag:time:boolean",
+       "struct flag:tombstone:boolean",
+       "struct flag:verbose:boolean",
+       "struct flag:end_top:int",
+       "struct flag:end_around:int",
+       "struct flag:moonphase:unsigned",
+       "struct flag:suppress_alert:unsigned long",
+       "struct flag:paranoia_bits:unsigned",
+       "struct flag:pickup_burden:int",
+       "struct flag:pile_limit:int",
+       "struct flag:inv_order:char",
+       "struct flag:pickup_types:char",
+       "struct flag:end_disclose:char",
+       "struct flag:menu_style:char",
+       "struct flag:made_fruit:boolean",
+       "struct flag:initrole:int",
+       "struct flag:initrace:int",
+       "struct flag:initgend:int",
+       "struct flag:initalign:int",
+       "struct flag:randomall:int",
+       "struct flag:pantheon:int",
+       "struct flag:lootabc:boolean",
+       "struct flag:showrace:boolean",
+       "struct flag:travelcmd:boolean",
+       "struct flag:runmode:int",
+       "struct fruit:fname:char",
+       "struct fruit:fid:int",
+       "struct fruit:nextf:struct fruit *",
+       "struct kinfo:next:struct kinfo *",
+       "struct kinfo:id:int",
+       "struct kinfo:format:int",
+       "struct kinfo:name:char",
+       "struct levelflags:nfountains:uchar",
+       "struct levelflags:nsinks:uchar",
+       "struct levelflags:has_shop:Bitfield(has_shop, 1)",
+       "struct levelflags:has_vault:Bitfield(has_vault, 1)",
+       "struct levelflags:has_zoo:Bitfield(has_zoo, 1)",
+       "struct levelflags:has_court:Bitfield(has_court, 1)",
+       "struct levelflags:has_morgue:Bitfield(has_morgue, 1)",
+       "struct levelflags:has_beehive:Bitfield(has_beehive, 1)",
+       "struct levelflags:has_barracks:Bitfield(has_barracks, 1)",
+       "struct levelflags:has_temple:Bitfield(has_temple, 1)",
+       "struct levelflags:has_swamp:Bitfield(has_swamp, 1)",
+       "struct levelflags:noteleport:Bitfield(noteleport, 1)",
+       "struct levelflags:hardfloor:Bitfield(hardfloor, 1)",
+       "struct levelflags:nommap:Bitfield(nommap, 1)",
+       "struct levelflags:hero_memory:Bitfield(hero_memory, 1)",
+       "struct levelflags:shortsighted:Bitfield(shortsighted, 1)",
+       "struct levelflags:graveyard:Bitfield(graveyard, 1)",
+       "struct levelflags:sokoban_rules:Bitfield(sokoban_rules, 1)",
+       "struct levelflags:is_maze_lev:Bitfield(is_maze_lev, 1)",
+       "struct levelflags:is_cavernous_lev:Bitfield(is_cavernous_lev, 1)",
+       "struct levelflags:arboreal:Bitfield(arboreal, 1)",
+       "struct levelflags:wizard_bones:Bitfield(wizard_bones, 1)",
+       "struct levelflags:corrmaze:Bitfield(corrmaze, 1)",
+       "struct linfo:flags:unsigned char",
+#ifdef MFLOPPY
+       "struct linfo:where:int",
+       "struct linfo:time:long",
+       "struct linfo:size:long",
+#endif /*MFLOPPY*/
+       "struct ls_t:next:struct ls_t *",
+       "struct ls_t:x:xchar",
+       "struct ls_t:y:xchar",
+       "struct ls_t:range:short",
+       "struct ls_t:flags:short",
+       "struct ls_t:type:short",
+       "struct ls_t:id:any",
+       "struct mapseen_feat:nfount:Bitfield(nfount, 2)",
+       "struct mapseen_feat:nsink:Bitfield(nsink, 2)",
+       "struct mapseen_feat:naltar:Bitfield(naltar, 2)",
+       "struct mapseen_feat:nthrone:Bitfield(nthrone, 2)",
+       "struct mapseen_feat:ngrave:Bitfield(ngrave, 2)",
+       "struct mapseen_feat:ntree:Bitfield(ntree, 2)",
+       "struct mapseen_feat:water:Bitfield(water, 2)",
+       "struct mapseen_feat:lava:Bitfield(lava, 2)",
+       "struct mapseen_feat:ice:Bitfield(ice, 2)",
+       "struct mapseen_feat:nshop:Bitfield(nshop, 2)",
+       "struct mapseen_feat:ntemple:Bitfield(ntemple, 2)",
+       "struct mapseen_feat:msalign:Bitfield(msalign, 2)",
+       "struct mapseen_feat:shoptype:Bitfield(shoptype, 5)",
+       "struct mapseen_flags:unreachable:Bitfield(unreachable, 1)",
+       "struct mapseen_flags:forgot:Bitfield(forgot, 1)",
+       "struct mapseen_flags:knownbones:Bitfield(knownbones, 1)",
+       "struct mapseen_flags:oracle:Bitfield(oracle, 1)",
+       "struct mapseen_flags:sokosolved:Bitfield(sokosolved, 1)",
+       "struct mapseen_flags:bigroom:Bitfield(bigroom, 1)",
+       "struct mapseen_flags:castle:Bitfield(castle, 1)",
+       "struct mapseen_flags:castletune:Bitfield(castletune, 1)",
+       "struct mapseen_flags:valley:Bitfield(valley, 1)",
+       "struct mapseen_flags:msanctum:Bitfield(msanctum, 1)",
+       "struct mapseen_flags:ludios:Bitfield(ludios, 1)",
+       "struct mapseen_flags:roguelevel:Bitfield(roguelevel, 1)",
+       "struct mapseen_flags:quest_summons:Bitfield(quest_summons, 1)",
+       "struct mapseen_flags:questing:Bitfield(questing, 1)",
+       "struct mapseen_flags:vibrating_square:Bitfield(vibrating_square, 1)",
+       "struct mapseen_flags:spare1:Bitfield(spare1, 1)",
+       "struct mapseen_rooms:seen:Bitfield(seen, 1)",
+       "struct mapseen_rooms:untended:Bitfield(untended, 1)",
+       "struct mapseen:next:struct mapseen *",
+       "struct mapseen:br:branch *",
+       "struct mapseen:lev:d_level",
+       "struct mapseen:feat:mapseen_feat",
+       "struct mapseen:flags:mapseen_flags",
+       "struct mapseen:custom:char *",
+       "struct mapseen:custom_lth:unsigned",
+       "struct mapseen:msrooms:mapseen_rooms",
+       "struct mapseen:final_resting_place:struct cemetery *",
+       "struct mextra:mname:char *",
+       "struct mextra:egd:struct egd *",
+       "struct mextra:epri:struct epri *",
+       "struct mextra:eshk:struct eshk *",
+       "struct mextra:emin:struct emin *",
+       "struct mextra:edog:struct edog *",
+       "struct mextra:mcorpsenm:int",
+       "struct mkroom:lx:schar",
+       "struct mkroom:hx:schar",
+       "struct mkroom:ly:schar",
+       "struct mkroom:hy:schar",
+       "struct mkroom:rtype:schar",
+       "struct mkroom:orig_rtype:schar",
+       "struct mkroom:rlit:schar",
+       "struct mkroom:needfill:schar",
+       "struct mkroom:needjoining:schar",
+       "struct mkroom:doorct:schar",
+       "struct mkroom:fdoor:schar",
+       "struct mkroom:nsubrooms:schar",
+       "struct mkroom:irregular:boolean",
+       "struct mkroom:sbrooms:struct mkroom *",
+       "struct mkroom:resident:struct monst *",
+       "struct monst:nmon:struct monst *",
+       "struct monst:data:struct permonst *",
+       "struct monst:m_id:unsigned",
+       "struct monst:mnum:short",
+       "struct monst:cham:short",
+       "struct monst:movement:short",
+       "struct monst:m_lev:uchar",
+       "struct monst:malign:aligntyp",
+       "struct monst:mx:xchar",
+       "struct monst:my:xchar",
+       "struct monst:mux:xchar",
+       "struct monst:muy:xchar",
+       "struct monst:mtrack:nhcoord",
+       "struct monst:mhp:int",
+       "struct monst:mhpmax:int",
+       "struct monst:mappearance:unsigned",
+       "struct monst:m_ap_type:uchar",
+       "struct monst:mtame:schar",
+       "struct monst:mextrinsics:unsigned short",
+       "struct monst:mspec_used:int",
+       "struct monst:female:Bitfield(female, 1)",
+       "struct monst:minvis:Bitfield(minvis, 1)",
+       "struct monst:invis_blkd:Bitfield(invis_blkd, 1)",
+       "struct monst:perminvis:Bitfield(perminvis, 1)",
+       "struct monst:mcan:Bitfield(mcan, 1)",
+       "struct monst:mburied:Bitfield(mburied, 1)",
+       "struct monst:mundetected:Bitfield(mundetected, 1)",
+       "struct monst:mcansee:Bitfield(mcansee, 1)",
+       "struct monst:mspeed:Bitfield(mspeed, 2)",
+       "struct monst:permspeed:Bitfield(permspeed, 2)",
+       "struct monst:mrevived:Bitfield(mrevived, 1)",
+       "struct monst:mcloned:Bitfield(mcloned, 1)",
+       "struct monst:mavenge:Bitfield(mavenge, 1)",
+       "struct monst:mflee:Bitfield(mflee, 1)",
+       "struct monst:mfleetim:Bitfield(mfleetim, 7)",
+       "struct monst:msleeping:Bitfield(msleeping, 1)",
+       "struct monst:mblinded:Bitfield(mblinded, 7)",
+       "struct monst:mstun:Bitfield(mstun, 1)",
+       "struct monst:mfrozen:Bitfield(mfrozen, 7)",
+       "struct monst:mcanmove:Bitfield(mcanmove, 1)",
+       "struct monst:mconf:Bitfield(mconf, 1)",
+       "struct monst:mpeaceful:Bitfield(mpeaceful, 1)",
+       "struct monst:mtrapped:Bitfield(mtrapped, 1)",
+       "struct monst:mleashed:Bitfield(mleashed, 1)",
+       "struct monst:isshk:Bitfield(isshk, 1)",
+       "struct monst:isminion:Bitfield(isminion, 1)",
+       "struct monst:isgd:Bitfield(isgd, 1)",
+       "struct monst:ispriest:Bitfield(ispriest, 1)",
+       "struct monst:iswiz:Bitfield(iswiz, 1)",
+       "struct monst:wormno:Bitfield(wormno, 5)",
+       "struct monst:mtemplit:Bitfield(mtemplit, 1)",
+       "struct monst:mstrategy:unsigned long",
+       "struct monst:mtrapseen:long",
+       "struct monst:mlstmv:long",
+       "struct monst:mspare1:long",
+       "struct monst:minvent:struct obj *",
+       "struct monst:mw:struct obj *",
+       "struct monst:misc_worn_check:long",
+       "struct monst:weapon_check:xchar",
+       "struct monst:meating:int",
+       "struct monst:mextra:struct mextra *",
+       "struct mvitals:born:uchar",
+       "struct mvitals:died:uchar",
+       "struct mvitals:mvflags:uchar",
+       "struct nhcoord:x:xchar",
+       "struct nhcoord:y:xchar",
+       "struct nhrect:lx:xchar",
+       "struct nhrect:ly:xchar",
+       "struct nhrect:hx:xchar",
+       "struct nhrect:hy:xchar",
+       "struct novel_tracking:id:unsigned",
+       "struct novel_tracking:count:int",
+       "struct novel_tracking:pasg:xchar",
+       "struct obj:nobj:struct obj *",
+       "struct obj:v:vptrs",
+       "struct obj:cobj:struct obj *",
+       "struct obj:o_id:unsigned",
+       "struct obj:ox:xchar",
+       "struct obj:oy:xchar",
+       "struct obj:otyp:short",
+       "struct obj:owt:unsigned",
+       "struct obj:quan:long",
+       "struct obj:spe:schar",
+       "struct obj:oclass:char",
+       "struct obj:invlet:char",
+       "struct obj:oartifact:char",
+       "struct obj:where:xchar",
+       "struct obj:timed:xchar",
+       "struct obj:cursed:Bitfield(cursed, 1)",
+       "struct obj:blessed:Bitfield(blessed, 1)",
+       "struct obj:unpaid:Bitfield(unpaid, 1)",
+       "struct obj:no_charge:Bitfield(no_charge, 1)",
+       "struct obj:known:Bitfield(known, 1)",
+       "struct obj:dknown:Bitfield(dknown, 1)",
+       "struct obj:bknown:Bitfield(bknown, 1)",
+       "struct obj:rknown:Bitfield(rknown, 1)",
+       "struct obj:oeroded:Bitfield(oeroded, 2)",
+       "struct obj:oeroded2:Bitfield(oeroded2, 2)",
+       "struct obj:oerodeproof:Bitfield(oerodeproof, 1)",
+       "struct obj:olocked:Bitfield(olocked, 1)",
+       "struct obj:obroken:Bitfield(obroken, 1)",
+       "struct obj:otrapped:Bitfield(otrapped, 1)",
+       "struct obj:recharged:Bitfield(recharged, 3)",
+       "struct obj:lamplit:Bitfield(lamplit, 1)",
+       "struct obj:globby:Bitfield(globby, 1)",
+       "struct obj:greased:Bitfield(greased, 1)",
+       "struct obj:nomerge:Bitfield(nomerge, 1)",
+       "struct obj:was_thrown:Bitfield(was_thrown, 1)",
+       "struct obj:in_use:Bitfield(in_use, 1)",
+       "struct obj:bypass:Bitfield(bypass, 1)",
+       "struct obj:cknown:Bitfield(cknown, 1)",
+       "struct obj:lknown:Bitfield(lknown, 1)",
+       "struct obj:corpsenm:int",
+       "struct obj:usecount:int",
+       "struct obj:oeaten:unsigned",
+       "struct obj:age:long",
+       "struct obj:owornmask:long",
+       "struct obj:oextra:struct oextra *",
+       "struct objclass:oc_name_idx:short",
+       "struct objclass:oc_descr_idx:short",
+       "struct objclass:oc_uname:char *",
+       "struct objclass:oc_name_known:Bitfield(oc_name_known, 1)",
+       "struct objclass:oc_merge:Bitfield(oc_merge, 1)",
+       "struct objclass:oc_uses_known:Bitfield(oc_uses_known, 1)",
+       "struct objclass:oc_pre_discovered:Bitfield(oc_pre_discovered, 1)",
+       "struct objclass:oc_magic:Bitfield(oc_magic, 1)",
+       "struct objclass:oc_charged:Bitfield(oc_charged, 1)",
+       "struct objclass:oc_unique:Bitfield(oc_unique, 1)",
+       "struct objclass:oc_nowish:Bitfield(oc_nowish, 1)",
+       "struct objclass:oc_big:Bitfield(oc_big, 1)",
+       "struct objclass:oc_tough:Bitfield(oc_tough, 1)",
+       "struct objclass:oc_dir:Bitfield(oc_dir, 2)",
+       "struct objclass:oc_material:Bitfield(oc_material, 5)",
+       "struct objclass:oc_subtyp:schar",
+       "struct objclass:oc_oprop:uchar",
+       "struct objclass:oc_class:char",
+       "struct objclass:oc_delay:schar",
+       "struct objclass:oc_color:uchar",
+       "struct objclass:oc_prob:short",
+       "struct objclass:oc_weight:unsigned short",
+       "struct objclass:oc_cost:short",
+       "struct objclass:oc_wsdam:schar",
+       "struct objclass:oc_wldam:schar",
+       "struct objclass:oc_oc1:schar",
+       "struct objclass:oc_oc2:schar",
+       "struct objclass:oc_nutrition:unsigned short",
+       "struct obj_split:parent_oid:unsigned",
+       "struct obj_split:child_oid:unsigned",
+       "struct oextra:oname:char *",
+       "struct oextra:omonst:struct monst *",
+       "struct oextra:omid:unsigned *",
+       "struct oextra:olong:long *",
+       "struct oextra:omailcmd:char *",
+       "struct polearm_info:hitmon:struct monst *",
+       "struct polearm_info:m_id:unsigned",
+       "struct prop:extrinsic:long",
+       "struct prop:blocked:long",
+       "struct prop:intrinsic:long",
+       "struct q_score:first_start:Bitfield(first_start, 1)",
+       "struct q_score:met_leader:Bitfield(met_leader, 1)",
+       "struct q_score:not_ready:Bitfield(not_ready, 3)",
+       "struct q_score:pissed_off:Bitfield(pissed_off, 1)",
+       "struct q_score:got_quest:Bitfield(got_quest, 1)",
+       "struct q_score:first_locate:Bitfield(first_locate, 1)",
+       "struct q_score:met_intermed:Bitfield(met_intermed, 1)",
+       "struct q_score:got_final:Bitfield(got_final, 1)",
+       "struct q_score:made_goal:Bitfield(made_goal, 3)",
+       "struct q_score:met_nemesis:Bitfield(met_nemesis, 1)",
+       "struct q_score:killed_nemesis:Bitfield(killed_nemesis, 1)",
+       "struct q_score:in_battle:Bitfield(in_battle, 1)",
+       "struct q_score:cheater:Bitfield(cheater, 1)",
+       "struct q_score:touched_artifact:Bitfield(touched_artifact, 1)",
+       "struct q_score:offered_artifact:Bitfield(offered_artifact, 1)",
+       "struct q_score:got_thanks:Bitfield(got_thanks, 1)",
+       "struct q_score:ldrgend:Bitfield(ldrgend, 2)",
+       "struct q_score:nemgend:Bitfield(nemgend, 2)",
+       "struct q_score:godgend:Bitfield(godgend, 2)",
+       "struct q_score:leader_is_dead:Bitfield(leader_is_dead, 1)",
+       "struct q_score:leader_m_id:unsigned",
+       "struct rm:glyph:int",
+       "struct rm:typ:schar",
+       "struct rm:seenv:uchar",
+       "struct rm:flags:Bitfield(flags, 5)",
+       "struct rm:horizontal:Bitfield(horizontal, 1)",
+       "struct rm:lit:Bitfield(lit, 1)",
+       "struct rm:waslit:Bitfield(waslit, 1)",
+       "struct rm:roomno:Bitfield(roomno, 6)",
+       "struct rm:edge:Bitfield(edge, 1)",
+       "struct rm:candig:Bitfield(candig, 1)",
+       "struct s_level:next:struct s_level *",
+       "struct s_level:dlevel:d_level",
+       "struct s_level:proto:char",
+       "struct s_level:boneid:char",
+       "struct s_level:rndlevs:uchar",
+       "struct s_level:flags:d_flags",
+       "struct savefile_info:sfi1:unsigned long",
+       "struct savefile_info:sfi2:unsigned long",
+       "struct savefile_info:sfi3:unsigned long",
+       "struct skills:skill:xchar",
+       "struct skills:max_skill:xchar",
+       "struct skills:advance:unsigned short",
+       "struct spell:sp_id:short",
+       "struct spell:sp_lev:xchar",
+       "struct spell:sp_know:int",
+       "struct stairway:sx:xchar",
+       "struct stairway:sy:xchar",
+       "struct stairway:tolev:d_level",
+       "struct stairway:up:char",
+       "struct takeoff_info:mask:long",
+       "struct takeoff_info:what:long",
+       "struct takeoff_info:delay:int",
+       "struct takeoff_info:cancelled_don:boolean",
+       "struct takeoff_info:disrobing:char",
+       "struct tin_info:tin:struct obj *",
+       "struct tin_info:o_id:unsigned",
+       "struct tin_info:usedtime:int",
+       "struct tin_info:reqtime:int",
+       "struct trap:ntrap:struct trap *",
+       "struct trap:tx:xchar",
+       "struct trap:ty:xchar",
+       "struct trap:dst:d_level",
+       "struct trap:launch:nhcoord",
+       "struct trap:ttyp:Bitfield(ttyp, 5)",
+       "struct trap:tseen:Bitfield(tseen, 1)",
+       "struct trap:once:Bitfield(once, 1)",
+       "struct trap:madeby_u:Bitfield(madeby_u, 1)",
+       "struct trap:vl:vlaunchinfo",
+       "struct tribute_info:tributesz:size_t",
+       "struct tribute_info:enabled:boolean",
+       "struct tribute_info:bookstock:Bitfield(bookstock, 1)",
+       "struct tribute_info:Deathnotice:Bitfield(Deathnotice,1)",
+       "struct u_achieve:amulet:Bitfield(amulet, 1)",
+       "struct u_achieve:bell:Bitfield(bell, 1)",
+       "struct u_achieve:book:Bitfield(book, 1)",
+       "struct u_achieve:menorah:Bitfield(menorah, 1)",
+       "struct u_achieve:enter_gehennom:Bitfield(enter_gehennom,1)",
+       "struct u_achieve:ascended:Bitfield(ascended, 1)",
+       "struct u_achieve:mines_luckstone:Bitfield(mines_luckstone, 1)",
+       "struct u_achieve:finish_sokoban:Bitfield(finish_sokoban, 1)",
+       "struct u_achieve:killed_medusa:Bitfield(killed_medusa, 1)",
+       "struct u_conduct:unvegetarian:long",
+       "struct u_conduct:unvegan:long",
+       "struct u_conduct:food:long",
+       "struct u_conduct:gnostic:long",
+       "struct u_conduct:weaphit:long",
+       "struct u_conduct:killer:long",
+       "struct u_conduct:literate:long",
+       "struct u_conduct:polypiles:long",
+       "struct u_conduct:polyselfs:long",
+       "struct u_conduct:wishes:long",
+       "struct u_conduct:wisharti:long",
+       "struct u_event:minor_oracle:Bitfield(minor_oracle, 1)",
+       "struct u_event:major_oracle:Bitfield(major_oracle, 1)",
+       "struct u_event:read_tribute:Bitfield(read_tribute, 1)",
+       "struct u_event:qcalled:Bitfield(qcalled, 1)",
+       "struct u_event:qexpelled:Bitfield(qexpelled, 1)",
+       "struct u_event:qcompleted:Bitfield(qcompleted, 1)",
+       "struct u_event:uheard_tune:Bitfield(uheard_tune, 2)",
+       "struct u_event:uopened_dbridge:Bitfield(uopened_dbridge, 1)",
+       "struct u_event:invoked:Bitfield(invoked, 1)",
+       "struct u_event:gehennom_entered:Bitfield(gehennom_entered, 1)",
+       "struct u_event:uhand_of_elbereth:Bitfield(uhand_of_elbereth, 2)",
+       "struct u_event:udemigod:Bitfield(udemigod, 1)",
+       "struct u_event:uvibrated:Bitfield(uvibrated, 1)",
+       "struct u_event:ascended:Bitfield(ascended, 1)",
+       "struct u_have:amulet:Bitfield(amulet, 1)",
+       "struct u_have:bell:Bitfield(bell, 1)",
+       "struct u_have:book:Bitfield(book, 1)",
+       "struct u_have:menorah:Bitfield(menorah, 1)",
+       "struct u_have:questart:Bitfield(questart, 1)",
+       "struct u_have:unused:Bitfield(unused, 3)",
+       "struct u_realtime:realtime:long",
+       "struct u_realtime:start_timing:time_t",
+       "struct u_realtime:finish_time:time_t",
+       "struct u_roleplay:blind:boolean",
+       "struct u_roleplay:nudist:boolean",
+       "struct u_roleplay:numbones:long",
+       "struct version_info:incarnation:unsigned long",
+       "struct version_info:feature_set:unsigned long",
+       "struct version_info:entity_count:unsigned long",
+       "struct version_info:struct_sizes1:unsigned long",
+       "struct version_info:struct_sizes2:unsigned long",
+       "struct victual_info:piece:struct obj *",
+       "struct victual_info:o_id:unsigned",
+       "struct victual_info:usedtime:int",
+       "struct victual_info:reqtime:int",
+       "struct victual_info:nmod:int",
+       "struct victual_info:canchoke:Bitfield(canchoke, 1)",
+       "struct victual_info:fullwarn:Bitfield(fullwarn, 1)",
+       "struct victual_info:eating:Bitfield(eating, 1)",
+       "struct victual_info:doreset:Bitfield(doreset, 1)",
+       "union vlaunchinfo:v_launch_otyp:short",
+       "union vlaunchinfo:v_launch2:nhcoord",
+       "union vlaunchinfo:v_conjoined:uchar",
+       "union vlaunchinfo:v_tnote:short",
+       "union vptrs:v_nexthere:struct obj *",
+       "union vptrs:v_ocontainer:struct obj *",
+       "union vptrs:v_ocarry:struct monst *",
+       "struct warntype_info:obj:unsigned long",
+       "struct warntype_info:polyd:unsigned long",
+       "struct warntype_info:species:struct permonst *",
+       "struct warntype_info:speciesidx:short",
+       "struct you:ux:xchar",
+       "struct you:uy:xchar",
+       "struct you:dx:schar",
+       "struct you:dy:schar",
+       "struct you:dz:schar",
+       "struct you:di:schar",
+       "struct you:tx:xchar",
+       "struct you:ty:xchar",
+       "struct you:ux0:xchar",
+       "struct you:uy0:xchar",
+       "struct you:uz:d_level",
+       "struct you:uz0:d_level",
+       "struct you:utolev:d_level",
+       "struct you:utotype:uchar",
+       "struct you:umoved:boolean",
+       "struct you:last_str_turn:int",
+       "struct you:ulevel:int",
+       "struct you:ulevelmax:int",
+       "struct you:utrap:unsigned",
+       "struct you:utraptype:unsigned",
+       "struct you:urooms:char",
+       "struct you:urooms0:char",
+       "struct you:uentered:char",
+       "struct you:ushops:char",
+       "struct you:ushops0:char",
+       "struct you:ushops_entered:char",
+       "struct you:ushops_left:char",
+       "struct you:uhunger:int",
+       "struct you:uhs:unsigned",
+       "struct you:uprops:prop",
+       "struct you:umconf:unsigned",
+       "struct you:usick_type:Bitfield(usick_type, 2)",
+       "struct you:nv_range:int",
+       "struct you:xray_range:int",
+       "struct you:bglyph:int",
+       "struct you:cglyph:int",
+       "struct you:bc_order:int",
+       "struct you:bc_felt:int",
+       "struct you:umonster:int",
+       "struct you:umonnum:int",
+       "struct you:mh:int",
+       "struct you:mhmax:int",
+       "struct you:mtimedone:int",
+       "struct you:macurr:attribs",
+       "struct you:mamax:attribs",
+       "struct you:ulycn:int",
+       "struct you:ucreamed:unsigned",
+       "struct you:uswldtim:unsigned",
+       "struct you:uswallow:Bitfield(uswallow, 1)",
+       "struct you:uinwater:Bitfield(uinwater, 1)",
+       "struct you:uundetected:Bitfield(uundetected, 1)",
+       "struct you:mfemale:Bitfield(mfemale, 1)",
+       "struct you:uinvulnerable:Bitfield(uinvulnerable, 1)",
+       "struct you:uburied:Bitfield(uburied, 1)",
+       "struct you:uedibility:Bitfield(uedibility, 1)",
+       "struct you:udg_cnt:unsigned",
+       "struct you:uachieve:u_achieve",
+       "struct you:uevent:u_event",
+       "struct you:uhave:u_have",
+       "struct you:uconduct:u_conduct",
+       "struct you:uroleplay:u_roleplay",
+       "struct you:acurr:attribs",
+       "struct you:aexe:attribs",
+       "struct you:abon:attribs",
+       "struct you:amax:attribs",
+       "struct you:atemp:attribs",
+       "struct you:atime:attribs",
+       "struct you:ualign:align",
+       "struct you:ualignbase:aligntyp",
+       "struct you:uluck:schar",
+       "struct you:moreluck:schar",
+       "struct you:uhitinc:schar",
+       "struct you:udaminc:schar",
+       "struct you:uac:schar",
+       "struct you:uspellprot:uchar",
+       "struct you:usptime:uchar",
+       "struct you:uspmtime:uchar",
+       "struct you:uhp:int",
+       "struct you:uhpmax:int",
+       "struct you:uen:int",
+       "struct you:uenmax:int",
+       "struct you:uhpinc:xchar",
+       "struct you:ueninc:xchar",
+       "struct you:ugangr:int",
+       "struct you:ugifts:int",
+       "struct you:ublessed:int",
+       "struct you:ublesscnt:int",
+       "struct you:umoney0:long",
+       "struct you:uspare1:long",
+       "struct you:uexp:long",
+       "struct you:urexp:long",
+       "struct you:ucleansed:long",
+       "struct you:usleep:long",
+       "struct you:uinvault:int",
+       "struct you:ustuck:struct monst *",
+       "struct you:usteed:struct monst *",
+       "struct you:ugallop:long",
+       "struct you:urideturns:int",
+       "struct you:umortality:int",
+       "struct you:ugrave_arise:int",
+       "struct you:weapon_slots:int",
+       "struct you:skills_advanced:int",
+       "struct you:skill_record:xchar",
+       "struct you:weapon_skills:skills",
+       "struct you:twoweap:boolean",
+       "struct you:mcham:short",
+};
+
+int critical_members_count()
+{
+       return SIZE(critical_members);
+}
+
+/*sfdata.c*/
diff --git a/src/sflendian.c b/src/sflendian.c
new file mode 100644 (file)
index 0000000..c346b3f
--- /dev/null
@@ -0,0 +1,1313 @@
+/* NetHack 3.6 sflendian.c $NHDT-Date$  $NHDT-Branch$:$NHDT-Revision$ */
+/* Copyright (c) M. Allison, 2019. */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/* fieldlevel little-endian binary file */
+#include "hack.h"
+#include "integer.h"
+#include "sfprocs.h"
+
+/*
++------------+--------+------+-------+-----------+--------+-----------+
+| Data model | short  | int  | long  | long long | pointer|     OS    |
++------------+--------+------+-------+-----------+--------+-----------+
+|   LLP64    |   16   |  32  |   32  |     64    |   64   | Windows   |
++------------+--------+------+-------+-----------+--------+-----------+
+|    LP64    |   16   |  32  |   64  |     64    |   64   | Most Unix |
++------------+--------+------+-------+-----------+--------+-----------+
+|    ILP64   |   16   |  64  |   64  |     64    |   64   |HAL,SPARC64|
++------------+--------+------+-------+-----------+--------+-----------+
+
+  We're using this for NetHack's little-endian binary fieldlevel format
+  because it involves the fewest compromises (sorry SPARC64,
+  you'll have to use one of the text file formats instead):
+  
+  Data model | short  | int  | long  | long long | pointer|     OS    |
+     LP64    |   16   |  32  |   64  |     64    |   64   | Most Unix |
+*/
+
+#if defined(_MSC_VER)
+#include <intrin.h>
+#define bswap16(x) _byteswap_ushort(x)
+#define bswap32(x) _byteswap_ulong(x)
+#define bswap64(x) _byteswap_uint64(x)
+#elif defined(__GNUC__)
+#define bswap16(x) __builtin_bswap16(x)
+#define bswap32(x) __builtin_bswap32(x)
+#define bswap64(x) __builtin_bswap64(x)
+#else
+/* else use ais523 approach */
+# define bswap16(x)   ((((x) & 0x00ffU) << 8) | \
+                           (((x) & 0xff00U) >> 8))
+
+# define bswap32(x)   ((((x) & 0x000000ffLU) << 24) | \
+                           (((x) & 0x0000ff00LU) <<  8) | \
+                           (((x) & 0x00ff0000LU) >>  8) | \
+                           (((x) & 0xff000000LU) >> 24))
+
+# define bswap64(x)   ((((x) & 0x00000000000000ffLLU) << 56) | \
+                           (((x) & 0x000000000000ff00LLU) << 40) | \
+                           (((x) & 0x0000000000ff0000LLU) << 24) | \
+                           (((x) & 0x00000000ff000000LLU) <<  8) | \
+                           (((x) & 0x000000ff00000000LLU) <<  8) | \
+                           (((x) & 0x0000ff0000000000LLU) << 24) | \
+                           (((x) & 0x00ff000000000000LLU) << 40) | \
+                           (((x) & 0xff00000000000000LLU) << 56))
+#endif
+
+#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
+
+struct sf_procs lendian_sfo_procs = {
+    "-le",
+    {
+        lendian_sfo_aligntyp,
+        lendian_sfo_any,
+        lendian_sfo_bitfield,
+        lendian_sfo_boolean,
+        lendian_sfo_char,
+        lendian_sfo_genericptr,
+        lendian_sfo_int,
+        lendian_sfo_long,
+        lendian_sfo_schar,
+        lendian_sfo_short,
+        lendian_sfo_size_t,
+        lendian_sfo_time_t,
+        lendian_sfo_unsigned,
+        lendian_sfo_uchar,
+        lendian_sfo_uint,
+        lendian_sfo_ulong,
+        lendian_sfo_ushort,
+        lendian_sfo_xchar,
+        lendian_sfo_str,
+        lendian_sfo_addinfo,
+    }
+};
+
+struct sf_procs lendian_sfi_procs =
+{
+    "-le",
+    {
+        lendian_sfi_aligntyp,
+        lendian_sfi_any,
+        lendian_sfi_bitfield,
+        lendian_sfi_boolean,
+        lendian_sfi_char,
+        lendian_sfi_genericptr,
+        lendian_sfi_int,
+        lendian_sfi_long,
+        lendian_sfi_schar,
+        lendian_sfi_short,
+        lendian_sfi_size_t,
+        lendian_sfi_time_t,
+        lendian_sfi_unsigned,
+        lendian_sfi_uchar,
+        lendian_sfi_uint,
+        lendian_sfi_ulong,
+        lendian_sfi_ushort,
+        lendian_sfi_xchar,
+        lendian_sfi_str,
+        lendian_sfi_addinfo,
+    }
+};
+
+#ifdef SAVEFILE_DEBUGGING
+static long floc = 0L;
+#endif
+
+/*
+ *----------------------------------------------------------------------------
+ * sfo_lendian_ routines
+ *
+ * Default output routines.
+ *
+ *----------------------------------------------------------------------------
+ */
+void
+lendian_sfo_any(nhfp, d_any, myparent, myname, cnt)
+NHFILE *nhfp;
+union any *d_any;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char *parent = "any";
+    int i;
+    uint64_t ui64;
+    int64_t i64;
+    uint32_t ui32;
+    int32_t i32;
+    int8_t i8;
+    for (i = 0; i < cnt; ++i) {
+        ui64 = (uint64_t) d_any->a_void;
+        fwrite(&ui64, sizeof ui64, 1, nhfp->fpdef);
+        i64 = (int64_t) d_any->a_ulong;
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug,"%s %s %ld %ld %d\n", myname,
+                "any",
+                d_any->a_ulong, ftell(nhfp->fpdef), cnt);
+#endif
+        fwrite(&i64, sizeof i64, 1, nhfp->fpdef);
+        ui32 = (uint32_t) d_any->a_uint;
+        fwrite(&ui32, sizeof ui32, 1, nhfp->fpdef);
+        i32 = (int32_t) d_any->a_int;
+        fwrite(&i32, sizeof i32, 1, nhfp->fpdef);
+        i8 = (int8_t) d_any->a_char;
+        fwrite(&i8, sizeof i8, 1, nhfp->fpdef);
+        d_any++;
+    }
+#if 0
+    sfo_genericptr(nhfp, d_any->a_void, parent, "a_void", 1);      /* (genericptr_t)    */
+    sfo_genericptr(nhfp, d_any->a_obj, parent, "a_obj", 1);        /* (struct obj *)    */
+    sfo_genericptr(nhfp, d_any->a_monst, parent, "a_monst", 1);    /* (struct monst *)  */
+    sfo_int(nhfp, &d_any->a_int, parent, "a_int", 1);              /* (int)             */
+    sfo_char(nhfp, &d_any->a_char, parent, "a_char", 1);           /* (char)            */
+    sfo_schar(nhfp, &d_any->a_schar, parent, "a_schar", 1);        /* (schar)           */
+    sfo_uchar(nhfp, &d_any->a_uchar, parent, "a_uchar", 1);        /* (uchar)           */
+    sfo_uint(nhfp, &d_any->a_uint, parent, "a_uint", 1);           /* (unsigned int)    */
+    sfo_long(nhfp, &d_any->a_long, parent, "a_long", 1);           /* (long)            */
+    sfo_ulong(nhfp, &d_any->a_ulong, parent, "a_ulong", 1);        /* (unsigned long)   */
+    sfo_genericptr(nhfp, d_any->a_iptr, parent, "a_iptr", 1);      /* (int *)           */
+    sfo_genericptr(nhfp, d_any->a_lptr, parent, "a_lptr", 1);      /* (long *)          */
+    sfo_genericptr(nhfp, d_any->a_ulptr, parent, "a_ulptr", 1);    /* (unsigned long *) */
+    sfo_genericptr(nhfp, d_any->a_uptr, parent, "a_uptr", 1);      /* (unsigned *)      */my
+    sfo_genericptr(nhfp, d_any->a_string, parent, "a_string", 1);  /* (const char *)    */
+    sfo_ulong(nhfp, &d_any->a_mask32, parent, "a_mask32", 1);      /* (unsigned long)   */
+#endif
+}
+
+void
+lendian_sfo_aligntyp(nhfp, d_aligntyp, myparent, myname, cnt)
+NHFILE *nhfp;
+aligntyp *d_aligntyp;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "aligntyp";
+    int i;
+    int16_t val;
+
+    for (i = 0; i < cnt; ++i) {
+        val = nhfp->bendian ? bswap16(*d_aligntyp) : *d_aligntyp;
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug,"%s %s %hd %ld %d\n", myname,
+                "aligntyp",
+                val, ftell(nhfp->fpdef), cnt);
+#endif
+        fwrite(&val, sizeof val, 1, nhfp->fpdef);
+        d_aligntyp++;
+    }
+}
+
+void
+lendian_sfo_bitfield(nhfp, d_bitfield, myparent, myname, cnt)
+NHFILE *nhfp;
+uint8_t *d_bitfield;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "bitfield";
+
+    /* for bitfields, cnt is the number of bits, not an array */
+#ifdef SAVEFILE_DEBUGGING
+    fprintf(nhfp->fpdebug,"%s %s %d %ld %d\n", myname,
+            "bitfield",
+            (int) *d_bitfield, ftell(nhfp->fpdef), cnt);
+#endif
+    fwrite(d_bitfield, sizeof *d_bitfield, 1, nhfp->fpdef);
+}
+
+void
+lendian_sfo_boolean(nhfp, d_boolean, myparent, myname, cnt)
+NHFILE *nhfp;
+boolean *d_boolean;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "boolean";
+    int i;
+    int8_t val;
+
+    for (i = 0; i < cnt; ++i) {
+        val = *d_boolean;
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug,"%s %s %d %ld %d\n", myname,
+                "boolean",
+                (int) val, ftell(nhfp->fpdef), cnt);
+#endif
+        fwrite(&val, sizeof val, 1, nhfp->fpdef);
+        d_boolean++;
+    }
+}
+
+void
+lendian_sfo_char(nhfp, d_char, myparent, myname, cnt)
+NHFILE *nhfp;
+char *d_char;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    const char *parent = "char";
+    int8_t val;
+
+    for (i = 0; i < cnt; ++i) {
+        val = *d_char;
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug,"%s %s %d %ld %d\n", myname,
+                "char",
+                (int) val, ftell(nhfp->fpdef), cnt);
+#endif
+        fwrite(&val, sizeof val, 1, nhfp->fpdef);
+        d_char++;
+    }
+}
+
+void
+lendian_sfo_genericptr(nhfp, d_genericptr, myparent, myname, cnt)
+NHFILE *nhfp;
+genericptr_t *d_genericptr;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    int8_t p;
+
+    /*
+     * sbrooms is an array of pointers to mkroom.
+     * That array dimension is MAX_SUBROOMS.
+     * Even though the pointers themselves won't
+     * be valid, we need to account for the existence
+     * of the elements of that array, and whether each
+     * is zero or non-zero.
+     *
+     * We only consume a single byte in the file for that
+     * and we expand it back to pointer size later when
+     * we read it back in, again preserving zero or non-zero.
+     */
+
+    for (i = 0; i < cnt; ++i) {
+        p = (*d_genericptr) ? 1 : 0;
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug,"%s %s %d %ld %d\n", myname,
+                "genericptr",
+                (int) p, ftell(nhfp->fpdef), cnt);
+#endif
+        fwrite(&p, sizeof p, 1, nhfp->fpdef);
+        d_genericptr++;
+    }
+}
+
+void
+lendian_sfo_int(nhfp, d_int, myparent, myname, cnt)
+NHFILE *nhfp;
+int *d_int;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    const char *parent = "int";
+    int32_t i32, val;
+
+    for (i = 0; i < cnt; ++i) {
+        i32 = (int32_t) *d_int;
+        val = nhfp->bendian ? bswap32(i32) : i32;
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug,"%s %s %d %ld %d\n", myname,
+                "int",
+                val, ftell(nhfp->fpdef), cnt);
+#endif
+        fwrite(&val, sizeof val, 1, nhfp->fpdef);
+        d_int++;
+    }
+}
+
+void
+lendian_sfo_long(nhfp, d_long, myparent, myname, cnt)
+NHFILE *nhfp;
+long *d_long;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    const char *parent = "long";
+    int64_t i64, val64;
+
+    for (i = 0; i < cnt; ++i) {
+        i64 = (int64_t) *d_long;
+        val64 = nhfp->bendian ? bswap64(i64) : i64;
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug, DEBUGFORMATSTR64, myname,
+                "long",
+                val64, ftell(nhfp->fpdef), cnt);
+#endif
+        fwrite(&val64, sizeof val64, 1, nhfp->fpdef);
+        d_long++;
+    }
+}
+
+void
+lendian_sfo_schar(nhfp, d_schar, myparent, myname, cnt)
+NHFILE *nhfp;
+schar *d_schar;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    int8_t itmp;
+    const char *parent = "schar";
+
+    for (i = 0; i < cnt; ++i) {
+        itmp = (int8_t) *d_schar;
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug,"%s %s %d %ld %d\n", myname,
+                "schar",
+                (int) itmp, ftell(nhfp->fpdef), cnt);
+#endif
+        fwrite(&itmp, sizeof itmp, 1, nhfp->fpdef);
+        d_schar++;
+    }
+}
+
+void
+lendian_sfo_short(nhfp, d_short, myparent, myname, cnt)
+NHFILE *nhfp;
+short *d_short;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    int16_t itmp;
+    const char *parent = "short";
+
+    for (i = 0; i < cnt; ++i) {
+        itmp = (int16_t) *d_short;
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug,"%s %s %hd %ld %d\n", myname,
+                "short",
+                itmp, ftell(nhfp->fpdef), cnt);
+#endif
+        fwrite(&itmp, sizeof itmp, 1, nhfp->fpdef);
+        d_short++;
+    }
+}
+
+void
+lendian_sfo_size_t(nhfp, d_size_t, myparent, myname, cnt)
+NHFILE *nhfp;
+size_t *d_size_t;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    uint64_t ui64, val;
+    const char *parent = "size_t";
+
+    for (i = 0; i < cnt; ++i) {
+        ui64 = (uint64_t) *d_size_t;
+        val = nhfp->bendian ? bswap64(ui64) : ui64;
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug, DEBUGFORMATSTR64, myname,
+                "size_t",
+                val, ftell(nhfp->fpdef), cnt);
+#endif
+        fwrite(&val, sizeof val, 1, nhfp->fpdef);
+        d_size_t++;
+    }
+}
+
+void
+lendian_sfo_time_t(nhfp, d_time_t, myparent, myname, cnt)
+NHFILE *nhfp;
+time_t *d_time_t;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    char buf[BUFSZ];
+    const char *parent = "time_t";
+
+    Sprintf(buf, "%s", yyyymmddhhmmss(*d_time_t));
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug,"%s %s %s %ld %d\n", myname,
+                "time",
+                buf, ftell(nhfp->fpdef), cnt);
+#endif
+    fwrite(buf, sizeof (char), 15, nhfp->fpdef);
+}
+
+void
+lendian_sfo_unsigned(nhfp, d_unsigned, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned *d_unsigned;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    lendian_sfo_uint(nhfp, d_unsigned, myparent, myname, cnt);
+}
+
+void
+lendian_sfo_uchar(nhfp, d_uchar, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned char *d_uchar;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    const char *parent = "uchar";
+    uint8_t ui8;
+    for (i = 0; i < cnt; ++i) {
+        ui8 = (uint8_t) *d_uchar;
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug,"%s %s %u %ld %d\n", myname,
+                "uchar",
+                (unsigned int) ui8, ftell(nhfp->fpdef), cnt);
+#endif
+        fwrite(&ui8, sizeof ui8, 1, nhfp->fpdef);
+        d_uchar++;
+    }
+}
+
+void
+lendian_sfo_uint(nhfp, d_uint, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned int *d_uint;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    const char *parent = "uint";
+    uint32_t ui32, val;
+    
+    for (i = 0; i < cnt; ++i) {
+        ui32 = (uint32_t) *d_uint;
+        val = nhfp->bendian ? bswap32(ui32) : ui32;
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug,"%s %s %u %ld %d\n", myname,
+                "uint",
+                val, ftell(nhfp->fpdef), cnt);
+#endif
+        fwrite(&val, sizeof val, 1, nhfp->fpdef);
+        d_uint++;
+    }
+}
+
+void
+lendian_sfo_ulong(nhfp, d_ulong, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned long *d_ulong;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    const char *parent = "ulong";
+    uint64_t ul64, val64;
+
+    for (i = 0; i < cnt; ++i) {
+        ul64 = (uint64_t) *d_ulong;
+        val64 = nhfp->bendian ? bswap64(ul64) : ul64;
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug, DEBUGFORMATSTR64, myname,
+                "ulong",
+                val64, ftell(nhfp->fpdef), cnt);
+#endif
+        fwrite(&val64, sizeof val64, 1, nhfp->fpdef);
+        d_ulong++;
+    }
+}
+
+void
+lendian_sfo_ushort(nhfp, d_ushort, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned short *d_ushort;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    const char *parent = "ushort";
+    uint16_t ui16, val16;
+
+    for (i = 0; i < cnt; ++i) {
+        ui16 = (uint16_t) *d_ushort;
+        val16 = nhfp->bendian ? bswap16(ui16) : ui16;
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug,"%s %s %hd %ld %d\n", myname,
+                "ushort",
+                val16, ftell(nhfp->fpdef), cnt);
+#endif
+        fwrite(&val16, sizeof val16, 1, nhfp->fpdef);
+        d_ushort++;
+    }
+}
+
+void
+lendian_sfo_xchar(nhfp, d_xchar, myparent, myname, cnt)
+NHFILE *nhfp;
+xchar *d_xchar;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    const char *parent = "xchar";
+    int16_t i16, val16;
+
+    for (i = 0; i < cnt; ++i) {
+        i16 = (int16_t) *d_xchar;
+        val16 = nhfp->bendian ? bswap16(i16) : i16;
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug,"%s %s %hd %ld %d\n", myname,
+                "xchar",
+                val16, ftell(nhfp->fpdef), cnt);
+#endif
+        fwrite(&val16, sizeof val16, 1, nhfp->fpdef);
+        d_xchar++;
+    }
+}
+
+static char strbuf[BUFSZ * 4];
+
+void
+lendian_sfo_str(nhfp, d_str, myparent, myname, cnt)
+NHFILE *nhfp;
+char *d_str;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i, j, intval;
+    int16_t i16, outcount = 0;
+    const char *parent = "str";
+    char sval[QBUFSZ], *src = d_str, *dest = strbuf;
+
+    /* cnt is the number of characters */
+    for (i = 0; i < cnt; ++i) {
+        if ((*src < 32) || (*src == '\\') || (*src > 128)) {
+            *dest++ = '\\';
+            outcount++;
+            intval = (int) *src++;
+            Sprintf(sval, "%03d", intval);
+            for (j = 0; j < 3; ++j) {
+                *dest++ = sval[j];
+                outcount++;
+            }
+        } else {
+            *dest++ = *src++;
+            outcount++;
+        }
+    }
+    *dest = '\0';
+    i16 = nhfp->bendian ? bswap16(outcount) : outcount;
+#ifdef SAVEFILE_DEBUGGING
+    fprintf(nhfp->fpdebug,"%s %s %hd %ld %d\n", myname,
+            "str-count",
+            i16, ftell(nhfp->fpdef), cnt);
+#endif
+    fwrite(&i16, sizeof i16, 1, nhfp->fpdef);
+#ifdef SAVEFILE_DEBUGGING
+    fprintf(nhfp->fpdebug,"%s %s %s %ld %d\n", myname,
+            "str",
+            strbuf, ftell(nhfp->fpdef), cnt);
+#endif
+    fwrite(strbuf, sizeof (char), outcount, nhfp->fpdef);
+}
+
+void
+lendian_sfo_addinfo(nhfp, parent, action, myname, index)
+NHFILE *nhfp;
+const char *parent, *action, *myname;
+int index;
+{
+    /* ignored */
+}
+
+
+/*
+ *----------------------------------------------------------------------------
+ * lendian_sfi_ routines called from functions in sfi_base.c
+ *----------------------------------------------------------------------------
+ */
+void
+lendian_sfi_any(nhfp, d_any, myparent, myname, cnt)
+NHFILE *nhfp;
+union any *d_any;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "any";
+    int i;
+    uint64_t ui64;
+    int64_t i64;
+    uint32_t ui32;
+    int32_t i32;
+    int8_t i8;
+    for (i = 0; i < cnt; ++i) {
+        fread(&ui64, sizeof ui64, 1, nhfp->fpdef);
+        if (feof(nhfp->fpdef)) {
+            nhfp->eof = TRUE;
+            return;
+       }
+#ifdef SAVEFILE_DEBUGGING
+        floc = ftell(nhfp->fpdef);
+#endif
+        fread(&i64, sizeof i64, 1, nhfp->fpdef);
+        if (feof(nhfp->fpdef)) {
+            nhfp->eof = TRUE;
+            return;
+       }
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug, DEBUGFORMATSTR64, myname,
+                "any",
+                ui64, floc, cnt);
+#endif
+        fread(&ui32, sizeof ui32, 1, nhfp->fpdef);
+        if (feof(nhfp->fpdef)) {
+            nhfp->eof = TRUE;
+            return;
+       }
+        fread(&i32, sizeof i32, 1, nhfp->fpdef);
+        if (feof(nhfp->fpdef)) {
+            nhfp->eof = TRUE;
+            return;
+       }
+        fread(&i8, sizeof i8, 1, nhfp->fpdef);
+        if (feof(nhfp->fpdef)) {
+            nhfp->eof = TRUE;
+            return;
+       }
+        d_any->a_void = (genericptr_t) ui64;
+        d_any->a_ulong = (unsigned long) i64;
+        d_any->a_uint = (unsigned int) ui32;
+        d_any->a_int = (int) i32;
+        d_any->a_char = (char) i8;
+        d_any++;
+    }
+#if 0
+    sfi_genericptr(nhfp, d_any->a_void, parent, "a_void", 1);
+    sfi_genericptr(nhfp, d_any->a_obj, parent, "a_obj", 1);
+    sfi_genericptr(nhfp, d_any->a_monst, parent, "a_monst", 1);
+    sfi_int(nhfp, &d_any->a_int, parent, "a_int", 1);
+    sfi_char(nhfp, &d_any->a_char, parent, "a_char", 1);
+    sfi_schar(nhfp, &d_any->a_schar, parent, "a_schar", 1);
+    sfi_uchar(nhfp, &d_any->a_uchar, parent, "a_uchar", 1);
+    sfi_uint(nhfp, &d_any->a_uint, parent, "a_uint", 1);
+    sfi_long(nhfp, &d_any->a_long, parent, "a_long", 1);
+    sfi_ulong(nhfp, &d_any->a_ulong, parent, "a_ulong", 1);
+    sfi_genericptr(nhfp, d_any->a_iptr, parent, "a_iptr", 1);
+    sfi_genericptr(nhfp, d_any->a_lptr, parent, "a_lptr", 1);
+    sfi_genericptr(nhfp, d_any->a_ulptr, parent, "a_ulptr", 1);
+    sfi_genericptr(nhfp, d_any->a_uptr, parent, "a_uptr", 1);
+    sfi_genericptr(nhfp, d_any->a_string, parent, "a_string", 1);
+    sfi_ulong(nhfp, &d_any->a_mask32, parent, "a_mask32", 1);
+#endif
+}
+
+void
+lendian_sfi_aligntyp(nhfp, d_aligntyp, myparent, myname, cnt)
+NHFILE *nhfp;
+aligntyp *d_aligntyp;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "aligntyp";
+    int i;
+    int16_t val, i16;
+
+    for (i = 0; i < cnt; ++i) {
+#ifdef SAVEFILE_DEBUGGING
+        floc = ftell(nhfp->fpdef);
+#endif
+        fread(&val, sizeof val, 1, nhfp->fpdef);
+        if (feof(nhfp->fpdef)) {
+            nhfp->eof = TRUE;
+            return;
+       }
+        i16 = nhfp->bendian ? bswap16(val) : val;
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug,"%s %s %hd %ld %d\n", myname,
+                "aligntyp",
+                i16, floc, cnt);
+#endif
+        *d_aligntyp = (aligntyp) i16;
+        d_aligntyp++;
+    }
+}
+
+void
+lendian_sfi_bitfield(nhfp, d_bitfield, myparent, myname, cnt)
+NHFILE *nhfp;
+uint8_t *d_bitfield;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    const char *parent = "bitfield";
+
+#ifdef SAVEFILE_DEBUGGING
+    floc = ftell(nhfp->fpdef);
+#endif
+    fread(d_bitfield, sizeof *d_bitfield, 1, nhfp->fpdef);
+    if (feof(nhfp->fpdef)) {
+        nhfp->eof = TRUE;
+        return;
+    }
+#ifdef SAVEFILE_DEBUGGING
+    fprintf(nhfp->fpdebug,"%s %s %d %ld %d\n", myname,
+            "bitfield",
+            (int) *d_bitfield, floc, cnt);
+#endif
+}
+
+void
+lendian_sfi_boolean(nhfp, d_boolean, myparent, myname, cnt)
+NHFILE *nhfp;
+boolean *d_boolean;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    const char *parent = "boolean";
+    int8_t i8;
+
+    for (i = 0; i < cnt; ++i) {
+#ifdef SAVEFILE_DEBUGGING
+        floc = ftell(nhfp->fpdef);
+#endif
+        fread(&i8, sizeof i8, 1, nhfp->fpdef);
+        if (feof(nhfp->fpdef)) {
+            nhfp->eof = TRUE;
+            return;
+        }
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug,"%s %s %d %ld %d\n", myname,
+                "boolean",
+                (int) i8, floc, cnt);
+#endif
+        *d_boolean = (boolean) i8;
+        d_boolean++;
+    }
+}
+
+void
+lendian_sfi_char(nhfp, d_char, myparent, myname, cnt)
+NHFILE *nhfp;
+char *d_char;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    int8_t i8;
+    const char *parent = "char";
+
+    for (i = 0; i < cnt; ++i) {
+#ifdef SAVEFILE_DEBUGGING
+        floc = ftell(nhfp->fpdef);
+#endif
+        fread(&i8, sizeof i8, 1, nhfp->fpdef);
+        if (feof(nhfp->fpdef)) {
+            nhfp->eof = TRUE;
+            return;
+        }
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug,"%s %s %d %ld %d\n", myname,
+                "char",
+                (int) i8, floc, cnt);
+#endif
+        *d_char = (char) i8;
+        d_char++;
+    }
+}
+
+void
+lendian_sfi_genericptr(nhfp, d_genericptr, myparent, myname, cnt)
+NHFILE *nhfp;
+genericptr_t *d_genericptr;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    static char *glorkum = "glorkum";
+    int8_t p;
+
+    for (i = 0; i < cnt; ++i) {
+#ifdef SAVEFILE_DEBUGGING
+        floc = ftell(nhfp->fpdef);
+#endif
+        fread(&p, sizeof p, 1, nhfp->fpdef);
+        if (feof(nhfp->fpdef)) {
+            nhfp->eof = TRUE;
+            return;
+        }
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug,"%s %s %d %ld %d\n", myname,
+                "genericptr",
+                (int) p, floc, cnt);
+#endif
+        *d_genericptr = p ? (genericptr_t) glorkum  : (genericptr_t) 0;
+        d_genericptr++;
+    }
+}
+
+void
+lendian_sfi_int(nhfp, d_int, myparent, myname, cnt)
+NHFILE *nhfp;
+int *d_int;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    int32_t val, i32;
+
+    for (i = 0; i < cnt; ++i) {
+#ifdef SAVEFILE_DEBUGGING
+        floc = ftell(nhfp->fpdef);
+#endif
+        fread(&val, sizeof val, 1, nhfp->fpdef);
+        if (feof(nhfp->fpdef)) {
+            nhfp->eof = TRUE;
+            return;
+        }
+        i32 = nhfp->bendian ? bswap32(val) : val;
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug,"%s %s %d %ld %d\n", myname,
+                "int",
+                i32, floc, cnt);
+#endif
+        *d_int = (int) i32;
+        d_int++;
+    }
+}
+
+void
+lendian_sfi_long(nhfp, d_long, myparent, myname, cnt)
+NHFILE *nhfp;
+long *d_long;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    int64_t val64, i64;
+
+    for (i = 0; i < cnt; ++i) {
+#ifdef SAVEFILE_DEBUGGING
+        floc = ftell(nhfp->fpdef);
+#endif
+        fread(&val64, sizeof val64, 1, nhfp->fpdef);
+        if (feof(nhfp->fpdef)) {
+            nhfp->eof = TRUE;
+            return;
+        }
+        i64 = nhfp->bendian ? bswap64(val64) : val64;
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug, DEBUGFORMATSTR64, myname,
+                "long",
+                i64, floc, cnt);
+#endif
+        *d_long = (long) i64;
+        d_long++;
+    }
+}
+
+void
+lendian_sfi_schar(nhfp, d_schar, myparent, myname, cnt)
+NHFILE *nhfp;
+schar *d_schar;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    int8_t i8;
+
+    for (i = 0; i < cnt; ++i) {
+#ifdef SAVEFILE_DEBUGGING
+        floc = ftell(nhfp->fpdef);
+#endif
+        fread(&i8, sizeof i8, 1, nhfp->fpdef);
+        if (feof(nhfp->fpdef)) {
+            nhfp->eof = TRUE;
+            return;
+        }
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug,"%s %s %d %ld %d\n", myname, 
+                "schar",
+                (int) i8, floc, cnt);
+#endif
+        *d_schar = (schar) i8;
+        d_schar++;
+    }
+}
+
+void
+lendian_sfi_short(nhfp, d_short, myparent, myname, cnt)
+NHFILE *nhfp;
+short *d_short;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    int16_t val16, i16;
+
+    for (i = 0; i < cnt; ++i) {
+#ifdef SAVEFILE_DEBUGGING
+        floc = ftell(nhfp->fpdef);
+#endif
+        fread(&val16, sizeof val16, 1, nhfp->fpdef);
+        if (feof(nhfp->fpdef)) {
+            nhfp->eof = TRUE;
+            return;
+        }
+        i16 = nhfp->bendian ? bswap16(val16) : val16;
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug,"%s %s %hd %ld %d\n", myname,
+                "short",
+                i16, floc, cnt);
+#endif
+        *d_short = (short) i16;
+        d_short++;
+    }
+}
+
+void
+lendian_sfi_size_t(nhfp, d_size_t, myparent, myname, cnt)
+NHFILE *nhfp;
+size_t *d_size_t;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    uint64_t ui64, val;
+    const char *parent = "size_t";
+
+    for (i = 0; i < cnt; ++i) {
+#ifdef SAVEFILE_DEBUGGING
+        floc = ftell(nhfp->fpdef);
+#endif
+        fread(&val, sizeof val, 1, nhfp->fpdef);
+        if (feof(nhfp->fpdef)) {
+            nhfp->eof = TRUE;
+            return;
+        }
+        ui64 = nhfp->bendian ? bswap64(val) : val;
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug, DEBUGFORMATSTR64, myname,
+                "size_t",
+                ui64, floc, cnt);
+#endif
+        *d_size_t = (size_t) ui64;
+        d_size_t++;
+    }
+}
+
+void
+lendian_sfi_time_t(nhfp, d_time_t, myparent, myname, cnt)
+NHFILE *nhfp;
+time_t *d_time_t;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    time_t tmp;
+    char buf[BUFSZ];
+    const char *parent = "time_t";
+
+#ifdef SAVEFILE_DEBUGGING
+    floc = ftell(nhfp->fpdef);
+#endif
+    fread(buf, 1, 15, nhfp->fpdef);
+        if (feof(nhfp->fpdef)) {
+            nhfp->eof = TRUE;
+            return;
+        }
+#ifdef SAVEFILE_DEBUGGING
+    fprintf(nhfp->fpdebug,"%s %s %s %ld %d\n", myname, 
+            "time",
+            buf, floc, cnt);
+#endif
+    tmp = time_from_yyyymmddhhmmss(buf);
+    *d_time_t = tmp;
+}
+
+void
+lendian_sfi_unsigned(nhfp, d_unsigned, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned *d_unsigned;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    /* deferal */
+    lendian_sfi_uint(nhfp, d_unsigned, myparent, myname, cnt);
+}
+
+void
+lendian_sfi_uchar(nhfp, d_uchar, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned char *d_uchar;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    uint8_t ui8;
+
+    for (i = 0; i < cnt; ++i) {
+#ifdef SAVEFILE_DEBUGGING
+        floc = ftell(nhfp->fpdef);
+#endif
+        fread(&ui8, sizeof ui8, 1, nhfp->fpdef);
+        if (feof(nhfp->fpdef)) {
+            nhfp->eof = TRUE;
+            return;
+        }
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug,"%s %s %hu %ld %d\n", myname,
+                "uchar",
+                (unsigned short) ui8, floc, cnt);
+#endif
+        *d_uchar = (uchar) ui8;
+        d_uchar++;
+    }
+}
+
+void
+lendian_sfi_uint(nhfp, d_uint, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned int *d_uint;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    uint32_t val, ui32;
+
+    for (i = 0; i < cnt; ++i) {
+#ifdef SAVEFILE_DEBUGGING
+        floc = ftell(nhfp->fpdef);
+#endif
+        fread(&val, sizeof val, 1, nhfp->fpdef);
+        if (feof(nhfp->fpdef)) {
+            nhfp->eof = TRUE;
+            return;
+        }
+        ui32 = nhfp->bendian ? bswap32(val) : val;
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug,"%s %s %u %ld %d\n", myname, 
+                "uint",
+                ui32, floc, cnt);
+#endif
+        *d_uint = (unsigned int) ui32;
+        d_uint++;
+    }
+}
+
+void
+lendian_sfi_ulong(nhfp, d_ulong, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned long *d_ulong;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    uint64_t val64, ui64;
+
+    for (i = 0; i < cnt; ++i) {
+#ifdef SAVEFILE_DEBUGGING
+        floc = ftell(nhfp->fpdef);
+#endif
+        fread(&val64, sizeof val64, 1, nhfp->fpdef);
+        if (feof(nhfp->fpdef)) {
+            nhfp->eof = TRUE;
+            return;
+        }
+        ui64 = nhfp->bendian ? bswap64(val64) : val64;
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug, DEBUGFORMATSTR64, myname,
+                "ulong",
+                ui64, floc, cnt);
+#endif
+        *d_ulong = (unsigned long) ui64;
+        d_ulong++;
+    }
+}
+
+void
+lendian_sfi_ushort(nhfp, d_ushort, myparent, myname, cnt)
+NHFILE *nhfp;
+unsigned short *d_ushort;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    uint16_t val16, ui16;
+
+    for (i = 0; i < cnt; ++i) {
+#ifdef SAVEFILE_DEBUGGING
+        floc = ftell(nhfp->fpdef);
+#endif
+        fread(&val16, sizeof val16, 1, nhfp->fpdef);
+        if (feof(nhfp->fpdef)) {
+            nhfp->eof = TRUE;
+            return;
+        }
+        ui16 = nhfp->bendian ? bswap16(val16) : val16;
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug,"%s %s %hu %ld %d\n", myname,
+                "ushort",
+                ui16, floc, cnt);
+#endif
+        *d_ushort = (unsigned short) ui16;
+        d_ushort++;
+    }
+}
+
+void
+lendian_sfi_xchar(nhfp, d_xchar, myparent, myname, cnt)
+NHFILE *nhfp;
+xchar *d_xchar;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+    int i;
+    int16_t val16, i16;
+
+    for (i = 0; i < cnt; ++i) {
+#ifdef SAVEFILE_DEBUGGING
+        floc = ftell(nhfp->fpdef);
+#endif
+        fread(&val16, sizeof val16, 1, nhfp->fpdef);
+        if (feof(nhfp->fpdef)) {
+            nhfp->eof = TRUE;
+            return;
+        }
+        i16 = nhfp->bendian ? bswap16(val16) : val16;
+#ifdef SAVEFILE_DEBUGGING
+        fprintf(nhfp->fpdebug,"%s %s %hd %ld %d\n", myname,
+                "xchar",
+                i16, floc, cnt);
+#endif
+        *d_xchar = (xchar) i16;
+        d_xchar++;
+    }
+}
+
+static char strbuf[BUFSZ * 4];
+
+void
+lendian_sfi_str(nhfp, d_str, myparent, myname, cnt)
+NHFILE *nhfp;
+char *d_str;
+const char *myparent;
+const char *myname;
+int cnt;
+{
+#ifdef SAVEFILE_DEBUGGING
+    char testbuf[BUFSZ];
+#endif
+    int i, j, sval;
+    const char *parent = "str";
+    char n[4];
+    char *src, *dest;
+    int16_t i16, incount = 0;
+
+#ifdef SAVEFILE_DEBUGGING
+    floc = ftell(nhfp->fpdef);
+#endif
+    fread(&i16, sizeof i16, 1, nhfp->fpdef);
+    if (feof(nhfp->fpdef)) {
+        nhfp->eof = TRUE;
+        return;
+    }
+    incount = nhfp->bendian ? bswap16(i16) : i16;
+#ifdef SAVEFILE_DEBUGGING
+    fprintf(nhfp->fpdebug,"%s %s %hd %ld %d\n", myname,
+            "str-count",
+            incount, floc, cnt);
+#endif
+    if (incount >= (BUFSZ * 4) - 1)
+        panic("overflow on sflendian string read %d %d",
+                    incount, cnt);
+#ifdef SAVEFILE_DEBUGGING
+    floc = ftell(nhfp->fpdef);
+#endif
+    fread(strbuf, sizeof (char), incount, nhfp->fpdef);
+    if (feof(nhfp->fpdef)) {
+        nhfp->eof = TRUE;
+        return;
+    }
+    strbuf[incount] = '\0';
+#ifdef SAVEFILE_DEBUGGING
+    fprintf(nhfp->fpdebug,"%s %s %s %ld %d\n", myname,
+                "str",
+                strbuf, floc, cnt);
+#endif
+    src = strbuf;
+    dest =
+#ifdef SAVEFILE_DEBUGGING
+            testbuf;
+#else
+            d_str;
+#endif
+
+    for (i = 0; i < cnt; ++i) {
+        if (*src == '\\') {
+            src++;
+            for (j = 0; j < 4; ++j) {
+                if (j < 3)
+                    n[j] = *src++;
+                else
+                    n[j] = '\0';
+           }
+            sval = atoi(n);
+            *dest++ = (char) sval;
+        } else
+            *dest++ = *src++;
+    }
+}
+void
+lendian_sfi_addinfo(nhfp, myparent, action, myname, index)
+NHFILE *nhfp;
+const char *myparent, *action, *myname;
+int index;
+{
+    /* not doing anything here */
+}
+
+
+
index 19e2cd24ef99ed9e67d14ea61b0a40fe2728a9b5..cce71f3cb105a8440bd77ffaa5e363b109d6deb4 100644 (file)
@@ -6032,7 +6032,7 @@ const char *name;
     if (!fd)
         return FALSE;
     Fread((genericptr_t) &vers_info, sizeof vers_info, 1, fd);
-    if (!check_version(&vers_info, name, TRUE)) {
+    if (!check_version(&vers_info, name, TRUE, UTD_CHECKSIZES)) {
         (void) dlb_fclose(fd);
         goto give_up;
     }
index 05f14fa9284bc835fd4ba364b6ad8e6c9fa3429f..5bf7084d380a3d07175568ec0c65c3b56e392607 100644 (file)
@@ -5,6 +5,8 @@
 
 #include "hack.h"
 #include "lev.h" /* for checking save modes */
+#include "sfproto.h"
+
 
 STATIC_DCL void NDECL(stoned_dialogue);
 STATIC_DCL void NDECL(vomiting_dialogue);
@@ -1631,13 +1633,13 @@ do_storms()
  *      Call timers that have timed out.
  *
  * Save/Restore:
- *  void save_timers(int fd, int mode, int range)
+ *  void save_timers(NHFILE *, int range)
  *      Save all timers of range 'range'.  Range is either global
  *      or local.  Global timers follow game play, local timers
  *      are saved with a level.  Object and monster timers are
  *      saved using their respective id's instead of pointers.
  *
- *  void restore_timers(int fd, int range, boolean ghostly, long adjust)
+ *  void restore_timers(NHFILE *, int range, boolean ghostly, long adjust)
  *      Restore timers of range 'range'.  If from a ghost pile,
  *      adjust the timeout by 'adjust'.  The object and monster
  *      ids are not restored until later.
@@ -1665,10 +1667,10 @@ STATIC_DCL void FDECL(print_queue, (winid, timer_element *));
 STATIC_DCL void FDECL(insert_timer, (timer_element *));
 STATIC_DCL timer_element *FDECL(remove_timer,
                                 (timer_element **, SHORT_P, ANY_P *));
-STATIC_DCL void FDECL(write_timer, (int, timer_element *));
+STATIC_DCL void FDECL(write_timer, (NHFILE *, timer_element *));
 STATIC_DCL boolean FDECL(mon_is_local, (struct monst *));
 STATIC_DCL boolean FDECL(timer_is_local, (timer_element *));
-STATIC_DCL int FDECL(maybe_write_timer, (int, int, BOOLEAN_P));
+STATIC_DCL int FDECL(maybe_write_timer, (NHFILE *, int, BOOLEAN_P));
 
 /* If defined, then include names when printing out the timer queue */
 #define VERBOSE_TIMER
@@ -2110,8 +2112,8 @@ anything *arg;
 }
 
 STATIC_OVL void
-write_timer(fd, timer)
-int fd;
+write_timer(nhfp, timer)
+NHFILE *nhfp;
 timer_element *timer;
 {
     anything arg_save;
@@ -2121,34 +2123,49 @@ timer_element *timer;
     case TIMER_GLOBAL:
     case TIMER_LEVEL:
         /* assume no pointers in arg */
-        bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) timer, sizeof(timer_element));
+        if (nhfp->fieldlevel)
+            sfo_fe(nhfp, timer, "timers", "timer", 1);
         break;
 
     case TIMER_OBJECT:
-        if (timer->needs_fixup)
-            bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
-        else {
+        if (timer->needs_fixup) {
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t)timer, sizeof(timer_element));
+            if (nhfp->fieldlevel)
+                sfo_fe(nhfp, timer, "timers", "timer", 1);
+        } 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;
-            bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t)timer, sizeof(timer_element));
+            if (nhfp->fieldlevel)
+                sfo_fe(nhfp, timer, "timers", "timer", 1);
             timer->arg.a_obj = arg_save.a_obj;
             timer->needs_fixup = 0;
         }
         break;
 
     case TIMER_MONSTER:
-        if (timer->needs_fixup)
-            bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
-        else {
+        if (timer->needs_fixup) {
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t)timer, sizeof(timer_element));
+            if (nhfp->fieldlevel)
+                sfo_fe(nhfp, timer, "timers", "timer", 1);
+        } 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;
-            bwrite(fd, (genericptr_t) timer, sizeof(timer_element));
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t)timer, sizeof(timer_element));
+            if (nhfp->fieldlevel)
+                sfo_fe(nhfp, timer, "timers", "timer", 1);
             timer->arg.a_monst = arg_save.a_monst;
             timer->needs_fixup = 0;
         }
@@ -2231,8 +2248,9 @@ timer_element *timer;
  * be written.  If write_it is true, actually write the timer.
  */
 STATIC_OVL int
-maybe_write_timer(fd, range, write_it)
-int fd, range;
+maybe_write_timer(nhfp, range, write_it)
+NHFILE *nhfp;
+int range;
 boolean write_it;
 {
     int count = 0;
@@ -2244,17 +2262,14 @@ boolean write_it;
 
             if (!timer_is_local(curr)) {
                 count++;
-                if (write_it)
-                    write_timer(fd, curr);
+                if (write_it) write_timer(nhfp, curr);
             }
-
         } else {
             /* local timers */
 
             if (timer_is_local(curr)) {
                 count++;
-                if (write_it)
-                    write_timer(fd, curr);
+                if (write_it) write_timer(nhfp, curr);
             }
         }
     }
@@ -2262,6 +2277,7 @@ boolean write_it;
     return count;
 }
 
+
 /*
  * Save part of the timer list.  The parameter 'range' specifies either
  * global or level timers to save.  The timer ID is saved with the global
@@ -2276,22 +2292,29 @@ boolean write_it;
  *      + timeouts that stay with the level (obj & monst)
  */
 void
-save_timers(fd, mode, range)
-int fd, mode, range;
+save_timers(nhfp, range)
+NHFILE *nhfp;
+int range;
 {
     timer_element *curr, *prev, *next_timer = 0;
     int count;
 
-    if (perform_bwrite(mode)) {
-        if (range == RANGE_GLOBAL)
-            bwrite(fd, (genericptr_t) &g.timer_id, sizeof(g.timer_id));
-
-        count = maybe_write_timer(fd, range, FALSE);
-        bwrite(fd, (genericptr_t) &count, sizeof count);
-        (void) maybe_write_timer(fd, range, TRUE);
+    if (perform_bwrite(nhfp)) {
+        if (range == RANGE_GLOBAL) {
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t) &g.timer_id, sizeof(g.timer_id));
+            if (nhfp->fieldlevel)
+                sfo_ulong(nhfp, &g.timer_id, "timers", "g.timer_id", 1);
+        }
+        count = maybe_write_timer(nhfp, range, FALSE);
+        if (nhfp->structlevel)
+            bwrite(nhfp->fd, (genericptr_t) &count, sizeof count);
+        if (nhfp->fieldlevel)
+            sfo_int(nhfp, &count, "timers", "timer_count", 1);
+        (void) maybe_write_timer(nhfp, range, TRUE);
     }
 
-    if (release_data(mode)) {
+    if (release_data(nhfp)) {
         for (prev = 0, curr = g.timer_base; curr; curr = next_timer) {
             next_timer = curr->next; /* in case curr is removed */
 
@@ -2314,22 +2337,34 @@ int fd, mode, range;
  * monster pointers.
  */
 void
-restore_timers(fd, range, ghostly, adjust)
-int fd, range;
+restore_timers(nhfp, range, ghostly, adjust)
+NHFILE *nhfp;
+int range;
 boolean ghostly; /* restoring from a ghost level */
 long adjust;     /* how much to adjust timeout */
 {
     int count;
     timer_element *curr;
 
-    if (range == RANGE_GLOBAL)
-        mread(fd, (genericptr_t) &g.timer_id, sizeof g.timer_id);
+    if (range == RANGE_GLOBAL) {
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) &g.timer_id, sizeof g.timer_id);
+        if (nhfp->fieldlevel)
+            sfi_ulong(nhfp, &g.timer_id, "timers", "g.timer_id", 1);
+    }
 
     /* restore elements */
-    mread(fd, (genericptr_t) &count, sizeof count);
+    if (nhfp->structlevel)
+        mread(nhfp->fd, (genericptr_t) &count, sizeof count);
+    if (nhfp->fieldlevel)
+        sfi_int(nhfp, &count, "timers", "timer_count", 1);
+       
     while (count-- > 0) {
         curr = (timer_element *) alloc(sizeof(timer_element));
-        mread(fd, (genericptr_t) curr, sizeof(timer_element));
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) curr, sizeof(timer_element));
+        if (nhfp->fieldlevel)
+            sfi_fe(nhfp, curr, "timers", "timer", 1);
         if (ghostly)
             curr->timeout += adjust;
         insert_timer(curr);
index 468aae71123a49637c7d617b8e306a674741df6e..b42882fa8a85d2abda030675dacf059733a12b83 100644 (file)
@@ -6,6 +6,10 @@
 #include "hack.h"
 #include "dlb.h"
 #include "date.h"
+#include "lev.h"
+#include "sfproto.h"
+
+
 /*
  * All the references to the contents of patchlevel.h have been moved
  * into makedefs....
@@ -250,10 +254,11 @@ long filetime;
 #endif
 
 boolean
-check_version(version_data, filename, complain)
+check_version(version_data, filename, complain, utdflags)
 struct version_info *version_data;
 const char *filename;
 boolean complain;
+unsigned long utdflags;
 {
     if (
 #ifdef VERSION_COMPATIBILITY
@@ -273,9 +278,12 @@ boolean complain;
         (version_data->feature_set & ~IGNORED_FEATURES)
             != (VERSION_FEATURES & ~IGNORED_FEATURES)
 #endif
-        || version_data->entity_count != VERSION_SANITY1
-        || version_data->struct_sizes1 != VERSION_SANITY2
-        || version_data->struct_sizes2 != VERSION_SANITY3) {
+        || ((utdflags & UTD_SKIP_SANITY1) == 0
+             && version_data->entity_count != VERSION_SANITY1)
+        || ((utdflags & UTD_CHECKSIZES) &&
+            (version_data->struct_sizes1 != VERSION_SANITY2))
+        || ((utdflags & UTD_CHECKSIZES) &&
+            (version_data->struct_sizes2 != VERSION_SANITY3))) {
         if (complain)
             pline("Configuration incompatibility for file \"%s\".", filename);
         return FALSE;
@@ -286,24 +294,47 @@ boolean complain;
 /* this used to be based on file date and somewhat OS-dependant,
    but now examines the initial part of the file's contents */
 boolean
-uptodate(fd, name)
-int fd;
+uptodate(nhfp, name, utdflags)
+NHFILE *nhfp;
 const char *name;
+unsigned long utdflags;
 {
-    int rlen;
+    int rlen, cmc = 0, filecmc = 0;
     struct version_info vers_info;
     boolean verbose = name ? TRUE : FALSE;
+    char indicator;
 
-    rlen = read(fd, (genericptr_t) &vers_info, sizeof vers_info);
-    minit(); /* ZEROCOMP */
-    if (rlen == 0) {
-        if (verbose) {
-            pline("File \"%s\" is empty?", name);
-            wait_synch();
-        }
+    if (nhfp->structlevel) {
+        rlen = read(nhfp->fd, (genericptr_t) &indicator, sizeof indicator);
+        rlen = read(nhfp->fd, (genericptr_t) &filecmc, sizeof filecmc);
+        if (rlen == 0)
+            return FALSE;
+    }
+    if (nhfp->fieldlevel) {
+        sfi_char(nhfp, &indicator, "indicate", "format", 1);
+        sfi_int(nhfp, &filecmc, "validate", "critical_members_count", 1);
+        cmc = critical_members_count();
+    }
+    if (cmc != filecmc)
         return FALSE;
+
+    if (nhfp->fieldlevel && (nhfp->fnidx > historical)) {
+            sfi_version_info(nhfp, &vers_info, "version", "version_info", 1);
+    } else {
+        int rlen;
+
+        rlen = read(nhfp->fd, (genericptr_t) &vers_info, sizeof vers_info);
+        minit();                /* ZEROCOMP */
+        if (rlen == 0) {
+            if (verbose) {
+                pline("File \"%s\" is empty?", name);
+                wait_synch();
+            }
+            return FALSE;
+        }
     }
-    if (!check_version(&vers_info, name, verbose)) {
+
+    if (!check_version(&vers_info, name, verbose, utdflags)) {
         if (verbose)
             wait_synch();
         return FALSE;
@@ -312,19 +343,25 @@ const char *name;
 }
 
 void
-store_version(fd)
-int fd;
+store_version(nhfp)
+NHFILE *nhfp;
 {
     static const struct version_info version_data = {
         VERSION_NUMBER, VERSION_FEATURES,
         VERSION_SANITY1, VERSION_SANITY2, VERSION_SANITY3
     };
 
-    bufoff(fd);
-    /* bwrite() before bufon() uses plain write() */
-    bwrite(fd, (genericptr_t) &version_data,
-           (unsigned) (sizeof version_data));
-    bufon(fd);
+    if (nhfp->structlevel) {
+        bufoff(nhfp->fd);
+        /* bwrite() before bufon() uses plain write() */
+        bwrite(nhfp->fd,(genericptr_t) &version_data,
+               (unsigned) (sizeof version_data));
+        bufon(nhfp->fd);
+    }
+    if (nhfp->fieldlevel) {
+        sfo_version_info(nhfp, (struct version_info *) &version_data,
+                         "version", "version_info", 1);
+    }
     return;
 }
 
index 98ed3b6a0646d6f99e37f44cd66f65bc0a0c47b4..dbee675d6b6b909c4e9542ed6e2c80da2f25b8de 100644 (file)
@@ -5,6 +5,8 @@
 
 #include "hack.h"
 #include "lev.h"
+#include "sfproto.h"
+
 
 #define newseg() (struct wseg *) alloc(sizeof (struct wseg))
 #define dealloc_seg(wseg) free((genericptr_t) (wseg))
@@ -477,31 +479,46 @@ boolean use_detection_glyph;
  *  of segments, including the dummy.  Called from save.c.
  */
 void
-save_worm(fd, mode)
-int fd, mode;
+save_worm(nhfp)
+NHFILE *nhfp;
 {
     int i;
     int count;
     struct wseg *curr, *temp;
 
-    if (perform_bwrite(mode)) {
+    if (perform_bwrite(nhfp)) {
         for (i = 1; i < MAX_NUM_WORMS; i++) {
             for (count = 0, curr = wtails[i]; curr; curr = curr->nseg)
                 count++;
             /* Save number of segments */
-            bwrite(fd, (genericptr_t) &count, sizeof(int));
+            if (nhfp->structlevel)
+                bwrite(nhfp->fd, (genericptr_t) &count, sizeof(int));
+            if (nhfp->fieldlevel)
+                sfo_int(nhfp, &count, "worm", "segment_count", 1);
             /* Save segment locations of the monster. */
             if (count) {
                 for (curr = wtails[i]; curr; curr = curr->nseg) {
-                    bwrite(fd, (genericptr_t) & (curr->wx), sizeof(xchar));
-                    bwrite(fd, (genericptr_t) & (curr->wy), sizeof(xchar));
+                    if (nhfp->structlevel) {
+                        bwrite(nhfp->fd, (genericptr_t) &(curr->wx), sizeof(xchar));
+                        bwrite(nhfp->fd, (genericptr_t) &(curr->wy), sizeof(xchar));
+                    }
+                    if (nhfp->fieldlevel) {
+                        sfo_xchar(nhfp, &(curr->wx), "worm", "wx", 1);
+                        sfo_xchar(nhfp, &(curr->wy), "worm", "wy", 1);
+                    }
                 }
             }
         }
-        bwrite(fd, (genericptr_t) wgrowtime, sizeof(wgrowtime));
+        if (nhfp->structlevel) {
+            bwrite(nhfp->fd, (genericptr_t) wgrowtime, sizeof(wgrowtime));
+        }
+        if (nhfp->fieldlevel) {
+            for (i = 0; i < MAX_NUM_WORMS; ++i)
+                sfo_long(nhfp, &wgrowtime[i], "worm", "wgrowtime", 1);
+        }
     }
 
-    if (release_data(mode)) {
+    if (release_data(nhfp)) {
         /* Free the segments only.  savemonchn() will take care of the
          * monsters. */
         for (i = 1; i < MAX_NUM_WORMS; i++) {
@@ -518,29 +535,38 @@ int fd, mode;
     }
 }
 
+/* SAVE2018 */
+
 /*
  *  rest_worm()
  *
  *  Restore the worm information from the save file.  Called from restore.c
  */
 void
-rest_worm(fd)
-int fd;
+rest_worm(nhfp)
+NHFILE *nhfp;
 {
     int i, j, count;
     struct wseg *curr, *temp;
 
     for (i = 1; i < MAX_NUM_WORMS; i++) {
-        mread(fd, (genericptr_t) &count, sizeof(int));
-        if (!count)
-            continue; /* none */
+        if (nhfp->structlevel)
+            mread(nhfp->fd, (genericptr_t) &count, sizeof(int));
+        if (nhfp->fieldlevel)
+            sfi_int(nhfp, &count, "worm", "segment_count", 1);
 
         /* Get the segments. */
         for (curr = (struct wseg *) 0, j = 0; j < count; j++) {
             temp = newseg();
             temp->nseg = (struct wseg *) 0;
-            mread(fd, (genericptr_t) & (temp->wx), sizeof(xchar));
-            mread(fd, (genericptr_t) & (temp->wy), sizeof(xchar));
+            if (nhfp->structlevel) {
+                mread(nhfp->fd, (genericptr_t) &(temp->wx), sizeof(xchar));
+                mread(nhfp->fd, (genericptr_t) &(temp->wy), sizeof(xchar));
+            }
+            if (nhfp->fieldlevel) {
+                sfi_xchar(nhfp, &(temp->wx), "worm", "wx", 1);
+                sfi_xchar(nhfp, &(temp->wy), "worm", "wy", 1);
+            }
             if (curr)
                 curr->nseg = temp;
             else
@@ -549,7 +575,13 @@ int fd;
         }
         wheads[i] = curr;
     }
-    mread(fd, (genericptr_t) wgrowtime, sizeof(wgrowtime));
+    if (nhfp->structlevel) {
+        mread(nhfp->fd, (genericptr_t) wgrowtime, sizeof(wgrowtime));
+    }
+    if (nhfp->fieldlevel) {
+        for (i = 0; i < MAX_NUM_WORMS; ++i)
+            sfi_long(nhfp, &wgrowtime[i], "worm", "wgrowtime", 1);
+    }
 }
 
 /*
index ffe1093377a769557d47b6e811f4efd6e1f4c7cc..6c59b8c005f3afaa5e9bba1899bfe18d081a957c 100644 (file)
@@ -90,7 +90,7 @@ pcmain(argc, argv)
 int argc;
 char *argv[];
 {
-    register int fd;
+    NHFILE *nhfp;
     register char *dir;
 #if defined(MSDOS)
     char *envp = NULL;
@@ -444,13 +444,16 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/
 
     /* Set up level 0 file to keep the game state.
      */
-    fd = create_levelfile(0, (char *) 0);
-    if (fd < 0) {
+    nhfp = create_levelfile(0, (char *) 0);
+    if (!nhfp) {
         raw_print("Cannot create lock file");
     } else {
         g.hackpid = 1;
-        write(fd, (genericptr_t) &g.hackpid, sizeof(g.hackpid));
-        nhclose(fd);
+        if (nhfp->structlevel)
+            write(nhfp->fd, (genericptr_t) &g.hackpid, sizeof(g.hackpid));
+        if (nhfp->fieldlevel)
+            sfi_int(nhfp, &g.hackpid, "locking", "g.hackpid", 1);
+        close_nhfile(nhfp);
     }
 #ifdef MFLOPPY
     level_info[0].where = ACTIVE;
@@ -468,7 +471,7 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/
  * We'll return here if new game player_selection() renames the hero.
  */
 attempt_restore:
-    if ((fd = restore_saved_game()) >= 0) {
+    if ((nhfp = restore_saved_game()) > 0) {
 #ifndef NO_SIGNAL
         (void) signal(SIGINT, (SIG_RET_TYPE) done1);
 #endif
@@ -481,7 +484,7 @@ attempt_restore:
         pline("Restoring save file...");
         mark_synch(); /* flush output */
 
-        if (dorecover(fd)) {
+        if (dorecover(nhfp)) {
             resuming = TRUE; /* not starting new game */
             if (discover)
                 You("are in non-scoring discovery mode.");
index 47ab9e0ce4593940faf3883f7ef3e6b58f4fa38b..bffc6cbe783256ea44774d7d70bec3ca85bbff90 100644 (file)
@@ -448,7 +448,9 @@ HACKCSRC = allmain.c alloc.c apply.c artifact.c attrib.c ball.c bones.c \
           mplayer.c mthrowu.c muse.c music.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 restore.c \
-          rip.c rnd.c role.c rumors.c save.c shk.c shknam.c sit.c sounds.c \
+          rip.c rnd.c role.c rumors.c save.c \
+          sfbase.c sfdata.c sfascii.c sflendian.c \
+          shk.c shknam.c sit.c sounds.c \
           sp_lev.c spell.c steal.c steed.c sys.c teleport.c timeout.c \
           topten.c track.c trap.c u_init.c \
           uhitm.c vault.c version.c vision.c weapon.c were.c wield.c \
@@ -464,7 +466,7 @@ SYSCSRC = ../sys/atari/tos.c ../sys/share/pcmain.c ../sys/share/pcsys.c \
 SYSCXXSRC = ../sys/share/cppregex.cpp
 
 # generated source files (tile.c is handled separately via WINxxxSRC)
-GENCSRC = vis_tab.c    #tile.c
+GENCSRC = vis_tab.c    sfdata.c #tile.c
 
 # all windowing-system-dependent .c (for dependencies and such)
 WINCSRC = $(WINTTYSRC) $(WINCURSESSRC) $(WINX11SRC) $(WINGNOMESRC) $(WINGEMSRC)
@@ -515,8 +517,9 @@ HOBJ = $(FIRSTOBJ) allmain.o alloc.o apply.o artifact.o attrib.o ball.o \
        mplayer.o mthrowu.o muse.o music.o o_init.o objnam.o options.o \
        pager.o pickup.o pline.o polyself.o potion.o pray.o priest.o \
        quest.o questpgr.o read.o rect.o region.o restore.o rip.o rnd.o \
-       role.o rumors.o save.o shk.o shknam.o sit.o sounds.o sp_lev.o spell.o \
-       sys.o \
+       role.o rumors.o save.o \
+       sfbase.o sfdata.o sfascii.o sflendian.o \
+       shk.o shknam.o sit.o sounds.o sp_lev.o spell.o sys.o \
        steal.o steed.o teleport.o timeout.o topten.o track.o trap.o u_init.o \
        uhitm.o vault.o vision.o vis_tab.o weapon.o were.o wield.o windows.o \
        wizard.o worm.o worn.o write.o zap.o \
@@ -658,6 +661,26 @@ tile.c: ../win/share/tilemap.c $(HACK_H)
 ../win/gnome/gn_rip.h: ../win/X11/rip.xpm
        cp ../win/X11/rip.xpm ../win/gnome/gn_rip.h
 
+# readtags dependencies
+#
+#
+../util/readtags:
+       @( cd ../util ; $(MAKE) readtags )
+
+../util/nethack.tags:
+       @( cd ../util ; $(MAKE) nethack.tags )
+
+sfbase.o: sfbase.c $(HACK_H) ../include/sfproto.h ../include/sfprocs.h
+sfascii.o: sfascii.c $(HACK_H) ../include/sfprocs.h
+sflendian.o: sflendian.c $(HACK_H) ../include/sfprocs.h
+sfdata.o: sfdata.c $(HACK_H) ../include/sfprocs.h
+
+sfdata.c: ../util/readtags ../util/nethack.tags
+       @( cd ../util ; ./readtags )
+
+../include/sfproto.h: ../util/readtags ../util/nethack.tags
+       @( cd ../util ; ./readtags )
+
 #      date.h should be remade any time any of the source or include code
 #      is modified.  Unfortunately, this would make the contents of this
 #      file far more complex.  Since "hack.h" depends on most of the include
@@ -672,7 +695,6 @@ tile.c: ../win/share/tilemap.c $(HACK_H)
        -$(SHELL) ../sys/unix/gitinfo.sh $(GITINFO) #before 'makedefs -v'
        ../util/makedefs -v
 
-
 lint:
 # lint cannot have -p here because (i) capitals are meaningful:
 # [Ww]izard, (ii) identifiers may coincide in the first six places:
index 78e9d725f55483b3a09095e14ae1687cd0d4c2ce..9c789626690ed48732ed338b15cd9e49030fa075 100644 (file)
@@ -126,6 +126,10 @@ LEXYYC = lex.yy.c
 # YTABH = y_tab.h
 # LEXYYC = lexyy.c
 
+# This is the universal ctags utility which produces the tags in the
+# format that util/readtags requires. 
+# https://github.com/universal-ctags/ctags.git
+CTAGSCMD = universal-ctags
 
 # if you change this to 1, feedback while building will omit -Dthis -Wthat
 # -Isomewhere so that each file being compiled is listed on one short line;
@@ -184,6 +188,7 @@ DGNCOMPSRC = dgn_yacc.c dgn_lex.c dgn_main.c
 RECOVSRC = recover.c
 DLBSRC = dlb_main.c
 UTILSRCS = $(MAKESRC) panic.c $(SPLEVSRC) $(DGNCOMPSRC) $(RECOVSRC) $(DLBSRC)
+READTAGSSRC = readtags.c
 
 # files that define all monsters and objects
 CMONOBJ = ../src/monst.c ../src/objects.c
@@ -210,6 +215,9 @@ RECOVOBJS = recover.o
 # object files for the data librarian
 DLBOBJS = dlb_main.o $(OBJDIR)/dlb.o $(OALLOC)
 
+# object files for readtags
+READTAGSOBJS = readtags.o
+
 # flags for creating distribution versions of sys/share/*_lex.c, using
 # a more portable flex skeleton, which is not included in the distribution.
 # hopefully keeping this out of the section to be edited will keep too
@@ -441,6 +449,73 @@ tileedit: tileedit.cpp $(TEXT_IO)
        $(CC) -o tileedit -I../include -I$(QTDIR)/include -L$(QTDIR)/lib \
                tileedit.cpp $(TEXT_IO) -lqt
 
+#      dependencies for readtags
+#
+CTAGDEP = ../include/align.h    ../include/artifact.h ../src/artifact.c     \
+        ../include/artilist.h ../include/attrib.h   ../src/bones.c        \
+        ../include/context.h  ../include/coord.h    ../include/decl.h     \
+        ../src/decl.c         ../include/dungeon.h  ../include/engrave.h  \
+        ../src/engrave.c      ../include/flag.h     ../include/func_tab.h \
+        ../include/global.h   ../include/hack.h     ../include/lev.h      \
+        ../include/mextra.h   ../include/mkroom.h   ../include/monst.h    \
+        ../include/monsym.h   ../include/obj.h      ../include/objclass.h \
+        ../include/prop.h     ../include/quest.h    ../include/rect.h     \
+        ../include/region.h   ../include/rm.h       ../include/skills.h   \
+        ../include/spell.h    ../include/sys.h      ../include/timeout.h  \
+        ../include/trap.h     ../include/you.h      ../include/onames.h   \
+        ../include/wintype.h
+#       ../include/permonst.h
+CTAGSOPT = --language-force=c --sort=no -D"Bitfield(x,n)=unsigned x : n" --excmd=pattern
+
+readtags: $(READTAGSOBJS)
+       $(CC) $(LFLAGS) -o readtags $(READTAGSOBJS) $(LIBS)
+
+readtags.o: readtags.c $(HACK_H)
+       $(CC) $(CFLAGS) -c readtags.c
+
+nethack.tags: $(CTAGDEP)
+#
+# tested with universal ctags from https://github.com/universal-ctags/ctags.git
+#
+       $(CTAGSCMD) $(CTAGSOPT) -f nethack.tags ../include/align.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/artifact.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../src/artifact.c
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/artilist.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/attrib.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../src/bones.c
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/context.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/coord.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/decl.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../src/decl.c
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/dungeon.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/engrave.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../src/engrave.c
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/flag.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/func_tab.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/global.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/hack.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/lev.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/mextra.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/mkroom.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/monst.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/monsym.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/obj.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/objclass.h
+#      $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/permonst.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/prop.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/quest.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/rect.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/region.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/rm.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/skills.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/spell.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/sys.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/timeout.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/trap.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/you.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/onames.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f nethack.tags ../include/wintype.h
+
 # using dependencies like
 #      ../src/foo::
 #              @( cd ../src ; $(MAKE) foo )
index 18d1b3aacba4a5625204f961df2e8eb044360361..bef1ffa5132a70a518032f61e8cb5474b3c2806b 100644 (file)
@@ -54,6 +54,7 @@ char *argv[];
 #ifdef CHDIR
     register char *dir;
 #endif
+    NHFILE *nhfp;
     boolean exact_username;
     boolean resuming = FALSE; /* assume new game */
     boolean plsel_once = FALSE;
@@ -280,7 +281,7 @@ attempt_restore:
         g.program_state.preserve_locks = 0; /* after getlock() */
     }
 
-    if (*g.plname && (fd = restore_saved_game()) >= 0) {
+    if (*g.plname && (nhfp = restore_saved_game()) != 0) {
         const char *fq_save = fqname(g.SAVEF, SAVEPREFIX, 1);
 
         (void) chmod(fq_save, 0); /* disallow parallel restores */
@@ -295,7 +296,7 @@ attempt_restore:
 #endif
         pline("Restoring save file...");
         mark_synch(); /* flush output */
-        if (dorecover(fd)) {
+        if (dorecover(nhfp)) {
             resuming = TRUE; /* not starting new game */
             wd_message();
             if (discover || wizard) {
index 00e9e8a0037fa4660733f82c967c66135f84565e..5e9a21b049eddddce8c0762da4e89af99995eba2 100644 (file)
@@ -236,7 +236,8 @@ VOBJ24 = $(O)track.o    $(O)trap.o     $(O)u_init.o   $(O)uhitm.o
 VOBJ25 = $(O)vault.o    $(O)vis_tab.o  $(O)vision.o   $(O)weapon.o
 VOBJ26 = $(O)were.o     $(O)wield.o    $(O)windows.o  $(O)wizard.o
 VOBJ27 = $(O)worm.o     $(O)worn.o     $(O)write.o    $(O)zap.o
-VOBJ28 = 
+VOBJ28 = $(O)sfbase.o   $(O)sfdata.o   $(O)sfascii.o  $(O)sflendian.o
+#VOBJ29 = 
 
 DLBOBJ = $(O)dlb.o
 
@@ -259,8 +260,8 @@ OBJS   = $(VOBJ01) $(VOBJ02) $(VOBJ03) $(VOBJ04) $(VOBJ05) \
          $(VOBJ11) $(VOBJ12) $(VOBJ13) $(VOBJ14) $(VOBJ15) \
          $(VOBJ16) $(VOBJ17) $(VOBJ18) $(VOBJ19) $(VOBJ20) \
          $(VOBJ21) $(VOBJ22) $(VOBJ23) $(VOBJ24) $(VOBJ25) \
-         $(VOBJ26) $(VOBJ27) $(VOBJ28) $(VOBJ29) $(REGEX)  \
-         $(CURSESOBJ)
+         $(VOBJ26) $(VOBJ27) $(VOBJ28) $(VOBJ29) $(VOBJ30) \
+         $(REGEX)  $(CURSESOBJ)
 
 GUIOBJ = $(O)mhaskyn.o $(O)mhdlg.o \
        $(O)mhfont.o $(O)mhinput.o $(O)mhmain.o $(O)mhmap.o \
@@ -364,6 +365,19 @@ DATABASE = $(DAT)\data.base
 #==========================================
 #==========================================
 
+#
+# ctags options
+#
+#CTAGSCMD=ctags-orig.exe
+CTAGSCMD=..\..\..\ctags\ctags.exe
+CTAGSOPT =--language-force=c --sort=no -D"Bitfield(x,n)=unsigned x : n" --excmd=pattern
+#
+# ctags wants unix-style pathnames
+#
+TINC = $(INCL:\=/)
+TSRC = $(SRC:\=/)
+
 cc=cl
 link=link
 rc=Rc
@@ -1066,6 +1080,7 @@ $(U)dgncomp.exe: $(DGNCOMPOBJS)
                )
 <<
 
 #=================================================
 # Create directory for holding object files
 #=================================================
@@ -1477,6 +1492,93 @@ $(O)NetHackW.o: $(HACK_H) $(MSWIN)\NetHackW.c
 $(O)ttystub.o: $(HACK_H) $(MSWSYS)\stubs.c
        @$(cc) $(cflagsBuild) -DTTYSTUB -Fo$@ $(MSWSYS)\stubs.c
 
+#
+#============================================
+# fieldlevel save dependencies
+#============================================
+
+$(O)sfbase.o: $(HACK_H) $(INCL)\sfproto.h $(INCL)\sfprocs.h \
+               $(SRC)\sfbase.c
+       @$(cc) $(cflagsBuild) -Fo$@ $(SRC)\sfbase.c
+
+$(O)sfdata.o: $(HACK_H) $(INCL)\sfprocs.h $(SRC)\sfdata.c
+       @$(cc) $(cflagsBuild) -Fo$@ $(SRC)\sfdata.c
+
+$(O)sfascii.o: $(HACK_H) $(INCL)\sfprocs.h $(SRC)\sfascii.c
+       @$(cc) $(cflagsBuild) -Fo$@ $(SRC)\sfascii.c
+
+$(O)sflendian.o: $(HACK_H) $(INCL)\sfprocs.h $(SRC)\sflendian.c
+       @$(cc) $(cflagsBuild) -Fo$@ $(SRC)\sflendian.c
+
+$(SRC)\sfdata.c: $(U)readtags.exe $(U)nethack.tags
+        $(U)readtags.exe
+
+$(INCL)\sfproto.h: $(U)readtags.exe $(U)nethack.tags
+        $(U)readtags.exe
+
+$(U)readtags.exe: $(O)readtags.o
+       @$(link) $(lflagsBuild) -out:$@ $(O)readtags.o
+
+$(O)readtags.o: $(U)readtags.c $(U)nethack.tags $(CONFIG_H) $(PATCHLEVEL_H)
+       @$(cc) $(cflagsBuild) $(TEMPL)  -Fo$@ $(U)readtags.c
+
+#
+#tested only with exuberant ctags from http://ctags.sourceforge.net
+#
+CTAGDEP = $(TINC)/align.h    $(TINC)/artifact.h $(TSRC)/artifact.c \
+         $(TINC)/artilist.h $(TINC)/attrib.h   $(TSRC)/bones.c    \
+         $(TINC)/context.h  $(TINC)/coord.h    $(TINC)/decl.h     \
+         $(TSRC)/decl.c     $(TINC)/dungeon.h  $(TINC)/engrave.h  \
+         $(TSRC)/engrave.c  $(TINC)/flag.h     $(TINC)/func_tab.h \
+         $(TINC)/global.h   $(TINC)/hack.h     $(TINC)/lev.h      \
+         $(TINC)/mextra.h   $(TINC)/mkroom.h   $(TINC)/monst.h    \
+         $(TINC)/monsym.h   $(TINC)/obj.h      $(TINC)/objclass.h \
+         $(TINC)/permonst.h $(TINC)/prop.h     $(TINC)/quest.h    \
+         $(TINC)/rect.h     $(TINC)/region.h   $(TINC)/rm.h       \
+         $(TINC)/skills.h   $(TINC)/spell.h    $(TINC)/sys.h      \
+         $(TINC)/timeout.h  $(TINC)/trap.h     $(TINC)/you.h      \
+         $(TINC)/onames.h   $(TINC)/wintype.h 
+
+$(U)nethack.tags: $(CTAGDEP)
+       $(CTAGSCMD) $(CTAGSOPT) -f $(U)nethack.tags $(TINC)/align.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/artifact.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TSRC)/artifact.c
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/artilist.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/attrib.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TSRC)/bones.c
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/context.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/coord.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/decl.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TSRC)/decl.c
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/dungeon.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/engrave.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TSRC)/engrave.c
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/flag.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/func_tab.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/global.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/hack.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/lev.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/mextra.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/mkroom.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/monst.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/monsym.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/obj.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/objclass.h
+#      $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/permonst.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/prop.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/quest.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/rect.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/region.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/rm.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/skills.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/spell.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/sys.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/timeout.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/trap.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/you.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/onames.h
+       $(CTAGSCMD) $(CTAGSOPT) -a -f $(U)nethack.tags $(TINC)/wintype.h
+
 # 
 # util dependencies
 #
index 4aad72a87942455f8304ce4b79bd5ebfc0e50e24..975638c06ff5bc28dd65d1ef53a018fb8efa931b 100644 (file)
@@ -82,7 +82,7 @@ int argc;
 char *argv[];
 {
     boolean resuming = FALSE; /* assume new game */
-    int fd;
+    NHFILE *nhfp;
     char *windowtype = NULL;
     char *envp = NULL;
     char *sptr = NULL;
@@ -291,9 +291,11 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/
        setting of renameallowed; when False, player_selection()
        won't resent renaming as an option */
     iflags.renameallowed = FALSE;
+#if 0
     /* Obtain the name of the logged on user and incorporate
      * it into the name. */
-    Sprintf(fnamebuf, "%s-%s", get_username(0), g.plname);
+#endif
+    Sprintf(fnamebuf, "%s", g.plname);
     (void) fname_encode(
         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-.", '%',
         fnamebuf, encodedfnamebuf, BUFSZ);
@@ -303,13 +305,13 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/
 
     /* Set up level 0 file to keep the game state.
      */
-    fd = create_levelfile(0, (char *) 0);
-    if (fd < 0) {
+    nhfp = create_levelfile(0, (char *) 0);
+    if (!nhfp) {
         raw_print("Cannot create lock file");
     } else {
         g.hackpid = GetCurrentProcessId();
-        write(fd, (genericptr_t) &g.hackpid, sizeof(g.hackpid));
-        nhclose(fd);
+        write(nhfp->fd, (genericptr_t) &g.hackpid, sizeof(g.hackpid));
+        close_nhfile(nhfp);
     }
     /*
      *  Initialize the vision system.  This must be before mklev() on a
@@ -322,7 +324,7 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/
      * We'll return here if new game player_selection() renames the hero.
      */
 attempt_restore:
-    if ((fd = restore_saved_game()) >= 0) {
+    if ((nhfp = restore_saved_game()) != 0) {
 #ifdef NEWS
         if (iflags.news) {
             display_file(NEWS, FALSE);
@@ -331,7 +333,7 @@ attempt_restore:
 #endif
         pline("Restoring save file...");
         mark_synch(); /* flush output */
-        if (dorecover(fd)) {
+        if (dorecover(nhfp)) {
             resuming = TRUE; /* not starting new game */
             if (discover)
                 You("are in non-scoring discovery mode.");
diff --git a/util/readtags.c b/util/readtags.c
new file mode 100644 (file)
index 0000000..8dd3162
--- /dev/null
@@ -0,0 +1,1618 @@
+/* NetHack 3.6 readtags.c      $Date$ $Revision$                 */
+/* Copyright (c) Michael Allison, 2018                           */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ *     Read the given ctags file and generate:
+ *      Intermediate temp files:
+ *              include/sfo_proto.tmp
+ *              include/sfi_proto.tmp
+ *             src/sfi_data.tmp
+ *             src/sfo_data.tmp
+ *      Final files:
+ *             sfdata.c
+ *              sfproto.h
+ *
+ */
+
+#include "hack.h"
+#include "lev.h"
+#include "integer.h"
+#include "wintype.h"
+#include <stdint.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef __GNUC__
+#define strncmpi strncasecmp
+#endif
+
+/* version information */
+#ifdef SHORT_FILENAMES
+#include "patchlev.h"
+#else
+#include "patchlevel.h"
+#endif
+
+#define NHTYPE_SIMPLE  1
+#define NHTYPE_COMPLEX 2
+struct nhdatatypes_t {
+       unsigned int dtclass;
+       char *dtype;
+       size_t dtsize;
+};
+
+struct tagstruct {
+    int linenum;
+    char ptr[128];
+    char tag[100];
+    char filename[128];
+    char searchtext[255];
+    char tagtype;
+    char parent[100];
+    char parenttype[100];
+    char arraysize1[100];
+    char arraysize2[100];
+    struct tagstruct *next;
+};
+
+struct needs_array_handling {
+    const char *nm;
+    const char *parent;
+};
+
+#define SFO_DATA c_sfodata
+#define SFI_DATA c_sfidata
+#define SFDATATMP c_sfdatatmp
+#define SFO_PROTO c_sfoproto
+#define SFI_PROTO c_sfiproto
+#define SFDATA c_sfdata
+#define SFPROTO c_sfproto
+
+static char *fgetline(FILE*);
+static void quit(void);
+static void out_of_memory(void);
+static void doline(char *);
+static void chain(struct tagstruct *);
+static void showthem(void);
+static char *stripspecial(char *);
+static char *deblank(char *);
+static char *deeol(char *);
+static void generate_c_files();
+static char *findtype(char *, char *);
+static boolean FDECL(is_prim, (char *));
+static void taglineparse(char *, struct tagstruct *);
+static void parseExtensionFields(struct tagstruct *, char *);
+static void set_member_array_size(struct tagstruct *);
+static char *member_array_dims(struct tagstruct *, char *);
+static char *member_array_size(struct tagstruct *, char *);
+static void output_types(FILE *);
+static char *FDECL(dtmacro,(const char *,int));
+static char *FDECL(dtfn,(const char *,int, boolean *));
+static char *FDECL(bfsize,(const char *));
+static char *FDECL(fieldfix,(char *,char *));
+
+#ifdef VMS
+static FILE *vms_fopen(name, mode) const char *name, *mode;
+{
+    return fopen(name, mode, "mbc=64", "shr=nil");
+}
+# define fopen(f,m) vms_fopen(f,m)
+#endif
+
+#define Fprintf    (void) fprintf
+#ifndef __GO32__
+#define DEFAULTTAGNAME "../util/nethack.tags"
+#else
+#define DEFAULTTAGNAME "../util/nhtags.tag"
+#endif
+#ifndef _MAX_PATH
+#define _MAX_PATH  120
+#endif
+
+#define TAB '\t'
+#define SPACE ' '
+
+struct tagstruct *first;
+struct tagstruct zerotag;
+
+static int tagcount;
+static const char *infilenm;
+static FILE *infile;
+static char line[255];
+static long lineno;
+static char ssdef[BUFSZ];
+static char fieldfixbuf[BUFSZ];
+
+#define NHTYPE_SIMPLE    1
+#define NHTYPE_COMPLEX   2
+
+struct nhdatatypes_t readtagstypes[] = {
+    {NHTYPE_SIMPLE, "any", sizeof(anything)},
+    {NHTYPE_SIMPLE, "genericptr_t", sizeof(genericptr_t)},
+    {NHTYPE_SIMPLE, "aligntyp", sizeof(aligntyp)},
+    {NHTYPE_SIMPLE, "Bitfield", sizeof(uint8_t)},
+    {NHTYPE_SIMPLE, "boolean", sizeof(boolean)},
+    {NHTYPE_SIMPLE, "char", sizeof(char)},
+    {NHTYPE_SIMPLE, "int",  sizeof(int)},
+    {NHTYPE_SIMPLE, "long", sizeof(long)},
+    {NHTYPE_SIMPLE, "schar", sizeof(schar)},
+    {NHTYPE_SIMPLE, "short", sizeof(short)},
+    {NHTYPE_SIMPLE, "size_t", sizeof(size_t)},
+    {NHTYPE_SIMPLE, "string", 1},
+    {NHTYPE_SIMPLE, "time_t",  sizeof(time_t)},
+    {NHTYPE_SIMPLE, "uchar",  sizeof(uchar)},
+    {NHTYPE_SIMPLE, "unsigned char", sizeof(unsigned char)},
+    {NHTYPE_SIMPLE, "unsigned int", sizeof(unsigned int)},
+    {NHTYPE_SIMPLE, "unsigned long", sizeof(unsigned long)},
+    {NHTYPE_SIMPLE, "unsigned short",  sizeof(unsigned short)},
+    {NHTYPE_SIMPLE, "unsigned", sizeof(unsigned)},
+    {NHTYPE_SIMPLE, "xchar",  sizeof(xchar)},
+    {NHTYPE_COMPLEX,"align", sizeof(struct align)},
+/*    {NHTYPE_COMPLEX,"attack", sizeof(struct attack)}, */ /* permonst affil */
+    {NHTYPE_COMPLEX,"attribs", sizeof(struct attribs)},
+    {NHTYPE_COMPLEX,"bill_x", sizeof(struct bill_x)},
+    {NHTYPE_COMPLEX,"book_info", sizeof(struct book_info)},
+    {NHTYPE_COMPLEX,"branch", sizeof(struct branch)},
+    {NHTYPE_COMPLEX,"bubble", sizeof(struct bubble)},
+    {NHTYPE_COMPLEX,"cemetery", sizeof(struct cemetery)},
+/*    {NHTYPE_COMPLEX,"container", sizeof(struct container)}, */
+    {NHTYPE_COMPLEX,"context_info", sizeof(struct context_info)},
+    {NHTYPE_COMPLEX,"d_flags", sizeof(struct d_flags)},
+    {NHTYPE_COMPLEX,"d_level", sizeof(struct d_level)},
+    {NHTYPE_COMPLEX,"damage", sizeof(struct damage)},
+    {NHTYPE_COMPLEX,"dest_area", sizeof(struct dest_area)},
+    {NHTYPE_COMPLEX,"dgn_topology", sizeof(struct dgn_topology)},
+    {NHTYPE_COMPLEX,"dig_info", sizeof(struct dig_info)},
+    {NHTYPE_COMPLEX,"dungeon", sizeof(struct dungeon)},
+    {NHTYPE_COMPLEX,"edog", sizeof(struct edog)},
+    {NHTYPE_COMPLEX,"egd", sizeof(struct egd)},
+    {NHTYPE_COMPLEX,"emin", sizeof(struct emin)},
+    {NHTYPE_COMPLEX,"engr", sizeof(struct engr)},
+    {NHTYPE_COMPLEX,"epri", sizeof(struct epri)},
+    {NHTYPE_COMPLEX,"eshk", sizeof(struct eshk)},
+    {NHTYPE_COMPLEX,"fakecorridor", sizeof(struct fakecorridor)},
+    {NHTYPE_COMPLEX,"fe", sizeof(struct fe)},
+    {NHTYPE_COMPLEX,"flag", sizeof(struct flag)},
+    {NHTYPE_COMPLEX,"fruit", sizeof(struct fruit)},
+    {NHTYPE_COMPLEX,"kinfo", sizeof(struct kinfo)},
+    {NHTYPE_COMPLEX,"levelflags", sizeof(struct levelflags)},
+    {NHTYPE_COMPLEX,"linfo", sizeof(struct linfo)},
+    {NHTYPE_COMPLEX,"ls_t", sizeof(struct ls_t)},
+    {NHTYPE_COMPLEX,"mapseen_feat", sizeof(struct mapseen_feat)},
+    {NHTYPE_COMPLEX,"mapseen_flags", sizeof(struct mapseen_flags)},
+    {NHTYPE_COMPLEX,"mapseen_rooms", sizeof(struct mapseen_rooms)},
+    {NHTYPE_COMPLEX,"mapseen", sizeof(struct mapseen)},
+    {NHTYPE_COMPLEX,"mextra", sizeof(struct mextra)},
+    {NHTYPE_COMPLEX,"mkroom", sizeof(struct mkroom)},
+    {NHTYPE_COMPLEX,"monst", sizeof(struct monst)},
+    {NHTYPE_COMPLEX,"mvitals", sizeof(struct mvitals)},
+    {NHTYPE_COMPLEX,"nhcoord", sizeof(struct nhcoord)},
+    {NHTYPE_COMPLEX,"nhrect", sizeof(struct nhrect)},
+    {NHTYPE_COMPLEX,"novel_tracking", sizeof(struct novel_tracking)},
+    {NHTYPE_COMPLEX,"obj", sizeof(struct obj)},
+    {NHTYPE_COMPLEX,"objclass", sizeof(struct objclass)},
+    {NHTYPE_COMPLEX,"obj_split", sizeof(struct obj_split)},
+    {NHTYPE_COMPLEX,"oextra", sizeof(struct oextra)},
+/*    {NHTYPE_COMPLEX,"permonst", sizeof(struct permonst)}, */
+    {NHTYPE_COMPLEX,"polearm_info", sizeof(struct polearm_info)},
+    {NHTYPE_COMPLEX,"prop", sizeof(struct prop)},
+    {NHTYPE_COMPLEX,"q_score", sizeof(struct q_score)},
+    {NHTYPE_COMPLEX,"rm", sizeof(struct rm)},
+    {NHTYPE_COMPLEX,"s_level", sizeof(struct s_level)},
+    {NHTYPE_COMPLEX,"savefile_info", sizeof(struct savefile_info)},
+    {NHTYPE_COMPLEX,"skills", sizeof(struct skills)},
+    {NHTYPE_COMPLEX,"spell", sizeof(struct spell)},
+    {NHTYPE_COMPLEX,"stairway", sizeof(struct stairway)},
+#ifdef SYSFLAGS
+    {NHTYPE_COMPLEX,"sysflag", sizeof(struct sysflag)},
+#endif
+    {NHTYPE_COMPLEX,"takeoff_info", sizeof(struct takeoff_info)},
+    {NHTYPE_COMPLEX,"tin_info", sizeof(struct tin_info)},
+    {NHTYPE_COMPLEX,"trap", sizeof(struct trap)},
+    {NHTYPE_COMPLEX,"tribute_info", sizeof(struct tribute_info)},
+    {NHTYPE_COMPLEX,"u_achieve", sizeof(struct u_achieve)},
+    {NHTYPE_COMPLEX,"u_conduct", sizeof(struct u_conduct)},
+    {NHTYPE_COMPLEX,"u_event", sizeof(struct u_event)},
+    {NHTYPE_COMPLEX,"u_have", sizeof(struct u_have)},
+    {NHTYPE_COMPLEX,"u_realtime", sizeof(struct u_realtime)},
+    {NHTYPE_COMPLEX,"u_roleplay", sizeof(struct u_roleplay)},
+    {NHTYPE_COMPLEX,"version_info", sizeof(struct version_info)},
+    {NHTYPE_COMPLEX,"victual_info", sizeof(struct victual_info)},
+    {NHTYPE_COMPLEX,"vlaunchinfo", sizeof(union vlaunchinfo)},
+    {NHTYPE_COMPLEX,"vptrs", sizeof(union vptrs)},
+    {NHTYPE_COMPLEX,"warntype_info", sizeof(struct warntype_info)},
+    {NHTYPE_COMPLEX,"you", sizeof(struct you)}
+};
+
+/*
+ * These have arrays of other structs, not just arrays of
+ * simple types. We need to put array handling right into
+ * the code for these ones.
+ */
+struct needs_array_handling nah[] = {
+    {"fakecorr", "egd"},
+    {"bill", "eshk"},
+    {"msrooms", "mapseen"},
+    {"mtrack", "monst"},
+    {"ualignbase", "you"},
+    {"weapon_skills", "you"},
+};
+
+/* conditional code tags - eecch */
+char *condtag[] = {
+#ifdef SYSFLAGS
+    "sysflag","altmeta","#ifdef AMIFLUSH", "",
+    "sysflag","amiflush","","#endif /*AMIFLUSH*/",
+    "sysflag","numcols", "#ifdef AMII_GRAPHICS", "",
+    "sysflag","amii_dripens","","",
+    "sysflag","amii_curmap","","#endif",
+    "sysflag","fast_map", "#ifdef OPT_DISMAP", "#endif",
+    "sysflag","asksavedisk","#ifdef MFLOPPY","#endif",
+    "sysflag","page_wait", "#ifdef MAC", "#endif",
+#endif
+    "linfo","where","#ifdef MFLOPPY","",
+    "linfo","time","","",
+    "linfo","size","","#endif /*MFLOPPY*/",
+    "obj","oinvis","#ifdef INVISIBLE_OBJECTS", "#endif",
+    (char *)0,(char *)0,(char *)0, (char *)0
+};
+
+
+
+int main(argc, argv)
+int argc;
+char *argv[];
+{
+    tagcount = 0;
+    
+    if (argc > 1) infilenm = argv[1];
+    if (!infilenm || !*infilenm) infilenm = DEFAULTTAGNAME;
+
+    infile = fopen(infilenm,"r");
+    if (!infile) {
+        printf("%s not found or unavailable\n",infilenm);
+        quit();
+    }
+
+    while (fgets(line, sizeof line, infile)) {
+        ++lineno;
+/*        if (lineno == 868) DebugBreak(); */
+        doline(line);
+    }
+
+    fclose(infile);
+    printf("\nRead in %ld lines and stored %d tags.\n", lineno,  tagcount);
+#if 0
+    showthem(); 
+#endif
+    generate_c_files();
+    exit(EXIT_SUCCESS);
+    /*NOTREACHED*/
+    return 0;
+}
+
+static void doline(line)
+char *line;
+{
+    char buf[255], *tmp1 = (char *)0;
+    struct tagstruct *tmptag = malloc(sizeof(struct tagstruct));
+
+    if (!tmptag) {
+        out_of_memory();
+    }
+    *tmptag = zerotag;
+    
+    if (!line || (line && *line == '!')) {
+        free(tmptag);
+        return;
+    }
+
+    strncpy(buf, deeol(line), 254);
+    taglineparse(buf,tmptag);
+    chain(tmptag);
+    return;
+}
+
+static void chain(tag)
+struct tagstruct *tag;
+{
+    static struct tagstruct *prev = (struct tagstruct *)0;
+    if (!first) {
+        tag->next = (struct tagstruct *)0;
+        first = tag;
+    } else {
+        tag->next = (struct tagstruct *)0;
+        if (prev) {
+            prev->next = tag;
+        } else {
+            printf("Error - No previous tag at %s\n", tag->tag);
+        }
+    }
+    prev = tag;
+    ++tagcount;
+}
+static void quit()
+{
+    exit(EXIT_FAILURE);
+}
+
+static void out_of_memory()
+{
+    printf("maketags: out of memory at line %ld of %s\n",
+        lineno, infilenm);
+    quit();
+}
+
+static char *member_array_dims(struct tagstruct *tmptag, char *buf)
+{
+    if (buf && tmptag) {
+        if (tmptag->arraysize1[0])
+            Sprintf(buf, "[%s]", tmptag->arraysize1);
+        if (tmptag->arraysize2[0])
+            Sprintf(eos(buf), "[%s]", tmptag->arraysize2);
+        return buf;
+    }
+    return "";
+}
+
+static char *member_array_size(struct tagstruct *tmptag, char *buf)
+{
+    if (buf && tmptag) {
+        if (tmptag->arraysize1[0])
+            strcpy(buf, tmptag->arraysize1);
+        if (tmptag->arraysize2[0])
+            Sprintf(eos(buf), " * %s", tmptag->arraysize2);
+        return buf;
+    }
+    return "";
+}
+
+void set_member_array_size(struct tagstruct *tmptag)
+{
+    char buf[BUFSZ];
+    static char result[49];
+    char *arr1 = (char *)0, *arr2 = (char *)0, *tmp;
+    int cnt = 0;
+
+    if (!tmptag || (tmptag && !tmptag->searchtext)) return;
+    strcpy(buf, tmptag->searchtext);
+    
+    tmptag->arraysize1[0] = '\0';
+    tmptag->arraysize2[0] = '\0';
+
+    /* find left-open square bracket */
+    tmp = strchr(buf, '[');
+    if (tmp) {
+        arr1 = tmp;
+        *tmp = '\0';
+        --tmp;
+        /* backup and make sure the [] are on the right tag */
+        while (!(*tmp == SPACE || *tmp == TAB || *tmp ==',' || cnt > 50)) {
+            --tmp;
+            cnt++;
+        }
+        if (cnt > 50) return;
+        tmp++;
+        if (strcmp(tmp, tmptag->tag) == 0) {
+            ++arr1;
+            tmp = strchr(arr1, ']');
+            if (tmp) {
+                arr2 = tmp;
+                ++arr2;
+                *tmp = '\0';
+                if (*arr2 == '[') { /* two-dimensional array */
+                    ++arr2;
+                    tmp = strchr(arr2, ']');
+                    if (tmp) *tmp = '\0';
+                } else {
+                    arr2 = (char *)0;
+                }
+            }
+        } else {
+            arr1 = (char *)0;
+        }
+    }
+    if (arr1) (void)strcpy(tmptag->arraysize1, arr1);
+    if (arr2) (void)strcpy(tmptag->arraysize2, arr2);
+}
+
+static void parseExtensionFields (tmptag, buf)
+struct tagstruct *tmptag;
+char *buf;
+{
+    char *p = buf;
+    while (p != (char *)0  &&  *p != '\0') {
+        while (*p == TAB)
+            *p++ = '\0';
+        if (*p != '\0') {
+            char *colon;
+            char *field = p;
+            
+            p = strchr (p, TAB);
+            if (p != (char *)0)
+                *p++ = '\0';
+            colon = strchr (field, ':');
+            if (colon == (char *)0) {
+                tmptag->tagtype = *field;
+            } else {
+                const char *key = field;
+                const char *value = colon + 1;
+                *colon = '\0';
+                if ((strcmp (key, "struct") == 0) ||
+                    (strcmp (key, "union") == 0)) {
+                    colon = strstr(value,"::");
+                    if (colon)
+                        value = colon +2;
+                    strcpy(tmptag->parenttype, key);
+                    strcpy(tmptag->parent, value);
+                }
+            }
+        }
+    }
+}
+
+void
+taglineparse(p,tmptag)
+char *p;
+struct tagstruct *tmptag;
+{
+    int fieldsPresent = 0;
+    char *filenm = 0, *pattern = 0, *tmp1 = 0;
+    int linenumber = 0;
+    char *tab = strchr (p, TAB);
+
+    if (tab != NULL) {
+        *tab = '\0';
+        strcpy(tmptag->tag,p);
+        p = tab + 1;
+        filenm = p;
+        tab = strchr (p, TAB);
+        if (tab != NULL) {
+            *tab = '\0';
+            p = tab + 1;
+            if (*p == '/'  ||  *p == '?') {
+                /* parse pattern */
+                int delimiter = *(unsigned char *) p;
+                linenumber = 0;
+                pattern = p;
+                do {
+                    p = strchr (p + 1, delimiter);
+                } while (p != (char *)0  &&  *(p - 1) == '\\');
+
+                if (p == (char *)0) {
+                    /* invalid pattern */
+                } else
+                    ++p;
+            } else if (isdigit ((int) *(unsigned char *) p)) {
+                /* parse line number */
+                pattern = p;
+                linenumber = atol(p);
+                while (isdigit((int) *(unsigned char *) p))
+                    ++p;
+            } else {
+                /* invalid pattern */
+            }
+            fieldsPresent = (strncmp (p, ";\"", 2) == 0);
+            *p = '\0';
+
+            if (fieldsPresent)
+                parseExtensionFields (tmptag, p + 2);
+        }
+    }
+
+    strcpy(tmptag->searchtext, pattern);
+    tmptag->linenum = linenumber;
+
+    /* add the array dimensions */
+    set_member_array_size(tmptag);
+
+    /* determine if this is a pointer and mark it as such */
+    if (tmptag->searchtext &&
+        (tmptag->tagtype == 'm' || tmptag->tagtype == 's')) {
+        char ptrbuf[BUFSZ], searchbuf[BUFSZ];
+
+        (void) strcpy(ptrbuf, tmptag->searchtext);
+        Sprintf(searchbuf,"*%s", tmptag->tag);
+        tmp1 = strstr(ptrbuf, searchbuf);
+        if (!tmp1) {
+            Sprintf(searchbuf,"* %s", tmptag->tag);
+            tmp1 = strstr(ptrbuf, searchbuf);
+        }
+        if (tmp1) {
+            while ((tmp1 > ptrbuf) && (*tmp1 != SPACE) &&
+                    (*tmp1 != TAB) && (*tmp1 != ','))
+                tmp1--;
+            tmp1++;
+            while (*tmp1 == '*')
+                tmp1++;
+            *tmp1 = '\0';
+            /* now find the first * before this in case multiple things
+               are declared on this line */
+            tmp1 = strchr(ptrbuf+2, '*');
+            if (tmp1) {
+                tmp1++;
+                *tmp1 = '\0';
+                tmp1 = ptrbuf + 2;
+                while (*tmp1 == SPACE || *tmp1 == TAB || *tmp1 == ',')
+                    ++tmp1;
+                (void)strcpy(tmptag->ptr, tmp1);
+            }
+        }
+    }
+}
+
+/* eos() is copied from hacklib.c */
+/* return the end of a string (pointing at '\0') */
+char *
+eos(s)            
+char *s;
+{
+    while (*s) s++;    /* s += strlen(s); */
+    return s;
+}
+
+static char stripbuf[255];
+
+static char *stripspecial(char *st)
+{
+    char *out = stripbuf;
+    *out = '\0';
+    if (!st) return st;
+    while(*st) {
+        if (*st >= SPACE)
+            *out++ = *st++;
+        else
+            *st++;
+    }
+    *out = '\0';
+    return stripbuf;
+}
+
+static char *deblank(char *st)
+{
+    char *out = stripbuf;
+    *out = '\0';
+    if (!st) return st;
+    while(*st) {
+        if (*st == SPACE) { 
+            *out++ = '_';
+            st++;
+        } else
+            *out++ = *st++;
+    }
+    *out = '\0';
+    return stripbuf;
+}
+
+static char *deeol(char *st)
+{
+    char *out = stripbuf;
+    *out = '\0';
+    if (!st) return st;
+    while(*st) {
+        if ((*st == '\r') || (*st == '\n')) { 
+            st++;
+        } else
+            *out++ = *st++;
+    }
+    *out = '\0';
+    return stripbuf;
+}
+
+#if 0
+static void showthem()
+{
+    char buf[BUFSZ], *tmp;
+    struct tagstruct *t = first;
+    while(t) {
+        printf("%-28s %c, %-16s %-10s", t->tag, t->tagtype,
+            t->parent, t->parenttype);
+#if 0
+            t->parent[0] ? t->searchtext : "");
+#endif
+        buf[0] = '\0';
+        tmp = member_array_dims(t,buf);        
+        if (tmp) printf("%s", tmp);
+        printf("%s","\n");
+        t = t->next;
+    }
+}
+#endif
+
+static boolean
+is_prim(sdt)
+char *sdt;
+{
+    int k = 0;
+    if (sdt) {
+        /* special case where we don't match entire thing */
+        if (!strncmpi(sdt, "Bitfield",8))
+            return TRUE;
+        for (k = 0; k < SIZE(readtagstypes); ++k) {
+            if (!strcmpi(readtagstypes[k].dtype, sdt)) {
+            if (readtagstypes[k].dtclass == NHTYPE_SIMPLE)
+                return TRUE;
+            else
+                return FALSE;
+            }
+        }
+    }
+    return FALSE;
+}
+
+char *
+findtype(st, tag)
+char *st;
+char *tag;
+{
+    static char ftbuf[512];
+    static char prevbuf[512];
+    char *tmp1, *tmp2, *tmp3, *tmp4, *r;
+    if (!st) return (char *)0;
+    if (st[0] == '/' && st[1] == '^') {
+        tmp2 = tmp3 = tmp4 = (char *)0;
+        tmp1 = &st[3];
+        while (*tmp1) {
+            if (isspace(*tmp1))
+                ; /* skip it */
+            else
+                break;
+            ++tmp1;
+        }
+        if (!strncmp(tmp1, tag, strlen(tag))) {
+            if(strlen(tag) == 1) {
+                char *sc = tmp1;
+                /* Kludge: single char match is too iffy,
+                   check to make sure its a complete
+                   token that we're comparing to. */
+                ++sc;
+                if (!(*sc == '_' || (*sc > 'a' && *sc < 'z') ||
+                     (*sc > 'A' && *sc < 'Z') || (*sc > '0' && *sc < '9')))
+                    return (char *)0;
+            } else {
+                return (char *)0;
+            }
+        }
+        if (*tmp1) {
+            if (!strncmp(tmp1, "Bitfield", 8)) {
+                strcpy(ftbuf, tmp1);
+                tmp1 = ftbuf;
+                tmp3 = strchr(tmp1, ')');
+                if (tmp3) {
+                    tmp3++;
+                    *tmp3 = '\0';
+                    return ftbuf;
+                }
+                return (char *)0;
+            }
+        }
+        if (*tmp1) {
+            int prevchar = 0;
+            strcpy(ftbuf, tmp1);
+            tmp1 = ftbuf;
+            /* find space separating first word with second */
+            while (!isspace(*tmp1)) {
+                prevchar = *tmp1;
+                ++tmp1;
+            }
+            
+            /* some oddball cases */
+            if (prevchar == ',' || prevchar == ';') {
+                tmp3 = strchr(ftbuf, ',');
+                tmp2 = strstr(ftbuf, tag);
+                return prevbuf;
+            } else {
+            /* a comma means that more than one thing declared on line */
+                 tmp3 = strchr(tmp1, ',');
+                tmp2 = strstr(tmp1, tag);
+            }
+            /* make sure we're matching a complete token */
+            if (tmp2) {
+                tmp4 = tmp2 + strlen(tag);
+                if ((*tmp4 == '_') || (*tmp4 >= 'a' && *tmp4 <= 'z') ||
+                 (*tmp4 >= 'A' && *tmp4 <= 'Z') || (*tmp4 >= '0' && *tmp4 <= '9'))
+                /* jump to next occurence then */
+                tmp2 = strstr(tmp4, tag);
+            }
+               /* tag w/o comma OR tag found w comma and tag before comma */
+            if ((tmp2 && !tmp3) || ((tmp2 && tmp3) && (tmp2 < tmp3))) {
+                *tmp2 = '\0';
+                --tmp2;
+                while (isspace(*tmp2))
+                    --tmp2;
+                tmp2++;
+                *tmp2 = '\0';
+            }
+            /* comma and no tag OR tag w comma and comma before tag */
+            else if ((tmp3 && !tmp2) || ((tmp2 && tmp3) && (tmp3 < tmp2))) {
+                --tmp3;
+                if (isspace(*tmp3)) {
+                    while (isspace(*tmp3))
+                        --tmp3;
+                }
+                while (!isspace(*tmp3) && (*tmp3 != '*')) 
+                    --tmp3;
+                while (isspace(*tmp3))
+                    --tmp3;
+                tmp3++;
+                *tmp3 = '\0';
+            }
+            /* comma or semicolon immediately following tag */
+            else {
+                volatile int y;
+                y = 1;
+            }
+            if (strncmpi(ftbuf, "struct ", 7) == 0)
+                r = ftbuf + 7;
+            else if (strncmpi(ftbuf, "union ", 6) == 0)
+                r = ftbuf + 6;
+            /* a couple of kludges follow unfortunately */
+            else if (strncmpi(ftbuf, "coord", 5) == 0)
+                r = "nhcoord";
+            else if (strncmpi(ftbuf, "anything", 8) == 0)
+                r = "any";
+            else if (strncmpi(ftbuf, "const char", 10) == 0)
+                r = "char";
+            else
+                r = ftbuf;
+            strcpy(prevbuf, r);
+            return r;
+        }
+    }
+    prevbuf[0] = '\0';
+    return (char *)0;
+}
+
+boolean
+listed(t)
+struct tagstruct *t;
+{
+    int k;
+
+    if ((strncmpi(t->tag, "Bitfield", 8) == 0) ||
+                    (strcmpi(t->tag, "string") == 0))
+        return TRUE;
+    for (k = 0; k < SIZE(readtagstypes); ++k) {
+        /*  This needs to be case-sensitive to avoid generating collision
+         *  between 'align' and 'Align'.
+         */
+        if (strcmp(readtagstypes[k].dtype, t->tag) == 0)
+            return TRUE;
+    }
+    return FALSE;
+}
+
+
+char *preamble[] = {
+    "/* Copyright (c) NetHack Development Team 2018.                   */\n",
+    "/* NetHack may be freely redistributed.  See license for details. */\n\n",
+    "/* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE!          */\n\n",
+    "#include \"hack.h\"\n",
+    "#include \"artifact.h\"\n",
+    "#include \"func_tab.h\"\n",
+    "#include \"lev.h\"\n",
+        "#include \"integer.h\"\n",
+        "#include \"wintype.h\"\n",
+    (char *)0
+};
+
+static void output_types(fp1)
+FILE *fp1;
+{
+    int k, cnt, hcnt = 1;
+    struct tagstruct *t = first;
+
+    Fprintf(fp1, "%s",
+        "struct nhdatatypes_t nhdatatypes[] = {\n");
+
+    for (k = 0; k < SIZE(readtagstypes); ++k) {
+        if (readtagstypes[k].dtclass == NHTYPE_SIMPLE) {
+            Fprintf(fp1,"\t{NHTYPE_SIMPLE,\"%s\", sizeof(%s)},\n",
+                readtagstypes[k].dtype,
+                (strncmpi(readtagstypes[k].dtype, "Bitfield", 8) == 0) ?
+                "uint8_t" :
+                (strcmpi(readtagstypes[k].dtype, "string") == 0) ?
+                "uchar" :
+                (strcmpi(readtagstypes[k].dtype, "any") == 0) ?
+                                "anything" : readtagstypes[k].dtype);
+/*                dtmacro(readtagstypes[k].dtype,0)); */
+#if 0
+            Fprintf(fp2, "#define %s\t%s%d\n", dtmacro(readtagstypes[k].dtype,1),
+                    (strlen(readtagstypes[k].dtype) > 12) ? "" :
+                (strlen(readtagstypes[k].dtype) < 5) ? "\t\t" :
+                "\t", hcnt++);
+#endif
+        }
+    }
+    cnt = 0;
+    while(t) {
+        if (listed(t) && ((t->tagtype == 's') || (t->tagtype == 'u'))) {
+            if (!strcmp(t->tag, "any")) {
+                t = t->next;
+                continue;
+            }
+            if (cnt > 0)
+                Fprintf(fp1, "%s", ",\n");
+            Fprintf(fp1, "\t{NHTYPE_COMPLEX,\"%s\", sizeof(%s %s)}",
+                    t->tag,
+                    (t->tagtype == 's') ? "struct" : "union", t->tag);
+            cnt += 1;
+        }
+        t = t->next;
+    }
+    Fprintf(fp1, "%s", "\n};\n\n");
+    Fprintf(fp1, "int nhdatatypes_size()\n{\n\treturn SIZE(nhdatatypes);\n}\n\n");
+}
+
+static void generate_c_files()
+{
+    struct tagstruct *t = first;
+#ifdef KR1ED
+    long clocktim = 0;
+#else
+    time_t clocktim = 0;
+#endif
+    char *c, cbuf[60], sfparent[BUFSZ], *substruct, *line;
+    FILE *SFO_DATA, *SFI_DATA, *SFDATATMP, *SFO_PROTO, *SFI_PROTO,
+         *SFDATA, *SFPROTO;
+    int k = 0, j, opening, closetag = 0;
+    char *iftxt = "} else ";
+    char *ft, *pt, *layout, *last_ft = (char *)0;
+    int okeydokey, x, a;
+    boolean did_i;
+
+    SFDATA = fopen("../src/sfdata.c", "w");
+    if (!SFDATA) return;
+
+    SFPROTO = fopen("../include/sfproto.h", "w");
+    if (!SFPROTO) return;
+
+    SFO_DATA = fopen("../src/sfo_data.tmp", "w");
+    if (!SFO_DATA) return;
+
+    SFO_PROTO = fopen("../include/sfo_proto.tmp", "w");
+    if (!SFO_PROTO) return;
+
+    SFI_PROTO = fopen("../include/sfi_proto.tmp", "w");
+    if (!SFI_PROTO) return;
+
+    SFI_DATA = fopen("../src/sfi_data.tmp", "w");
+    if (!SFI_DATA) return;
+
+    SFDATATMP = fopen("../src/sfdata.tmp", "w");
+    if (!SFDATATMP) return;
+
+    (void) time(&clocktim);
+    Strcpy(cbuf, ctime(&clocktim));
+
+    for (c = cbuf; *c; c++)
+        if (*c == '\n')
+            break;
+    *c = '\0';    /* strip off the '\n' */
+
+    /* begin sfproto.h */
+    Fprintf(SFPROTO,"/* NetHack %d.%d sfproto.h\t%s */\n", 
+               VERSION_MAJOR, VERSION_MINOR, cbuf);
+    for (j = 0; j < 3; ++j)
+        Fprintf(SFPROTO, "%s", preamble[j]);
+    Fprintf(SFPROTO, "#ifndef SFPROTO_H\n#define SFPROTO_H\n\n");
+    Fprintf(SFPROTO, "#include \"hack.h\"\n#include \"integer.h\"\n#include \"wintype.h\"\n\n"
+                          "#define E extern\n\n");
+
+    /* sfbase.c function prototypes */
+    Fprintf(SFPROTO,"%s\n", "E int NDECL(critical_members_count);");
+    Fprintf(SFPROTO,"/* sfbase.c output functions */\n");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfo_addinfo, (NHFILE *, const char *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfo_aligntyp, (NHFILE *, aligntyp *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfo_any, (NHFILE *, anything *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfo_bitfield, (NHFILE *, uint8_t *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfo_boolean, (NHFILE *, boolean *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfo_char, (NHFILE *, const char *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfo_genericptr, (NHFILE *, genericptr_t *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfo_int, (NHFILE *, int *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfo_long, (NHFILE *, long *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfo_schar, (NHFILE *, schar *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfo_short, (NHFILE *, short *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfo_size_t, (NHFILE *, size_t *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfo_time_t, (NHFILE *, time_t *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfo_uchar, (NHFILE *, uchar *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfo_unsigned, (NHFILE *, unsigned *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfo_uchar, (NHFILE *, unsigned char *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfo_uint, (NHFILE *, unsigned int *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfo_ulong, (NHFILE *, unsigned long *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfo_ushort, (NHFILE *, unsigned short *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfo_xchar, (NHFILE *, xchar *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfo_str, (NHFILE *, const char *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"/* sfbase.c input functions */\n");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfi_addinfo, (NHFILE *, const char *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfi_aligntyp, (NHFILE *, aligntyp *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfi_any, (NHFILE *, anything *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfi_bitfield, (NHFILE *, uint8_t *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfi_boolean, (NHFILE *, boolean *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfi_char, (NHFILE *, const char *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfi_genericptr, (NHFILE *, genericptr_t *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfi_int, (NHFILE *, int *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfi_long, (NHFILE *, long *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfi_schar, (NHFILE *, schar *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfi_short, (NHFILE *, short *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfi_size_t, (NHFILE *, size_t *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfi_time_t, (NHFILE *, time_t *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfi_uchar, (NHFILE *, uchar *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfi_unsigned, (NHFILE *, unsigned *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfi_uchar, (NHFILE *, unsigned char *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfi_uint, (NHFILE *, unsigned int *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfi_ulong, (NHFILE *, unsigned long *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfi_ushort, (NHFILE *, unsigned short *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfi_xchar, (NHFILE *, xchar *, const char *, const char *, int));");
+    Fprintf(SFPROTO,"%s\n", "E void FDECL(sfi_str, (NHFILE *, const char *, const char *, const char *, int));");
+    Fprintf(SFO_PROTO, "/* generated output functions */\n");
+    Fprintf(SFI_PROTO, "/* generated input functions */\n");
+    
+    /* begin sfdata.c */
+    Fprintf(SFDATA,"/* NetHack %d.%d sfdata.c\t$Date$ $Revision$ */\n",
+            VERSION_MAJOR, VERSION_MINOR);
+    for (j = 0; preamble[j]; ++j)
+        Fprintf(SFDATA, "%s", preamble[j]);
+    Fprintf(SFDATA, "#include \"sfproto.h\"\n\n");
+    Fprintf(SFDATA, "#define BUILD_DATE \"%s\"\n", cbuf);
+    Fprintf(SFDATA, "#define BUILD_TIME (%ldL)\n\n", (long) clocktim);
+    Fprintf(SFDATA, "#define NHTYPE_SIMPLE    1\n");
+    Fprintf(SFDATA, "#define NHTYPE_COMPLEX   2\n");
+    Fprintf(SFDATA, "struct nhdatatypes_t {\n");
+    Fprintf(SFDATA, "    unsigned int dtclass;\n");
+    Fprintf(SFDATA, "    char *dtype;\n");
+    Fprintf(SFDATA, "    size_t dtsize;\n};\n\n");
+    Fprintf(SFDATA,"static uint8_t bitfield = 0;\n");
+
+    output_types(SFDATATMP);
+    Fprintf(SFDATATMP,"char *critical_members[] = {\n");
+
+    k = 0;
+    opening = 1;
+    did_i = FALSE;
+    while(k < SIZE(readtagstypes)) {
+      boolean insert_const = FALSE;
+
+      if (readtagstypes[k].dtclass == NHTYPE_COMPLEX) {
+        
+          if (!strncmpi(readtagstypes[k].dtype,"Bitfield",8)) {            
+              Fprintf(SFO_DATA,
+                    "\nvoid\nsfo_bitfield(nhfp, d_bitfield, myparent, myname, cnt)\n"
+                    "NHFILE *nhfp;\n"
+                    "uint8_t *d_bitfield;\n"
+                    "const char *myparent;\n"
+                    "const char *myname;\n"
+                    "int cnt;\n"
+                    "{\n");
+
+              Fprintf(SFI_DATA,
+                    "\nvoid\nsfi_bitfield(nhfp, d_bitfield, myparent, myname, cnt)\n"
+                    "NHFILE *nhfp;\n"
+                    "uint8_t *d_bitfield;\n"
+                    "const char *myparent;\n"
+                    "const char *myname;\n"
+                    "int cnt;\n"
+                    "{\n");
+        }
+
+#if 0
+        if (!strncmpi(readtagstypes[k].dtype,"version_info",8))
+            insert_const = TRUE;
+#endif
+
+        pt = layout = (char *)0;
+        t = first;
+        while(t) {
+            if (t->tagtype == 'u' && !strcmp(t->tag, readtagstypes[k].dtype)) {
+                pt = "union";
+                break;
+            }
+            t = t->next;
+        }
+
+        if (!pt) {
+            pt = "struct";
+        }
+        Fprintf(SFO_PROTO,
+                "E void FDECL(sfo_%s, (NHFILE *, %s%s %s *, const char *, const char *, int));\n",
+                readtagstypes[k].dtype,
+                insert_const ? "const " : "",
+                pt, readtagstypes[k].dtype);
+
+        Fprintf(SFO_DATA,
+                "\nvoid\nsfo_%s(nhfp, d_%s, myparent, myname, cnt)\n"
+                "NHFILE *nhfp;\n"
+                "%s%s %s *d_%s;\n"
+                "const char *myparent;\n"
+                "const char *myname;\n"
+                "int cnt;\n"
+                "{\n",
+                readtagstypes[k].dtype,
+                deblank(readtagstypes[k].dtype),
+                insert_const ? "const " : "",
+                pt, readtagstypes[k].dtype,
+                deblank(readtagstypes[k].dtype));
+                        
+        Fprintf(SFO_DATA,
+                "    char *parent = \"%s\";\n",
+                readtagstypes[k].dtype);
+
+        Fprintf(SFI_PROTO,
+                "E void FDECL(sfi_%s, (NHFILE *, %s%s %s *, const char *, const char *, int));\n",
+                readtagstypes[k].dtype,
+                insert_const ? "const " : "",
+                pt, readtagstypes[k].dtype);
+
+        Fprintf(SFI_DATA,
+                "\nvoid\nsfi_%s(nhfp, d_%s, myparent, myname, cnt)\n"
+                "NHFILE *nhfp;\n"
+                "%s%s %s *d_%s;\n"
+                "const char *myparent;\n"
+                "const char *myname;\n"
+                "int cnt;\n"
+                "{\n",
+                readtagstypes[k].dtype,
+                deblank(readtagstypes[k].dtype),
+                insert_const ? "const " : "",
+                pt, readtagstypes[k].dtype,
+                deblank(readtagstypes[k].dtype));                    
+
+        Fprintf(SFI_DATA,
+                "    char *parent = \"%s\";\n",
+                readtagstypes[k].dtype);
+
+        Sprintf(sfparent, "%s %s", pt, readtagstypes[k].dtype);
+
+        for (a = 0; a < SIZE(nah); ++a) {
+            if (!strcmp(nah[a].parent, readtagstypes[k].dtype)) {
+                if (!did_i) {
+                    Fprintf(SFO_DATA, "    int i;\n");
+                    Fprintf(SFI_DATA, "    int i;\n");
+                    did_i = TRUE;
+                }
+            }
+        }
+
+        Fprintf(SFO_DATA, "\n");
+        Fprintf(SFI_DATA, "\n");
+
+        Fprintf(SFO_DATA,
+                "    if (nhfp->addinfo)\n"
+                "        sfo_addinfo(nhfp, myparent, \"start\", \"%s\", 1);\n",
+                readtagstypes[k].dtype);
+
+        Fprintf(SFI_DATA,
+                "    if (nhfp->addinfo)\n"
+                "        sfi_addinfo(nhfp, myparent, \"start\", \"%s\", 1);\n",
+                readtagstypes[k].dtype);
+
+        Fprintf(SFO_DATA, "\n");
+        Fprintf(SFI_DATA, "\n");
+
+        /********************************************************
+         *  cycle through all the tags and find every tag with  *
+         *  a parent matching readtagstypes[k].dtype            *
+         ********************************************************/
+
+        t = first;
+
+        while(t) { 
+            x = 0;
+            okeydokey = 0;
+
+            if (t->tagtype == 's')  {
+                char *ss = strstr(t->searchtext,"{$/");
+
+                if (ss) {
+                    strcpy(ssdef, t->tag);
+                }
+                t = t->next;
+                continue;
+            }
+
+            /************insert opening conditional if needed ********/
+            while(condtag[x]) {
+                if (!strcmp(condtag[x],readtagstypes[k].dtype) &&
+                    !strcmp(condtag[x+1],t->tag)) {
+                    okeydokey = 1;
+                    break;
+                }
+                x = x + 4;
+            }
+
+            /* some structs are entirely defined within another struct declaration.
+             * Legal, but unfortunate for us here.
+             */
+            substruct = strstr(t->parent, "::");
+            if (substruct) {
+                substruct += 2;
+            }
+
+            if ((strcmp(readtagstypes[k].dtype, t->parent) == 0) ||
+                 (substruct && strcmp(readtagstypes[k].dtype, substruct) == 0)) {
+                ft = (char *)0;
+                if (t->ptr[0])
+                    ft = &t->ptr[0];
+                else
+                    ft = findtype(t->searchtext, t->tag);
+                if (ft) {
+                    last_ft = ft;
+                    if (okeydokey && condtag[x+2] && strlen(condtag[x+2]) > 0) {
+                        Fprintf(SFO_DATA,"%s\n", condtag[x+2]);
+                        Fprintf(SFI_DATA,"%s\n", condtag[x+2]);
+                        Fprintf(SFDATATMP,"%s\n", condtag[x+2]);
+                    }
+                } else {
+                    /* use the last found one as last resort then */
+                    ft = last_ft;
+                }
+
+                /*****************  Bitfield *******************/
+                if (!strncmpi(ft, "Bitfield", 8)) {
+                    char lbuf[BUFSZ];
+                    int j, z;
+
+                    Sprintf(lbuf, 
+                            "    "
+                            "bitfield = d_%s->%s;",
+                            readtagstypes[k].dtype, t->tag);
+                    z = (int) strlen(lbuf);
+                    for (j = 0; j < (65 - z); ++j)
+                        Strcat(lbuf, " ");
+                    Sprintf(eos(lbuf), "/* (%s) */\n", ft);
+                    Fprintf(SFO_DATA, "%s", lbuf);
+                    Fprintf(SFO_DATA,
+                            "    "
+                            "sfo_bitfield(nhfp, &bitfield, parent, \"%s\", %s);\n",
+                            t->tag, bfsize(ft));       
+#if 0
+                    Fprintf(SFI_DATA,
+                            "    "
+                            "bitfield = 0;\n");
+#else
+                    Fprintf(SFI_DATA,
+                            "    "
+                            "bitfield = d_%s->%s;       /* set it to current value for testing */\n",
+                            readtagstypes[k].dtype, t->tag);
+#endif
+                    Fprintf(SFI_DATA,
+                            "    "
+                            "sfi_bitfield(nhfp, &bitfield, parent, \"%s\", %s);\n",
+                            t->tag, bfsize(ft));
+
+                    Fprintf(SFI_DATA,
+                            "    "
+                            "d_%s->%s = bitfield;\n\n",
+                            readtagstypes[k].dtype, t->tag);
+                    Fprintf(SFDATATMP,
+                            "\t\"%s:%s:%s\",\n",
+                            sfparent, t->tag, ft);
+                } else {
+                   /**************** not a bitfield ****************/
+                    char arrbuf[BUFSZ];
+                    char lbuf[BUFSZ];
+                    char fnbuf[BUFSZ];
+                    char altbuf[BUFSZ];
+                    boolean isptr = FALSE, kludge_sbrooms = FALSE;
+                    boolean insert_loop = FALSE;
+                    int j, z;
+
+                    /*************** kludge for sbrooms *************/
+                    if (!strcmp(t->tag, "sbrooms")) {
+                        kludge_sbrooms = TRUE;
+                        (void) strcpy(t->arraysize1,"MAX_SUBROOMS");
+                    }
+
+                    if (t->arraysize2[0]) {
+                        Sprintf(arrbuf, "(%s * %s)",
+                                t->arraysize1, t->arraysize2);
+                        isptr = TRUE; /* suppress the & in function args */
+                    } else if (t->arraysize1[0]) {
+                        Sprintf(arrbuf, "%s", t->arraysize1);
+                        isptr = TRUE; /* suppress the & in function args */
+                    } else {
+                        Strcpy(arrbuf, "1");
+                    }
+                    Strcpy(fnbuf, dtfn(ft,0,&isptr));
+                    /*
+                     * determine if this is one of the special cases
+                     * where there's an array of structs instead of
+                     * an array of simple types. We need to insert
+                     * a for loop in those cases.
+                     */
+                    for (a = 0; a < SIZE(nah); ++a) {
+                        if (!strcmp(nah[a].parent, t->parent))
+                            if (!strcmp(nah[a].nm, t->tag))
+                                insert_loop = TRUE;
+                    }
+
+                    if (isptr && !strcmp(fnbuf, readtagstypes[k].dtype)) {
+                        Strcpy(altbuf, "genericptr");
+                    } else if (isptr &&
+                              (!strcmp(t->ptr, "struct permonst *")  ||
+                               !strcmp(t->ptr, "struct monst *")     ||
+                               !strcmp(t->ptr, "struct obj *")       ||
+                               !strcmp(t->ptr, "struct cemetery *")  ||
+                               !strcmp(t->ptr, "struct container *") ||
+                               !strcmp(t->ptr, "struct mextra *")    ||
+                               !strcmp(t->ptr, "struct oextra *")    ||
+                               !strcmp(t->ptr, "struct s_level *")   ||
+                               !strcmp(t->ptr, "struct bill_x *")    ||
+                               !strcmp(t->ptr, "struct trap *"))) {
+                        Strcpy(altbuf, "genericptr");
+                    } else if (isptr &&
+                              (!strcmp(t->parent, "engr") &&
+                               !strcmp(t->tag, "engr_txt"))) {
+                        Strcpy(altbuf, "genericptr");
+                    } else if (isptr && !strcmp(t->tag, "oc_uname")) {
+                        Strcpy(altbuf, "genericptr");
+                    } else {
+                        Strcpy(altbuf, fnbuf);
+                    }
+
+                    if (insert_loop) {
+                        Fprintf(SFO_DATA,
+                                "    for (i = 0; i < %s; ++i)\n",
+                                arrbuf);
+                        Fprintf(SFI_DATA,
+                                "    for (i = 0; i < %s; ++i)\n",
+                                arrbuf);
+                        arrbuf[0] = '1';
+                        arrbuf[1] = '\0';
+                    }
+
+                    Sprintf(lbuf,
+                        "    "
+                        "%ssfo_%s(nhfp, %s%sd_%s->%s%s, parent, \"%s\", %s);",
+                        insert_loop ? "    " : "",
+                        altbuf,
+                        (isptr && !strcmp(altbuf, "genericptr")) ? "(genericptr_t) " : "",
+                        (isptr && !insert_loop && !kludge_sbrooms
+                                    && strcmp(altbuf, "genericptr")) ? "" : "&",
+                        readtagstypes[k].dtype,
+                        t->tag,
+                        kludge_sbrooms ? "[0]" : insert_loop ? "[i]" : "",
+                        t->tag,
+                        arrbuf);
+                    /* align comments */
+                    z = (int) strlen(lbuf);
+                    for (j = 0; j < (65 - z); ++j)
+                        Strcat(lbuf, " ");
+                    Sprintf(eos(lbuf), "/* (%s) */\n", ft);
+                    Fprintf(SFO_DATA, "%s", lbuf);
+
+                    Sprintf(lbuf,
+                        "    "
+                        "%ssfi_%s(nhfp, %s%sd_%s->%s%s, parent, \"%s\", %s);\n",
+                        insert_loop ? "    " : "",
+                        altbuf,
+                        (isptr && !strcmp(altbuf, "genericptr")) ? "(genericptr_t) " : "",
+                        (isptr && !insert_loop && !kludge_sbrooms
+                                    && strcmp(altbuf, "genericptr")) ? "" : "&",
+                        readtagstypes[k].dtype,
+                        t->tag,
+                        kludge_sbrooms ? "[0]" : insert_loop ? "[i]" : "",
+                        t->tag,
+                        arrbuf);
+                    Fprintf(SFI_DATA, "%s", lbuf);
+                    Fprintf(SFDATATMP,
+                        "\t\"%s:%s:%s\",\n",
+                        sfparent, t->tag,fieldfix(ft,ssdef));
+                    kludge_sbrooms = FALSE;
+                }
+
+                /************insert closing conditional if needed ********/
+                if (okeydokey && condtag[x+3] && strlen(condtag[x+3]) > 0) {
+                    Fprintf(SFO_DATA,"%s\n", condtag[x+3]);
+                    Fprintf(SFI_DATA,"%s\n", condtag[x+3]);
+                    Fprintf(SFDATATMP,"%s\n", condtag[x+3]);
+                }
+            }
+            t = t->next;
+        }
+
+        Fprintf(SFO_DATA, "\n");
+        Fprintf(SFI_DATA, "\n");
+
+        Fprintf(SFO_DATA,
+                "    if (nhfp->addinfo)\n"
+                "        sfo_addinfo(nhfp, myparent, \"end\", \"%s\", 1);\n",
+                readtagstypes[k].dtype);
+
+        Fprintf(SFI_DATA,
+                "    if (nhfp->addinfo)\n"
+                "        sfi_addinfo(nhfp, myparent, \"end\", \"%s\", 1);\n",
+                readtagstypes[k].dtype);
+
+        Fprintf(SFO_DATA, "}\n");
+        Fprintf(SFI_DATA, "}\n");
+        opening = 0;
+      }
+      ++k;
+      did_i = FALSE;
+    }
+
+    Fprintf(SFDATATMP,"};\n\n");
+    Fprintf(SFDATATMP, "int critical_members_count()\n{\n\treturn SIZE(critical_members);\n}\n\n");
+
+    fclose(SFO_DATA);
+    fclose(SFI_DATA);
+    fclose(SFO_PROTO);
+    fclose(SFI_PROTO);
+    fclose(SFDATATMP);
+
+    /* Consolidate SFO_* and SFI_* into single files */
+
+    SFO_DATA = fopen("../src/sfo_data.tmp", "r");
+    if (!SFO_DATA) return;
+    while ((line = fgetline(SFO_DATA)) != 0) {
+        (void) fputs(line, SFDATA);
+        free(line);
+    }
+    (void) fclose(SFO_DATA);
+    (void) remove("../src/sfo_data.tmp");   
+
+    SFI_DATA = fopen("../src/sfi_data.tmp", "r");
+    if (!SFI_DATA) return;
+    while ((line = fgetline(SFI_DATA)) != 0) {
+        (void) fputs(line, SFDATA);
+        free(line);
+    }
+    (void) fclose(SFI_DATA);
+    (void) remove("../src/sfi_data.tmp");   
+
+    SFO_PROTO = fopen("../include/sfo_proto.tmp", "r");
+    if (!SFO_PROTO) return;
+    while ((line = fgetline(SFO_PROTO)) != 0) {
+        (void) fputs(line, SFPROTO);
+        free(line);
+    }
+    (void) fclose(SFO_PROTO);
+    (void) remove("../include/sfo_proto.tmp");   
+
+    SFI_PROTO = fopen("../include/sfi_proto.tmp", "r");
+    if (!SFI_PROTO) return;
+    while ((line = fgetline(SFI_PROTO)) != 0) {
+        (void) fputs(line, SFPROTO);
+        free(line);
+    }
+    (void) fclose(SFI_PROTO);
+    (void) remove("../include/sfi_proto.tmp");   
+
+    SFDATATMP = fopen("../src/sfdata.tmp", "r");
+    if (!SFDATATMP) return;
+    while ((line = fgetline(SFDATATMP)) != 0) {
+        (void) fputs(line, SFDATA);
+        free(line);
+    }
+    (void) fclose(SFDATATMP);
+    (void) remove("../src/sfdata.tmp");   
+    
+    Fprintf(SFDATA, "/*sfdata.c*/\n");
+    Fprintf(SFPROTO,"#endif /* SFPROTO_H */\n");
+    (void) fclose(SFDATA);
+    (void) fclose(SFPROTO);
+}
+
+static char *
+dtmacro(str,n)
+const char *str;
+int n;     /* 1 = supress appending |SF_PTRMASK */
+{
+    static char buf[128], buf2[128];
+    char *nam, *c;
+    int ispointer = 0;
+
+    if (!str)
+        return (char *)0;
+    (void)strncpy(buf, str, 127);
+
+    c = buf;
+    while (*c)
+        c++;    /* eos */
+
+    c--;
+    if (*c == '*') {
+        ispointer = 1;
+        *c = '\0';
+        c--;
+    }
+    while(isspace(*c)) {
+        c--;
+    }
+    *(c+1) = '\0';
+    c = buf;
+
+    if (strncmpi(c, "Bitfield", 8) == 0) {
+        *(c+8) = '\0';
+    } else if (strcmpi(c, "genericptr_t") == 0) {
+        ispointer = 1;
+    } else if (strncmpi(c, "const ", 6) == 0) {
+        c = buf + 6;
+    } else if ((strncmpi(c, "struct ", 7) == 0) ||
+           (strncmpi(c, "struct\t", 7) == 0)) {
+        c = buf + 7;
+    } else if (strncmpi(c, "union ", 6) == 0) {
+        c = buf + 6;
+    }
+
+    /* end of substruct within struct definition */
+    if (strcmp(buf,"}") == 0 && strlen(ssdef) > 0) {
+        strcpy(buf,ssdef);
+        c = buf;
+    }
+
+    for (nam = c; *c; c++) {
+        if (*c >= 'a' && *c <= 'z')
+            *c -= (char)('a' - 'A');
+        else if (*c < 'A' || *c > 'Z')
+            *c = '_';
+    }
+    (void)sprintf(buf2, "SF_%s%s", nam,
+            (ispointer && (n == 0)) ? " | SF_PTRMASK" : "");
+    return buf2;
+}
+
+static char *
+dtfn(str,n, isptr)
+const char *str;
+int n;     /* 1 = supress appending |SF_PTRMASK */
+boolean *isptr;
+{
+    static char buf[128], buf2[128];
+    char *nam, *c;
+    int ispointer = 0;
+
+    if (!str)
+        return (char *)0;
+    (void)strncpy(buf, str, 127);
+
+    c = buf;
+    while (*c) c++;    /* eos */
+
+    c--;
+    if (*c == '*') {
+        ispointer = 1;
+        *c = '\0';
+        c--;
+    }
+    while(isspace(*c)) {
+        c--;
+    }
+    *(c+1) = '\0';
+    c = buf;
+
+    if (strncmpi(c, "Bitfield", 8) == 0) {
+        *(c+8) = '\0';
+    } else if (strcmpi(c, "genericptr_t") == 0) {
+        ispointer = 1;
+    } else if (strncmpi(c, "const ", 6) == 0) {
+        c = buf + 6;
+    } else if ((strncmpi(c, "struct ", 7) == 0) ||
+                   (strncmpi(c, "struct\t", 7) == 0)) {
+        c = buf + 7;
+    } else if (strncmpi(c, "union ", 6) == 0) {
+        c = buf + 6;
+    }
+
+    /* end of substruct within struct definition */
+    if (strcmp(buf,"}") == 0 && strlen(ssdef) > 0) {
+        strcpy(buf,ssdef);
+        c = buf;
+    }
+
+    for (nam = c; *c; c++) {
+        if (*c >= 'A' && *c <= 'Z')
+            *c = tolower(*c);
+        else if (*c == ' ')
+            *c = '_';
+    }
+    /* some fix-ups */
+    if (!strcmp(nam, "genericptr_t"))
+        nam = "genericptr";
+    else if (!strcmp(nam, "unsigned_int"))
+        nam = "uint";
+    else if (!strcmp(nam, "unsigned_long"))
+        nam = "ulong";
+    else if (!strcmp(nam, "unsigned_char"))
+        nam = "uchar";
+    else if (!strcmp(nam, "unsigned_short"))
+        nam = "ushort";
+
+    if (ispointer && isptr && n == 0)
+        *isptr = TRUE;
+    (void)sprintf(buf2, "%s%s", nam, "");
+    return buf2;
+}
+
+static char *
+fieldfix(f,ss)
+char *f, *ss;
+{
+    char *c, *dest = fieldfixbuf;
+
+    if (strcmp(f,"}") == 0 && strlen(ss) > 0 && strlen(ss) < BUFSZ - 1) {
+        /* (void)sprintf(fieldfixbuf,"struct %s", ss); */
+        strcpy(fieldfixbuf,ss);
+    } else {
+        if (strlen(f) < BUFSZ - 1) strcpy(fieldfixbuf,f);
+    }
+
+    /* converting any tabs to space */
+    for (c = fieldfixbuf; *c; c++)
+        if (*c == TAB) *c = SPACE;
+
+    return fieldfixbuf;
+}
+
+static char *
+bfsize(str)
+const char *str;
+{
+    static char buf[128];
+    const char *c1;
+    char *c2, *subst;
+
+    if (!str)
+        return (char *)0;
+
+    /* kludge */
+    subst = strstr(str, ",$/");
+    if (subst != 0) {
+        subst++;
+        *subst++ = ' ';
+        *subst++ = '1';
+    }
+    
+    c2 = buf;
+    c1 = str;
+    while (*c1) {
+        if (*c1 == ',')
+            break;
+        c1++;
+    }
+
+    if (*c1 == ',') {
+        c1++;
+        while (*c1 && *c1 != ')') {
+            *c2++ = *c1++;
+        }
+        *c2 = '\0';
+    } else {
+        return (char *)0;
+    }
+    return buf;
+}
+
+/* Read one line from input, up to and including the next newline
+ * character. Returns a pointer to the heap-allocated string, or a
+ * null pointer if no characters were read.
+ */
+static char *
+fgetline(fd)
+FILE *fd;
+{
+    static const int inc = 256;
+    int len = inc;
+    char *c = malloc(len), *ret;
+
+    for (;;) {
+        ret = fgets(c + len - inc, inc, fd);
+        if (!ret) {
+            free(c);
+            c = NULL;
+            break;
+        } else if (index(c, '\n')) {
+            /* normal case: we have a full line */
+            break;
+        }
+        len += inc;
+        c = realloc(c, len);
+    }
+    return c;
+}
+
+/*readtags2.c*/
+
+
index 5494094fd45eee318f44380ab299f59891d9e9a4..cfa359be481750989090be5b2c8d1e1f6148671b 100644 (file)
     <ClCompile Include="$(SrcDir)role.c" />\r
     <ClCompile Include="$(SrcDir)rumors.c" />\r
     <ClCompile Include="$(SrcDir)save.c" />\r
+    <ClCompile Include="$(SrcDir)sfstruct.c" />\r
+    <ClCompile Include="$(SrcDir)sfbase.c" />\r
+    <ClCompile Include="$(SrcDir)sflendian.c" />\r
+    <ClCompile Include="$(SrcDir)sfascii.c" />\r
+    <ClCompile Include="$(SrcDir)sfdata.c" />\r
     <ClCompile Include="$(SrcDir)shk.c" />\r
     <ClCompile Include="$(SrcDir)shknam.c" />\r
     <ClCompile Include="$(SrcDir)sit.c" />\r
   <Target Name="AfterRebuild">\r
     <MSBuild Projects="afternethack.proj" Targets="Build" Properties="Configuration=$(Configuration)" />\r
   </Target>\r
-</Project>
\ No newline at end of file
+</Project>\r
index 793158e0177b04126c8ca38421e43488cf7b00fa..4ee75a4b7f5b80fa812dce2ac6edd5e635cfcc4a 100644 (file)
     <ClCompile Include="$(SrcDir)role.c" />\r
     <ClCompile Include="$(SrcDir)rumors.c" />\r
     <ClCompile Include="$(SrcDir)save.c" />\r
+    <ClCompile Include="$(SrcDir)sfstruct.c" />\r
+    <ClCompile Include="$(SrcDir)sfbase.c" />\r
+    <ClCompile Include="$(SrcDir)sflendian.c" />\r
+    <ClCompile Include="$(SrcDir)sfascii.c" />\r
+    <ClCompile Include="$(SrcDir)sfdata.c" />\r
     <ClCompile Include="$(SrcDir)shk.c" />\r
     <ClCompile Include="$(SrcDir)shknam.c" />\r
     <ClCompile Include="$(SrcDir)sit.c" />\r