Source:NetHack 3.2.0/save.c

From NetHackWiki
(Redirected from NetHack 3.2.0/save.c)
Jump to navigation Jump to search

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

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