Source:NetHack 3.2.0/save.c

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

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   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 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*/