Fandom

Wikihack

Source:NetHack 3.3.0/save.c

2,034pages on
this wiki
Add New Page
Talk0

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.

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

Also on Fandom

Random Wiki