Source:NetHack 3.4.3/src/save.c

From NetHackWiki
Revision as of 12:26, 22 June 2006 by Jaytbot (talk | contribs) (Automated source code upload)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Below is the full text to src/save.c from NetHack 3.4.3. To link to a particular line, write [[save.c#line123]], for example.

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.    

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.

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