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