Source:SLASH'EM 0.0.7E7F2/save.c

From NetHackWiki
Jump to navigation Jump to search

Below is the full text to save.c from the source code of SLASH'EM 0.0.7E7F2. To link to a particular line, write [[SLASH'EM 0.0.7E7F2/save.c#line123]], for example.

The latest source code for vanilla NetHack is at Source code.


The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

1.    /*	SCCS Id: @(#)save.c	3.4	2003/11/14	*/
2.    /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3.    /* NetHack may be freely redistributed.  See license for details. */
4.    
5.    #include "hack.h"
6.    #include "lev.h"
7.    #include "quest.h"
8.    
9.    #ifndef NO_SIGNAL
10.   #include <signal.h>
11.   #endif
12.   #if !defined(LSC) && !defined(O_WRONLY) && !defined(AZTEC_C)
13.   #include <fcntl.h>
14.   #endif
15.   
16.   #ifdef MFLOPPY
17.   long bytes_counted;
18.   static int count_only;
19.   #endif
20.   
21.   /*WAC boolean here to keep track of quit status*/
22.   boolean saverestore;
23.   
24.   #ifdef MICRO
25.   int dotcnt, dotrow;	/* also used in restore */
26.   #endif
27.   
28.   #ifdef ZEROCOMP
29.   STATIC_DCL void FDECL(bputc, (int));
30.   #endif
31.   STATIC_DCL void FDECL(savelevchn, (int,int));
32.   STATIC_DCL void FDECL(savedamage, (int,int));
33.   STATIC_DCL void FDECL(saveobjchn, (int,struct obj *,int));
34.   STATIC_DCL void FDECL(savemonchn, (int,struct monst *,int));
35.   STATIC_DCL void FDECL(savetrapchn, (int,struct trap *,int));
36.   STATIC_DCL void FDECL(savegamestate, (int,int));
37.   #ifdef MFLOPPY
38.   STATIC_DCL void FDECL(savelev0, (int,XCHAR_P,int));
39.   STATIC_DCL boolean NDECL(swapout_oldest);
40.   STATIC_DCL void FDECL(copyfile, (char *,char *));
41.   #endif /* MFLOPPY */
42.   #ifdef GCC_WARN
43.   static long nulls[10];
44.   #else
45.   #define nulls nul
46.   #endif
47.   
48.   #if defined(UNIX) || defined(VMS) || defined(__EMX__) || defined(WIN32)
49.   #define HUP	if (!program_state.done_hup)
50.   #else
51.   #define HUP
52.   #endif
53.   
54.   #ifdef MENU_COLOR
55.   extern struct menucoloring *menu_colorings;
56.   #endif
57.   
58.   /* need to preserve these during save to avoid accessing freed memory */
59.   static unsigned ustuck_id = 0, usteed_id = 0;
60.   
61.   int
62.   dosave()
63.   {
64.   #ifdef KEEP_SAVE
65.   	/*WAC for reloading*/
66.   	register int fd;
67.   #endif
68.   
69.   	clear_nhwindow(WIN_MESSAGE);
70.   	if(yn("Really save?") == 'n') {
71.   		clear_nhwindow(WIN_MESSAGE);
72.   		if(multi > 0) nomul(0);
73.   	} else {
74.   		clear_nhwindow(WIN_MESSAGE);
75.   		pline("Saving...");
76.   #if defined(UNIX) || defined(VMS) || defined(__EMX__)
77.   		program_state.done_hup = 0;
78.   #endif
79.   #ifdef KEEP_SAVE
80.                   saverestore = FALSE;
81.                   if (flags.keep_savefile)
82.                           if(yn("Really quit?") == 'n') saverestore = TRUE;
83.                   if(dosave0() && !saverestore) {
84.   #else
85.   		if(dosave0()) {
86.   #endif
87.   			program_state.something_worth_saving = 0;
88.   			u.uhp = -1;		/* universal game's over indicator */
89.   			/* make sure they see the Saving message */
90.   			display_nhwindow(WIN_MESSAGE, TRUE);
91.   			exit_nhwindows("Be seeing you...");
92.   			terminate(EXIT_SUCCESS);
93.   	}
94.   /*WAC redraw later
95.   		else (void)doredraw();*/
96.   	}
97.   #ifdef KEEP_SAVE
98.   	if (saverestore) {
99.   /*WAC pulled this from pcmain.c - restore game from the file just saved*/
100.  		fd = create_levelfile(0);
101.  		if (fd < 0) {
102.  			raw_print("Cannot create lock file");
103.  		} else {
104.  			hackpid = 1;
105.  			write(fd, (genericptr_t) &hackpid, sizeof(hackpid));
106.  			close(fd);
107.  		}
108.  #ifdef MFLOPPY
109.  		level_info[0].where = ACTIVE;
110.  #endif
111.  
112.  		fd = restore_saved_game();
113.  		if (fd >= 0) dorecover(fd);
114.  		check_special_room(FALSE);
115.  		flags.move = 0;
116.  /*WAC correct these after restore*/
117.  		if(flags.moonphase == FULL_MOON)
118.  			change_luck(1);         
119.  		if(flags.friday13)
120.  			change_luck(-1);
121.  		if(iflags.window_inited)
122.  			clear_nhwindow(WIN_MESSAGE);
123.  	}
124.  	saverestore = FALSE;
125.  #endif
126.  	(void)doredraw();
127.  	return 0;
128.  }
129.  
130.  
131.  #if defined(UNIX) || defined(VMS) || defined (__EMX__) || defined(WIN32)
132.  /*ARGSUSED*/
133.  void
134.  hangup(sig_unused)  /* called as signal() handler, so sent at least one arg */
135.  int sig_unused;
136.  {
137.  # ifdef NOSAVEONHANGUP
138.  	(void) signal(SIGINT, SIG_IGN);
139.  	clearlocks();
140.  #  ifndef VMS
141.  	terminate(EXIT_FAILURE);
142.  #  endif
143.  # else	/* SAVEONHANGUP */
144.  	if (!program_state.done_hup++) {
145.  	    if (program_state.something_worth_saving)
146.  		(void) dosave0();
147.  #  ifdef VMS
148.  	    /* don't call exit when already within an exit handler;
149.  	       that would cancel any other pending user-mode handlers */
150.  	    if (!program_state.exiting)
151.  #  endif
152.  	    {
153.  		clearlocks();
154.  		terminate(EXIT_FAILURE);
155.  	    }
156.  	}
157.  # endif
158.  	return;
159.  }
160.  #endif
161.  
162.  /* returns 1 if save successful */
163.  int
164.  dosave0()
165.  {
166.  	const char *fq_save;
167.  	register int fd, ofd;
168.  	xchar ltmp;
169.  	d_level uz_save;
170.  	char whynot[BUFSZ];
171.  
172.  	if (!SAVEF[0])
173.  		return 0;
174.  	fq_save = fqname(SAVEF, SAVEPREFIX, 1);	/* level files take 0 */
175.  
176.  #if defined(UNIX) || defined(VMS)
177.  	(void) signal(SIGHUP, SIG_IGN);
178.  #endif
179.  #ifndef NO_SIGNAL
180.  	(void) signal(SIGINT, SIG_IGN);
181.  #endif
182.  
183.  #if defined(MICRO) && defined(MFLOPPY)
184.  	if (!saveDiskPrompt(0)) return 0;
185.  #endif
186.  
187.  	HUP if (iflags.window_inited) {
188.  	    uncompress_area(fq_save, SAVEF);
189.  	    fd = open_savefile();
190.  	    if (fd > 0) {
191.  		(void) close(fd);
192.  		clear_nhwindow(WIN_MESSAGE);
193.  		There("seems to be an old save file.");
194.  		if (yn("Overwrite the old file?") == 'n') {
195.  		    compress_area(fq_save, SAVEF);
196.  #ifdef KEEP_SAVE
197.  /*WAC don't restore if you didn't save*/
198.  			saverestore = FALSE;
199.  #endif
200.  		    return 0;
201.  		}
202.  	    }
203.  	}
204.  
205.  	HUP mark_synch();	/* flush any buffered screen output */
206.  
207.  	fd = create_savefile();
208.  	if(fd < 0) {
209.  		HUP pline("Cannot open save file.");
210.  		(void) delete_savefile();	/* ab@unido */
211.  		return(0);
212.  	}
213.  
214.  	vision_recalc(2);	/* shut down vision to prevent problems
215.  				   in the event of an impossible() call */
216.  	
217.  	/* undo date-dependent luck adjustments made at startup time */
218.  	if(flags.moonphase == FULL_MOON)	/* ut-sally!fletcher */
219.  		change_luck(-1);		/* and unido!ab */
220.  	if(flags.friday13)
221.  		change_luck(1);
222.  	if(iflags.window_inited)
223.  	    HUP clear_nhwindow(WIN_MESSAGE);
224.  
225.  #if defined(MICRO) && defined(TTY_GRAPHICS)
226.  	if (!strncmpi("tty", windowprocs.name, 3)) {
227.  	dotcnt = 0;
228.  	dotrow = 2;
229.  	curs(WIN_MAP, 1, 1);
230.  	  putstr(WIN_MAP, 0, "Saving:");
231.  	}
232.  #endif
233.  #ifdef MFLOPPY
234.  	/* make sure there is enough disk space */
235.  	if (iflags.checkspace) {
236.  	    long fds, needed;
237.  
238.  	    savelev(fd, ledger_no(&u.uz), COUNT_SAVE);
239.  	    savegamestate(fd, COUNT_SAVE);
240.  	    needed = bytes_counted;
241.  
242.  	    for (ltmp = 1; ltmp <= maxledgerno(); ltmp++)
243.  		if (ltmp != ledger_no(&u.uz) && level_info[ltmp].where)
244.  		    needed += level_info[ltmp].size + (sizeof ltmp);
245.  	    fds = freediskspace(fq_save);
246.  	    if (needed > fds) {
247.  		HUP {
248.  		    There("is insufficient space on SAVE disk.");
249.  		    pline("Require %ld bytes but only have %ld.", needed, fds);
250.  		}
251.  		flushout();
252.  		(void) close(fd);
253.  		(void) delete_savefile();
254.  		return 0;
255.  	    }
256.  
257.  	    co_false();
258.  	}
259.  #endif /* MFLOPPY */
260.  
261.  	store_version(fd);
262.  #ifdef STORE_PLNAME_IN_FILE
263.  	bwrite(fd, (genericptr_t) plname, PL_NSIZ);
264.  #endif
265.  	ustuck_id = (u.ustuck ? u.ustuck->m_id : 0);
266.  #ifdef STEED
267.  	usteed_id = (u.usteed ? u.usteed->m_id : 0);
268.  #endif
269.  
270.  	savelev(fd, ledger_no(&u.uz), WRITE_SAVE | FREE_SAVE);
271.  /*Keep things from beeing freed if not restoring*/
272.  /*
273.  #ifdef KEEP_SAVE
274.  	if (saverestore) savegamestate(fd, WRITE_SAVE);
275.  	else
276.  #endif
277.  */
278.  	savegamestate(fd, WRITE_SAVE | FREE_SAVE);
279.  
280.  	/* While copying level files around, zero out u.uz to keep
281.  	 * parts of the restore code from completely initializing all
282.  	 * in-core data structures, since all we're doing is copying.
283.  	 * This also avoids at least one nasty core dump.
284.  	 */
285.  	uz_save = u.uz;
286.  	u.uz.dnum = u.uz.dlevel = 0;
287.  	/* these pointers are no longer valid, and at least u.usteed
288.  	 * may mislead place_monster() on other levels
289.  	 */
290.  	setustuck((struct monst *)0);
291.  #ifdef STEED
292.  	u.usteed = (struct monst *)0;
293.  #endif
294.  
295.  	for(ltmp = (xchar)1; ltmp <= maxledgerno(); ltmp++) {
296.  		if (ltmp == ledger_no(&uz_save)) continue;
297.  		if (!(level_info[ltmp].flags & LFILE_EXISTS)) continue;
298.  #if defined(MICRO) && defined(TTY_GRAPHICS)
299.  		curs(WIN_MAP, 1 + dotcnt++, dotrow);
300.  		if (dotcnt >= (COLNO - 1)) {
301.  			dotrow++;
302.  			dotcnt = 0;
303.  		}
304.  		  putstr(WIN_MAP, 0, ".");
305.  		mark_synch();
306.  #endif
307.  		ofd = open_levelfile(ltmp, whynot);
308.  		if (ofd < 0) {
309.  		    HUP pline("%s", whynot);
310.  		    (void) close(fd);
311.  		    (void) delete_savefile();
312.  		    HUP killer = whynot;
313.  		    HUP done(TRICKED);
314.  		    return(0);
315.  		}
316.  		minit();	/* ZEROCOMP */
317.  		getlev(ofd, hackpid, ltmp, FALSE);
318.  		(void) close(ofd);
319.  		bwrite(fd, (genericptr_t) &ltmp, sizeof ltmp); /* level number*/
320.  		savelev(fd, ltmp, WRITE_SAVE | FREE_SAVE);     /* actual level*/
321.  		delete_levelfile(ltmp);
322.  	}
323.  	bclose(fd);
324.  
325.  	u.uz = uz_save;
326.  
327.  	/* get rid of current level --jgm */
328.  
329.  	delete_levelfile(ledger_no(&u.uz));
330.  	delete_levelfile(0);
331.  	compress_area(FILE_AREA_SAVE, fq_save);
332.  	return(1);
333.  }
334.  
335.  STATIC_OVL void
336.  savegamestate(fd, mode)
337.  register int fd, mode;
338.  {
339.  	int uid;
340.  
341.  #ifdef MFLOPPY
342.  	count_only = (mode & COUNT_SAVE);
343.  #endif
344.  	uid = getuid();
345.  	bwrite(fd, (genericptr_t) &uid, sizeof uid);
346.  	bwrite(fd, (genericptr_t) &flags, sizeof(struct flag));
347.  	bwrite(fd, (genericptr_t) &u, sizeof(struct you));
348.  
349.  	/* must come before migrating_objs and migrating_mons are freed */
350.  	save_timers(fd, mode, RANGE_GLOBAL);
351.  	save_light_sources(fd, mode, RANGE_GLOBAL);
352.  
353.  	saveobjchn(fd, invent, mode);
354.  	saveobjchn(fd, migrating_objs, mode);
355.  	savemonchn(fd, migrating_mons, mode);
356.  	if (release_data(mode)) {
357.  	    invent = 0;
358.  	    migrating_objs = 0;
359.  	    migrating_mons = 0;
360.  	}
361.  	bwrite(fd, (genericptr_t) mvitals, sizeof(mvitals));
362.  
363.  	save_dungeon(fd, (boolean)!!perform_bwrite(mode),
364.  			 (boolean)!!release_data(mode));
365.  	savelevchn(fd, mode);
366.  	bwrite(fd, (genericptr_t) &moves, sizeof moves);
367.  	bwrite(fd, (genericptr_t) &monstermoves, sizeof monstermoves);
368.  	bwrite(fd, (genericptr_t) &quest_status, sizeof(struct q_score));
369.  	bwrite(fd, (genericptr_t) spl_book,
370.  				sizeof(struct spell) * (MAXSPELL + 1));
371.  	bwrite(fd, (genericptr_t) tech_list,
372.  			sizeof(struct tech) * (MAXTECH + 1));
373.  	save_artifacts(fd);
374.  	save_oracles(fd, mode);
375.  	if(ustuck_id)
376.  	    bwrite(fd, (genericptr_t) &ustuck_id, sizeof ustuck_id);
377.  #ifdef STEED
378.  	if(usteed_id)
379.  	    bwrite(fd, (genericptr_t) &usteed_id, sizeof usteed_id);
380.  #endif
381.  	bwrite(fd, (genericptr_t) pl_character, sizeof pl_character);
382.  	bwrite(fd, (genericptr_t) pl_fruit, sizeof pl_fruit);
383.  	bwrite(fd, (genericptr_t) &current_fruit, sizeof current_fruit);
384.  	savefruitchn(fd, mode);
385.  	savenames(fd, mode);
386.  	save_waterlevel(fd, mode);
387.  	bflush(fd);
388.  }
389.  
390.  #ifdef INSURANCE
391.  void
392.  savestateinlock()
393.  {
394.  	int fd, hpid;
395.  	static boolean havestate = TRUE;
396.  	char whynot[BUFSZ];
397.  
398.  	/* When checkpointing is on, the full state needs to be written
399.  	 * on each checkpoint.  When checkpointing is off, only the pid
400.  	 * needs to be in the level.0 file, so it does not need to be
401.  	 * constantly rewritten.  When checkpointing is turned off during
402.  	 * a game, however, the file has to be rewritten once to truncate
403.  	 * it and avoid restoring from outdated information.
404.  	 *
405.  	 * Restricting havestate to this routine means that an additional
406.  	 * noop pid rewriting will take place on the first "checkpoint" after
407.  	 * the game is started or restored, if checkpointing is off.
408.  	 */
409.  	if (flags.ins_chkpt || havestate) {
410.  		/* save the rest of the current game state in the lock file,
411.  		 * following the original int pid, the current level number,
412.  		 * and the current savefile name, which should not be subject
413.  		 * to any internal compression schemes since they must be
414.  		 * readable by an external utility
415.  		 */
416.  		fd = open_levelfile(0, whynot);
417.  		if (fd < 0) {
418.  		    pline("%s", whynot);
419.  		    pline("Probably someone removed it.");
420.  		    killer = whynot;
421.  		    done(TRICKED);
422.  		    return;
423.  		}
424.  
425.  		(void) read(fd, (genericptr_t) &hpid, sizeof(hpid));
426.  		if (hackpid != hpid) {
427.  		    Sprintf(whynot,
428.  			    "Level #0 pid (%d) doesn't match ours (%d)!",
429.  			    hpid, hackpid);
430.  		    pline("%s", whynot);
431.  		    killer = whynot;
432.  		    done(TRICKED);
433.  		}
434.  		(void) close(fd);
435.  
436.  		fd = create_levelfile(0, whynot);
437.  		if (fd < 0) {
438.  		    pline("%s", whynot);
439.  		    killer = whynot;
440.  		    done(TRICKED);
441.  		    return;
442.  		}
443.  		(void) write(fd, (genericptr_t) &hackpid, sizeof(hackpid));
444.  		if (flags.ins_chkpt) {
445.  		    int currlev = ledger_no(&u.uz);
446.  
447.  		    (void) write(fd, (genericptr_t) &currlev, sizeof(currlev));
448.  		    save_savefile_name(fd);
449.  		    store_version(fd);
450.  #ifdef STORE_PLNAME_IN_FILE
451.  		    bwrite(fd, (genericptr_t) plname, PL_NSIZ);
452.  #endif
453.  		    ustuck_id = (u.ustuck ? u.ustuck->m_id : 0);
454.  #ifdef STEED
455.  		    usteed_id = (u.usteed ? u.usteed->m_id : 0);
456.  #endif
457.  		    savegamestate(fd, WRITE_SAVE);
458.  		}
459.  		bclose(fd);
460.  	}
461.  	havestate = flags.ins_chkpt;
462.  }
463.  #endif
464.  
465.  #ifdef MFLOPPY
466.  boolean
467.  savelev(fd, lev, mode)
468.  int fd;
469.  xchar lev;
470.  int mode;
471.  {
472.  	if (mode & COUNT_SAVE) {
473.  		bytes_counted = 0;
474.  		savelev0(fd, lev, COUNT_SAVE);
475.  		/* probably bytes_counted will be filled in again by an
476.  		 * immediately following WRITE_SAVE anyway, but we'll
477.  		 * leave it out of checkspace just in case */
478.  		if (iflags.checkspace) {
479.  			while (bytes_counted > freediskspace(levels))
480.  				if (!swapout_oldest())
481.  					return FALSE;
482.  		}
483.  	}
484.  	if (mode & (WRITE_SAVE | FREE_SAVE)) {
485.  		bytes_counted = 0;
486.  		savelev0(fd, lev, mode);
487.  	}
488.  	if (mode != FREE_SAVE) {
489.  		level_info[lev].where = ACTIVE;
490.  		level_info[lev].time = moves;
491.  		level_info[lev].size = bytes_counted;
492.  	}
493.  	return TRUE;
494.  }
495.  
496.  STATIC_OVL void
497.  savelev0(fd,lev,mode)
498.  #else
499.  void
500.  savelev(fd,lev,mode)
501.  #endif
502.  int fd;
503.  xchar lev;
504.  int mode;
505.  {
506.  #ifdef TOS
507.  	short tlev;
508.  #endif
509.  
510.  	/* if we're tearing down the current level without saving anything
511.  	   (which happens upon entrance to the endgame or after an aborted
512.  	   restore attempt) then we don't want to do any actual I/O */
513.  	if (mode == FREE_SAVE) goto skip_lots;
514.  	if (iflags.purge_monsters) {
515.  		/* purge any dead monsters (necessary if we're starting
516.  		 * a panic save rather than a normal one, or sometimes
517.  		 * when changing levels without taking time -- e.g.
518.  		 * create statue trap then immediately level teleport) */
519.  		dmonsfree();
520.  	}
521.  
522.  	if(fd < 0) panic("Save on bad file!");	/* impossible */
523.  #ifdef MFLOPPY
524.  	count_only = (mode & COUNT_SAVE);
525.  #endif
526.  	if (lev >= 0 && lev <= maxledgerno())
527.  	    level_info[lev].flags |= VISITED;
528.  	bwrite(fd,(genericptr_t) &hackpid,sizeof(hackpid));
529.  #ifdef TOS
530.  	tlev=lev; tlev &= 0x00ff;
531.  	bwrite(fd,(genericptr_t) &tlev,sizeof(tlev));
532.  #else
533.  	bwrite(fd,(genericptr_t) &lev,sizeof(lev));
534.  #endif
535.  #ifdef RLECOMP
536.  	{
537.  	    /* perform run-length encoding of rm structs */
538.  	    struct rm *prm, *rgrm;
539.  	    int x, y;
540.  	    uchar match;
541.  
542.  	    rgrm = &levl[0][0];		/* start matching at first rm */
543.  	    match = 0;
544.  
545.  	    for (y = 0; y < ROWNO; y++) {
546.  		for (x = 0; x < COLNO; x++) {
547.  		    prm = &levl[x][y];
548.  #ifdef DISPLAY_LAYERS
549.  		    if (prm->mem_bg == rgrm->mem_bg
550.  			&& prm->mem_trap == rgrm->mem_trap
551.  			&& prm->mem_obj == rgrm->mem_obj
552.  			&& prm->mem_corpse == rgrm->mem_corpse
553.  			&& prm->mem_invis == rgrm->mem_invis
554.  #else
555.  		    if (prm->glyph == rgrm->glyph
556.  #endif
557.  			&& prm->typ == rgrm->typ
558.  			&& prm->seenv == rgrm->seenv
559.  			&& prm->horizontal == rgrm->horizontal
560.  			&& prm->flags == rgrm->flags
561.  			&& prm->lit == rgrm->lit
562.  			&& prm->waslit == rgrm->waslit
563.  			&& prm->roomno == rgrm->roomno
564.  			&& prm->edge == rgrm->edge) {
565.  			match++;
566.  			if (match > 254) {
567.  			    match = 254;	/* undo this match */
568.  			    goto writeout;
569.  			}
570.  		    } else {
571.  			/* the run has been broken,
572.  			 * write out run-length encoding */
573.  		    writeout:
574.  			bwrite(fd, (genericptr_t)&match, sizeof(uchar));
575.  			bwrite(fd, (genericptr_t)rgrm, sizeof(struct rm));
576.  			/* start encoding again. we have at least 1 rm
577.  			 * in the next run, viz. this one. */
578.  			match = 1;
579.  			rgrm = prm;
580.  		    }
581.  		}
582.  	    }
583.  	    if (match > 0) {
584.  		bwrite(fd, (genericptr_t)&match, sizeof(uchar));
585.  		bwrite(fd, (genericptr_t)rgrm, sizeof(struct rm));
586.  	    }
587.  	}
588.  #else
589.  	bwrite(fd,(genericptr_t) levl,sizeof(levl));
590.  #endif /* RLECOMP */
591.  
592.  	bwrite(fd,(genericptr_t) &monstermoves,sizeof(monstermoves));
593.  	bwrite(fd,(genericptr_t) &upstair,sizeof(stairway));
594.  	bwrite(fd,(genericptr_t) &dnstair,sizeof(stairway));
595.  	bwrite(fd,(genericptr_t) &upladder,sizeof(stairway));
596.  	bwrite(fd,(genericptr_t) &dnladder,sizeof(stairway));
597.  	bwrite(fd,(genericptr_t) &sstairs,sizeof(stairway));
598.  	bwrite(fd,(genericptr_t) &updest,sizeof(dest_area));
599.  	bwrite(fd,(genericptr_t) &dndest,sizeof(dest_area));
600.  	bwrite(fd,(genericptr_t) &level.flags,sizeof(level.flags));
601.  	bwrite(fd, (genericptr_t) doors, sizeof(doors));
602.  	save_rooms(fd);	/* no dynamic memory to reclaim */
603.  
604.  	/* from here on out, saving also involves allocated memory cleanup */
605.   skip_lots:
606.  	/* must be saved before mons, objs, and buried objs */
607.  	save_timers(fd, mode, RANGE_LEVEL);
608.  	save_light_sources(fd, mode, RANGE_LEVEL);
609.  
610.  	savemonchn(fd, fmon, mode);
611.  	save_worm(fd, mode);	/* save worm information */
612.  	savetrapchn(fd, ftrap, mode);
613.  	saveobjchn(fd, fobj, mode);
614.  	saveobjchn(fd, level.buriedobjlist, mode);
615.  	saveobjchn(fd, billobjs, mode);
616.  	if (release_data(mode)) {
617.  	    fmon = 0;
618.  	    ftrap = 0;
619.  	    fobj = 0;
620.  	    level.buriedobjlist = 0;
621.  	    billobjs = 0;
622.  	}
623.  	save_engravings(fd, mode);
624.  	savedamage(fd, mode);
625.  	save_regions(fd, mode);
626.  	if (mode != FREE_SAVE) bflush(fd);
627.  }
628.  
629.  #ifdef ZEROCOMP
630.  /* The runs of zero-run compression are flushed after the game state or a
631.   * level is written out.  This adds a couple bytes to a save file, where
632.   * the runs could be mashed together, but it allows gluing together game
633.   * state and level files to form a save file, and it means the flushing
634.   * does not need to be specifically called for every other time a level
635.   * file is written out.
636.   */
637.  
638.  #define RLESC '\0'    /* Leading character for run of LRESC's */
639.  #define flushoutrun(ln) (bputc(RLESC), bputc(ln), ln = -1)
640.  
641.  #ifndef ZEROCOMP_BUFSIZ
642.  # define ZEROCOMP_BUFSIZ BUFSZ
643.  #endif
644.  static NEARDATA unsigned char outbuf[ZEROCOMP_BUFSIZ];
645.  static NEARDATA unsigned short outbufp = 0;
646.  static NEARDATA short outrunlength = -1;
647.  static NEARDATA int bwritefd;
648.  static NEARDATA boolean compressing = FALSE;
649.  
650.  /*dbg()
651.  {
652.      HUP printf("outbufp %d outrunlength %d\n", outbufp,outrunlength);
653.  }*/
654.  
655.  STATIC_OVL void
656.  bputc(c)
657.  int c;
658.  {
659.  #ifdef MFLOPPY
660.      bytes_counted++;
661.      if (count_only)
662.        return;
663.  #endif
664.      if (outbufp >= sizeof outbuf) {
665.  	(void) write(bwritefd, outbuf, sizeof outbuf);
666.  	outbufp = 0;
667.      }
668.      outbuf[outbufp++] = (unsigned char)c;
669.  }
670.  
671.  /*ARGSUSED*/
672.  void
673.  bufon(fd)
674.  int fd;
675.  {
676.      compressing = TRUE;
677.      return;
678.  }
679.  
680.  /*ARGSUSED*/
681.  void
682.  bufoff(fd)
683.  int fd;
684.  {
685.      if (outbufp) {
686.  	outbufp = 0;
687.  	panic("closing file with buffered data still unwritten");
688.      }
689.      outrunlength = -1;
690.      compressing = FALSE;
691.      return;
692.  }
693.  
694.  void
695.  bflush(fd)  /* flush run and buffer */
696.  register int fd;
697.  {
698.      bwritefd = fd;
699.      if (outrunlength >= 0) {	/* flush run */
700.  	flushoutrun(outrunlength);
701.      }
702.  #ifdef MFLOPPY
703.      if (count_only) outbufp = 0;
704.  #endif
705.  
706.      if (outbufp) {
707.  	if (write(fd, outbuf, outbufp) != outbufp) {
708.  #if defined(UNIX) || defined(VMS) || defined(__EMX__)
709.  	    if (program_state.done_hup)
710.  		terminate(EXIT_FAILURE);
711.  	    else
712.  #endif
713.  		bclose(fd);	/* panic (outbufp != 0) */
714.  	}
715.  	outbufp = 0;
716.      }
717.  }
718.  
719.  void
720.  bwrite(fd, loc, num)
721.  int fd;
722.  genericptr_t loc;
723.  register unsigned num;
724.  {
725.      register unsigned char *bp = (unsigned char *)loc;
726.  
727.      if (!compressing) {
728.  #ifdef MFLOPPY
729.  	bytes_counted += num;
730.  	if (count_only) return;
731.  #endif
732.  	if ((unsigned) write(fd, loc, num) != num) {
733.  #if defined(UNIX) || defined(VMS) || defined(__EMX__)
734.  	    if (program_state.done_hup)
735.  		terminate(EXIT_FAILURE);
736.  	    else
737.  #endif
738.  		panic("cannot write %u bytes to file #%d", num, fd);
739.  	}
740.      } else {
741.  	bwritefd = fd;
742.  	for (; num; num--, bp++) {
743.  	    if (*bp == RLESC) {	/* One more char in run */
744.  		if (++outrunlength == 0xFF) {
745.  		    flushoutrun(outrunlength);
746.  		}
747.  	    } else {		/* end of run */
748.  		if (outrunlength >= 0) {	/* flush run */
749.  		    flushoutrun(outrunlength);
750.  		}
751.  		bputc(*bp);
752.  	    }
753.  	}
754.      }
755.  }
756.  
757.  void
758.  bclose(fd)
759.  int fd;
760.  {
761.      bufoff(fd);
762.      (void) close(fd);
763.      return;
764.  }
765.  
766.  #else /* ZEROCOMP */
767.  
768.  static int bw_fd = -1;
769.  static FILE *bw_FILE = 0;
770.  static boolean buffering = FALSE;
771.  
772.  void
773.  bufon(fd)
774.      int fd;
775.  {
776.  #ifdef UNIX
777.      if(bw_fd >= 0)
778.  	panic("double buffering unexpected");
779.      bw_fd = fd;
780.      if((bw_FILE = fdopen(fd, "w")) == 0)
781.  	panic("buffering of file %d failed", fd);
782.  #endif
783.      buffering = TRUE;
784.  }
785.  
786.  void
787.  bufoff(fd)
788.  int fd;
789.  {
790.      bflush(fd);
791.      buffering = FALSE;
792.  }
793.  
794.  void
795.  bflush(fd)
796.      int fd;
797.  {
798.  #ifdef UNIX
799.      if(fd == bw_fd) {
800.  	if(fflush(bw_FILE) == EOF)
801.  	    panic("flush of savefile failed!");
802.      }
803.  #endif
804.      return;
805.  }
806.  
807.  void
808.  bwrite(fd,loc,num)
809.  register int fd;
810.  register genericptr_t loc;
811.  register unsigned num;
812.  {
813.  	boolean failed;
814.  
815.  #ifdef MFLOPPY
816.  	bytes_counted += num;
817.  	if (count_only) return;
818.  #endif
819.  
820.  #ifdef UNIX
821.  	if (buffering) {
822.  	    if(fd != bw_fd)
823.  		panic("unbuffered write to fd %d (!= %d)", fd, bw_fd);
824.  
825.  	    failed = (fwrite(loc, (int)num, 1, bw_FILE) != 1);
826.  	} else
827.  #endif /* UNIX */
828.  	{
829.  /* lint wants the 3rd arg of write to be an int; lint -p an unsigned */
830.  #if defined(BSD) || defined(ULTRIX)
831.  	    failed = (write(fd, loc, (int)num) != (int)num);
832.  #else /* e.g. SYSV, __TURBOC__ */
833.  	    failed = (write(fd, loc, num) != num);
834.  #endif
835.  	}
836.  
837.  	if (failed) {
838.  #if defined(UNIX) || defined(VMS) || defined(__EMX__)
839.  	    if (program_state.done_hup)
840.  		terminate(EXIT_FAILURE);
841.  	    else
842.  #endif
843.  		panic("cannot write %u bytes to file #%d", num, fd);
844.  	}
845.  }
846.  
847.  void
848.  bclose(fd)
849.      int fd;
850.  {
851.      bufoff(fd);
852.  #ifdef UNIX
853.      if (fd == bw_fd) {
854.  	(void) fclose(bw_FILE);
855.  	bw_fd = -1;
856.  	bw_FILE = 0;
857.      } else
858.  #endif
859.  	(void) close(fd);
860.      return;
861.  }
862.  #endif /* ZEROCOMP */
863.  
864.  STATIC_OVL void
865.  savelevchn(fd, mode)
866.  register int fd, mode;
867.  {
868.  	s_level	*tmplev, *tmplev2;
869.  	int cnt = 0;
870.  
871.  	for (tmplev = sp_levchn; tmplev; tmplev = tmplev->next) cnt++;
872.  	if (perform_bwrite(mode))
873.  	    bwrite(fd, (genericptr_t) &cnt, sizeof(int));
874.  
875.  	for (tmplev = sp_levchn; tmplev; tmplev = tmplev2) {
876.  	    tmplev2 = tmplev->next;
877.  	    if (perform_bwrite(mode))
878.  		bwrite(fd, (genericptr_t) tmplev, sizeof(s_level));
879.  	    if (release_data(mode))
880.  		free((genericptr_t) tmplev);
881.  	}
882.  	if (release_data(mode))
883.  	    sp_levchn = 0;
884.  }
885.  
886.  STATIC_OVL void
887.  savedamage(fd, mode)
888.  register int fd, mode;
889.  {
890.  	register struct damage *damageptr, *tmp_dam;
891.  	unsigned int xl = 0;
892.  
893.  	damageptr = level.damagelist;
894.  	for (tmp_dam = damageptr; tmp_dam; tmp_dam = tmp_dam->next)
895.  	    xl++;
896.  	if (perform_bwrite(mode))
897.  	    bwrite(fd, (genericptr_t) &xl, sizeof(xl));
898.  
899.  	while (xl--) {
900.  	    if (perform_bwrite(mode))
901.  		bwrite(fd, (genericptr_t) damageptr, sizeof(*damageptr));
902.  	    tmp_dam = damageptr;
903.  	    damageptr = damageptr->next;
904.  	    if (release_data(mode))
905.  		free((genericptr_t)tmp_dam);
906.  	}
907.  	if (release_data(mode))
908.  	    level.damagelist = 0;
909.  }
910.  
911.  STATIC_OVL void
912.  saveobjchn(fd, otmp, mode)
913.  register int fd, mode;
914.  register struct obj *otmp;
915.  {
916.  	register struct obj *otmp2;
917.  	unsigned int xl;
918.  	int minusone = -1;
919.  
920.  	while(otmp) {
921.  	    otmp2 = otmp->nobj;
922.  	    if (perform_bwrite(mode)) {
923.  		xl = otmp->oxlth + otmp->onamelth;
924.  		bwrite(fd, (genericptr_t) &xl, sizeof(int));
925.  		bwrite(fd, (genericptr_t) otmp, xl + sizeof(struct obj));
926.  	    }
927.  	    if (Has_contents(otmp))
928.  		saveobjchn(fd,otmp->cobj,mode);
929.  	    if (release_data(mode)) {
930.  		if (otmp->oclass == FOOD_CLASS) food_disappears(otmp);
931.  		if (otmp->oclass == SPBOOK_CLASS) book_disappears(otmp);
932.  		otmp->where = OBJ_FREE;	/* set to free so dealloc will work */
933.  		otmp->timed = 0;	/* not timed any more */
934.  		otmp->lamplit = 0;	/* caller handled lights */
935.  		dealloc_obj(otmp);
936.  	    }
937.  	    otmp = otmp2;
938.  	}
939.  	if (perform_bwrite(mode))
940.  	    bwrite(fd, (genericptr_t) &minusone, sizeof(int));
941.  }
942.  
943.  STATIC_OVL void
944.  savemonchn(fd, mtmp, mode)
945.  register int fd, mode;
946.  register struct monst *mtmp;
947.  {
948.  	register struct monst *mtmp2;
949.  	unsigned int xl;
950.  	int minusone = -1;
951.  	struct permonst *monbegin = &mons[0];
952.  
953.  	if (perform_bwrite(mode))
954.  	    bwrite(fd, (genericptr_t) &monbegin, sizeof(monbegin));
955.  
956.  	while (mtmp) {
957.  	    mtmp2 = mtmp->nmon;
958.  
959.  	    if (perform_bwrite(mode)) {
960.  		xl = mtmp->mxlth + mtmp->mnamelth;
961.  		bwrite(fd, (genericptr_t) &xl, sizeof(int));
962.  		bwrite(fd, (genericptr_t) mtmp, xl + sizeof(struct monst));
963.  	    }
964.  	    if (mtmp->minvent)
965.  		saveobjchn(fd,mtmp->minvent,mode);
966.  	    if (release_data(mode))
967.  		dealloc_monst(mtmp);
968.  	    mtmp = mtmp2;
969.  	}
970.  	if (perform_bwrite(mode))
971.  	    bwrite(fd, (genericptr_t) &minusone, sizeof(int));
972.  }
973.  
974.  STATIC_OVL void
975.  savetrapchn(fd, trap, mode)
976.  register int fd, mode;
977.  register struct trap *trap;
978.  {
979.  	register struct trap *trap2;
980.  
981.  	while (trap) {
982.  	    trap2 = trap->ntrap;
983.  	    if (perform_bwrite(mode))
984.  		bwrite(fd, (genericptr_t) trap, sizeof(struct trap));
985.  	    if (release_data(mode))
986.  		dealloc_trap(trap);
987.  	    trap = trap2;
988.  	}
989.  	if (perform_bwrite(mode))
990.  	    bwrite(fd, (genericptr_t)nulls, sizeof(struct trap));
991.  }
992.  
993.  /* save all the fruit names and ID's; this is used only in saving whole games
994.   * (not levels) and in saving bones levels.  When saving a bones level,
995.   * we only want to save the fruits which exist on the bones level; the bones
996.   * level routine marks nonexistent fruits by making the fid negative.
997.   */
998.  void
999.  savefruitchn(fd, mode)
1000. register int fd, mode;
1001. {
1002. 	register struct fruit *f2, *f1;
1003. 
1004. 	f1 = ffruit;
1005. 	while (f1) {
1006. 	    f2 = f1->nextf;
1007. 	    if (f1->fid >= 0 && perform_bwrite(mode))
1008. 		bwrite(fd, (genericptr_t) f1, sizeof(struct fruit));
1009. 	    if (release_data(mode))
1010. 		dealloc_fruit(f1);
1011. 	    f1 = f2;
1012. 	}
1013. 	if (perform_bwrite(mode))
1014. 	    bwrite(fd, (genericptr_t)nulls, sizeof(struct fruit));
1015. 	if (release_data(mode))
1016. 	    ffruit = 0;
1017. }
1018. 
1019. /* also called by prscore(); this probably belongs in dungeon.c... */
1020. /*
1021.  * [ALI] Also called by init_dungeons() for the sake of the GTK interface
1022.  * and the display_score callback of the proxy interface. For this purpose,
1023.  * the previous dungeon must be discarded.
1024.  */
1025. void
1026. free_dungeons()
1027. {
1028. #if defined(FREE_ALL_MEMORY) || defined(GTK_GRAPHICS) || defined(PROXY_GRAPHICS)
1029. 	savelevchn(0, FREE_SAVE);
1030. 	save_dungeon(0, FALSE, TRUE);
1031. #endif
1032. 	return;
1033. }
1034. 
1035. #ifdef MENU_COLOR
1036. void
1037. free_menu_coloring()
1038. {
1039.    struct menucoloring *tmp = menu_colorings;
1040.    
1041.    while (tmp) {
1042.       struct menucoloring *tmp2 = tmp->next;
1043. #ifdef USE_REGEX_MATCH
1044.       (void) regfree(&tmp->match);
1045. #else
1046.       free(tmp->match);
1047. #endif
1048.       free(tmp);
1049.       tmp = tmp2;
1050.    }
1051.    return;
1052. }
1053. #endif
1054. 
1055. void
1056. freedynamicdata()
1057. {
1058. 	unload_qtlist();
1059. 	free_invbuf();	/* let_to_name (invent.c) */
1060. 	free_youbuf();	/* You_buf,&c (pline.c) */
1061. #ifdef MENU_COLOR
1062.         free_menu_coloring();
1063. #endif
1064. 	tmp_at(DISP_FREEMEM, 0);	/* temporary display effects */
1065. #ifdef FREE_ALL_MEMORY
1066. # define freeobjchn(X)	(saveobjchn(0, X, FREE_SAVE),  X = 0)
1067. # define freemonchn(X)	(savemonchn(0, X, FREE_SAVE),  X = 0)
1068. # define freetrapchn(X)	(savetrapchn(0, X, FREE_SAVE), X = 0)
1069. # define freefruitchn()	 savefruitchn(0, FREE_SAVE)
1070. # define freenames()	 savenames(0, FREE_SAVE)
1071. # define free_oracles()	save_oracles(0, FREE_SAVE)
1072. # define free_waterlevel() save_waterlevel(0, FREE_SAVE)
1073. # define free_worm()	 save_worm(0, FREE_SAVE)
1074. # define free_timers(R)	 save_timers(0, FREE_SAVE, R)
1075. # define free_light_sources(R) save_light_sources(0, FREE_SAVE, R);
1076. # define free_engravings() save_engravings(0, FREE_SAVE)
1077. # define freedamage()	 savedamage(0, FREE_SAVE)
1078. # define free_animals()	 mon_animal_list(FALSE)
1079. 
1080. 	/* move-specific data */
1081. 	dmonsfree();		/* release dead monsters */
1082. 
1083. 	/* level-specific data */
1084. 	free_timers(RANGE_LEVEL);
1085. 	free_light_sources(RANGE_LEVEL);
1086. 	freemonchn(fmon);
1087. 	free_worm();		/* release worm segment information */
1088. 	freetrapchn(ftrap);
1089. 	freeobjchn(fobj);
1090. 	freeobjchn(level.buriedobjlist);
1091. 	freeobjchn(billobjs);
1092. 	free_engravings();
1093. 	freedamage();
1094. 
1095. 	/* game-state data */
1096. 	free_timers(RANGE_GLOBAL);
1097. 	free_light_sources(RANGE_GLOBAL);
1098. 	freeobjchn(invent);
1099. 	freeobjchn(migrating_objs);
1100. 	freemonchn(migrating_mons);
1101. 	freemonchn(mydogs);		/* ascension or dungeon escape */
1102.      /* freelevchn();	[folded into free_dungeons()] */
1103. 	free_animals();
1104. 	free_oracles();
1105. 	freefruitchn();
1106. 	freenames();
1107. 	free_waterlevel();
1108. 	free_dungeons();
1109. 
1110. 	/* some pointers in iflags */
1111. 	if (iflags.wc_font_map) free(iflags.wc_font_map);
1112. 	if (iflags.wc_font_message) free(iflags.wc_font_message);
1113. 	if (iflags.wc_font_text) free(iflags.wc_font_text);
1114. 	if (iflags.wc_font_menu) free(iflags.wc_font_menu);
1115. 	if (iflags.wc_font_status) free(iflags.wc_font_status);
1116. 	if (iflags.wc_tile_file) free(iflags.wc_tile_file);
1117. #ifdef AUTOPICKUP_EXCEPTIONS
1118. 	free_autopickup_exceptions();
1119. #endif
1120. 
1121. #endif	/* FREE_ALL_MEMORY */
1122. 	return;
1123. }
1124. 
1125. #ifdef MFLOPPY
1126. boolean
1127. swapin_file(lev)
1128. int lev;
1129. {
1130. 	char to[PATHLEN], from[PATHLEN];
1131. 
1132. 	Sprintf(from, "%s%s", permbones, alllevels);
1133. 	Sprintf(to, "%s%s", levels, alllevels);
1134. 	set_levelfile_name(from, lev);
1135. 	set_levelfile_name(to, lev);
1136. 	if (iflags.checkspace) {
1137. 		while (level_info[lev].size > freediskspace(to))
1138. 			if (!swapout_oldest())
1139. 				return FALSE;
1140. 	}
1141. # ifdef WIZARD
1142. 	if (wizard) {
1143. 		pline("Swapping in `%s'.", from);
1144. 		wait_synch();
1145. 	}
1146. # endif
1147. 	copyfile(from, to);
1148. 	(void) unlink(from);
1149. 	level_info[lev].where = ACTIVE;
1150. 	return TRUE;
1151. }
1152. 
1153. STATIC_OVL boolean
1154. swapout_oldest() {
1155. 	char to[PATHLEN], from[PATHLEN];
1156. 	int i, oldest;
1157. 	long oldtime;
1158. 
1159. 	if (!ramdisk)
1160. 		return FALSE;
1161. 	for (i = 1, oldtime = 0, oldest = 0; i <= maxledgerno(); i++)
1162. 		if (level_info[i].where == ACTIVE
1163. 		&& (!oldtime || level_info[i].time < oldtime)) {
1164. 			oldest = i;
1165. 			oldtime = level_info[i].time;
1166. 		}
1167. 	if (!oldest)
1168. 		return FALSE;
1169. 	Sprintf(from, "%s%s", levels, alllevels);
1170. 	Sprintf(to, "%s%s", permbones, alllevels);
1171. 	set_levelfile_name(from, oldest);
1172. 	set_levelfile_name(to, oldest);
1173. # ifdef WIZARD
1174. 	if (wizard) {
1175. 		pline("Swapping out `%s'.", from);
1176. 		wait_synch();
1177. 	}
1178. # endif
1179. 	copyfile(from, to);
1180. 	(void) unlink(from);
1181. 	level_info[oldest].where = SWAPPED;
1182. 	return TRUE;
1183. }
1184. 
1185. STATIC_OVL void
1186. copyfile(from, to)
1187. char *from, *to;
1188. {
1189. # ifdef TOS
1190. 
1191. 	if (_copyfile(from, to))
1192. 		panic("Can't copy %s to %s", from, to);
1193. # else
1194. 	char buf[BUFSIZ];	/* this is system interaction, therefore
1195. 				 * BUFSIZ instead of NetHack's BUFSZ */
1196. 	int nfrom, nto, fdfrom, fdto;
1197. 
1198. 	if ((fdfrom = open(from, O_RDONLY | O_BINARY, FCMASK)) < 0)
1199. 		panic("Can't copy from %s !?", from);
1200. 	if ((fdto = open(to, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK)) < 0)
1201. 		panic("Can't copy to %s", to);
1202. 	do {
1203. 		nfrom = read(fdfrom, buf, BUFSIZ);
1204. 		nto = write(fdto, buf, nfrom);
1205. 		if (nto != nfrom)
1206. 			panic("Copyfile failed!");
1207. 	} while (nfrom == BUFSIZ);
1208. 	(void) close(fdfrom);
1209. 	(void) close(fdto);
1210. # endif /* TOS */
1211. }
1212. 
1213. void
1214. co_false()	    /* see comment in bones.c */
1215. {
1216.     count_only = FALSE;
1217.     return;
1218. }
1219. 
1220. #endif /* MFLOPPY */
1221. 
1222. /*save.c*/