Source:NetHack 3.3.0/save.c

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

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   10. #endif 11.  #if !defined(LSC) && !defined(O_WRONLY) && !defined(AZTEC_C) 12.  #include   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*/