Source:NetHack 3.4.3/src/save.c

From NetHackWiki
(Redirected from Source:Ref/freedynamicdata)
Jump to: navigation, search

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

  1. /*	SCCS Id: @(#)save.c	3.4	2003/11/14	*/
  2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3. /* NetHack may be freely redistributed.  See license for details. */

The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

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