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. */
12 #if !defined(LSC) && !defined(O_WRONLY) && !defined(AZTEC_C)
18 static int count_only;
22 int dotcnt, dotrow; /* also used in restore */
26 STATIC_DCL void FDECL(bputc, (int));
28 STATIC_DCL void FDECL(savelevchn, (int,int));
29 STATIC_DCL void FDECL(savedamage, (int,int));
30 STATIC_DCL void FDECL(saveobjchn, (int,struct obj *,int));
31 STATIC_DCL void FDECL(savemonchn, (int,struct monst *,int));
32 STATIC_DCL void FDECL(savetrapchn, (int,struct trap *,int));
33 STATIC_DCL void FDECL(savegamestate, (int,int));
35 STATIC_DCL void FDECL(savelev0, (int,XCHAR_P,int));
36 STATIC_DCL boolean NDECL(swapout_oldest);
37 STATIC_DCL void FDECL(copyfile, (char *,char *));
40 static long nulls[10];
45 #if defined(UNIX) || defined(VMS) || defined(__EMX__) || defined(WIN32)
46 #define HUP if (!program_state.done_hup)
51 /* need to preserve these during save to avoid accessing freed memory */
52 static unsigned ustuck_id = 0, usteed_id = 0;
57 clear_nhwindow(WIN_MESSAGE);
58 if(yn("Really save?") == 'n') {
59 clear_nhwindow(WIN_MESSAGE);
60 if(multi > 0) nomul(0);
62 clear_nhwindow(WIN_MESSAGE);
64 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
65 program_state.done_hup = 0;
68 program_state.something_worth_saving = 0;
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();
80 #if defined(UNIX) || defined(VMS) || defined (__EMX__) || defined(WIN32)
83 hangup(sig_unused) /* called as signal() handler, so sent at least one arg */
86 # ifdef NOSAVEONHANGUP
87 (void) signal(SIGINT, SIG_IGN);
90 terminate(EXIT_FAILURE);
92 # else /* SAVEONHANGUP */
93 if (!program_state.done_hup++) {
94 if (program_state.something_worth_saving)
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)
103 terminate(EXIT_FAILURE);
111 /* returns 1 if save successful */
116 register int fd, ofd;
123 fq_save = fqname(SAVEF, SAVEPREFIX, 1); /* level files take 0 */
125 #if defined(UNIX) || defined(VMS)
126 (void) signal(SIGHUP, SIG_IGN);
129 (void) signal(SIGINT, SIG_IGN);
132 #if defined(MICRO) && defined(MFLOPPY)
133 if (!saveDiskPrompt(0)) return 0;
136 HUP if (iflags.window_inited) {
138 fd = open_savefile();
141 clear_nhwindow(WIN_MESSAGE);
142 There("seems to be an old save file.");
143 if (yn("Overwrite the old file?") == 'n') {
150 HUP mark_synch(); /* flush any buffered screen output */
152 fd = create_savefile();
154 HUP pline("Cannot open save file.");
155 (void) delete_savefile(); /* ab@unido */
159 vision_recalc(2); /* shut down vision to prevent problems
160 in the event of an impossible() call */
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 */
167 if(iflags.window_inited)
168 HUP clear_nhwindow(WIN_MESSAGE);
174 if (strncmpi("X11", windowprocs.name, 3))
175 putstr(WIN_MAP, 0, "Saving:");
178 /* make sure there is enough disk space */
179 if (iflags.checkspace) {
182 savelev(fd, ledger_no(&u.uz), COUNT_SAVE);
183 savegamestate(fd, COUNT_SAVE);
184 needed = bytes_counted;
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);
192 There("is insufficient space on SAVE disk.");
193 pline("Require %ld bytes but only have %ld.", needed, fds);
197 (void) delete_savefile();
206 #ifdef STORE_PLNAME_IN_FILE
207 bwrite(fd, (genericptr_t) plname, PL_NSIZ);
209 ustuck_id = (u.ustuck ? u.ustuck->m_id : 0);
211 usteed_id = (u.usteed ? u.usteed->m_id : 0);
213 savelev(fd, ledger_no(&u.uz), WRITE_SAVE | FREE_SAVE);
214 savegamestate(fd, WRITE_SAVE | FREE_SAVE);
216 /* While copying level files around, zero out u.uz to keep
217 * parts of the restore code from completely initializing all
218 * in-core data structures, since all we're doing is copying.
219 * This also avoids at least one nasty core dump.
222 u.uz.dnum = u.uz.dlevel = 0;
223 /* these pointers are no longer valid, and at least u.usteed
224 * may mislead place_monster() on other levels
226 u.ustuck = (struct monst *)0;
228 u.usteed = (struct monst *)0;
231 for(ltmp = (xchar)1; ltmp <= maxledgerno(); ltmp++) {
232 if (ltmp == ledger_no(&uz_save)) continue;
233 if (!(level_info[ltmp].flags & LFILE_EXISTS)) continue;
235 curs(WIN_MAP, 1 + dotcnt++, dotrow);
236 if (dotcnt >= (COLNO - 1)) {
240 if (strncmpi("X11", windowprocs.name, 3)){
241 putstr(WIN_MAP, 0, ".");
245 ofd = open_levelfile(ltmp, whynot);
247 HUP pline("%s", whynot);
249 (void) delete_savefile();
254 minit(); /* ZEROCOMP */
255 getlev(ofd, hackpid, ltmp, FALSE);
257 bwrite(fd, (genericptr_t) <mp, sizeof ltmp); /* level number*/
258 savelev(fd, ltmp, WRITE_SAVE | FREE_SAVE); /* actual level*/
259 delete_levelfile(ltmp);
265 /* get rid of current level --jgm */
266 delete_levelfile(ledger_no(&u.uz));
273 savegamestate(fd, mode)
274 register int fd, mode;
279 count_only = (mode & COUNT_SAVE);
282 bwrite(fd, (genericptr_t) &uid, sizeof uid);
283 bwrite(fd, (genericptr_t) &flags, sizeof(struct flag));
284 bwrite(fd, (genericptr_t) &u, sizeof(struct you));
286 /* must come before migrating_objs and migrating_mons are freed */
287 save_timers(fd, mode, RANGE_GLOBAL);
288 save_light_sources(fd, mode, RANGE_GLOBAL);
290 saveobjchn(fd, invent, mode);
291 saveobjchn(fd, migrating_objs, mode);
292 savemonchn(fd, migrating_mons, mode);
293 if (release_data(mode)) {
298 bwrite(fd, (genericptr_t) mvitals, sizeof(mvitals));
300 save_dungeon(fd, (boolean)!!perform_bwrite(mode),
301 (boolean)!!release_data(mode));
302 savelevchn(fd, mode);
303 bwrite(fd, (genericptr_t) &moves, sizeof moves);
304 bwrite(fd, (genericptr_t) &monstermoves, sizeof monstermoves);
305 bwrite(fd, (genericptr_t) &quest_status, sizeof(struct q_score));
306 bwrite(fd, (genericptr_t) spl_book,
307 sizeof(struct spell) * (MAXSPELL + 1));
309 save_oracles(fd, mode);
311 bwrite(fd, (genericptr_t) &ustuck_id, sizeof ustuck_id);
314 bwrite(fd, (genericptr_t) &usteed_id, sizeof usteed_id);
316 bwrite(fd, (genericptr_t) pl_character, sizeof pl_character);
317 bwrite(fd, (genericptr_t) pl_fruit, sizeof pl_fruit);
318 bwrite(fd, (genericptr_t) ¤t_fruit, sizeof current_fruit);
319 savefruitchn(fd, mode);
321 save_waterlevel(fd, mode);
330 static boolean havestate = TRUE;
333 /* When checkpointing is on, the full state needs to be written
334 * on each checkpoint. When checkpointing is off, only the pid
335 * needs to be in the level.0 file, so it does not need to be
336 * constantly rewritten. When checkpointing is turned off during
337 * a game, however, the file has to be rewritten once to truncate
338 * it and avoid restoring from outdated information.
340 * Restricting havestate to this routine means that an additional
341 * noop pid rewriting will take place on the first "checkpoint" after
342 * the game is started or restored, if checkpointing is off.
344 if (flags.ins_chkpt || havestate) {
345 /* save the rest of the current game state in the lock file,
346 * following the original int pid, the current level number,
347 * and the current savefile name, which should not be subject
348 * to any internal compression schemes since they must be
349 * readable by an external utility
351 fd = open_levelfile(0, whynot);
354 pline("Probably someone removed it.");
360 (void) read(fd, (genericptr_t) &hpid, sizeof(hpid));
361 if (hackpid != hpid) {
363 "Level #0 pid (%d) doesn't match ours (%d)!",
371 fd = create_levelfile(0, whynot);
378 (void) write(fd, (genericptr_t) &hackpid, sizeof(hackpid));
379 if (flags.ins_chkpt) {
380 int currlev = ledger_no(&u.uz);
382 (void) write(fd, (genericptr_t) &currlev, sizeof(currlev));
383 save_savefile_name(fd);
385 #ifdef STORE_PLNAME_IN_FILE
386 bwrite(fd, (genericptr_t) plname, PL_NSIZ);
388 ustuck_id = (u.ustuck ? u.ustuck->m_id : 0);
390 usteed_id = (u.usteed ? u.usteed->m_id : 0);
392 savegamestate(fd, WRITE_SAVE);
396 havestate = flags.ins_chkpt;
402 savelev(fd, lev, mode)
407 if (mode & COUNT_SAVE) {
409 savelev0(fd, lev, COUNT_SAVE);
410 /* probably bytes_counted will be filled in again by an
411 * immediately following WRITE_SAVE anyway, but we'll
412 * leave it out of checkspace just in case */
413 if (iflags.checkspace) {
414 while (bytes_counted > freediskspace(levels))
415 if (!swapout_oldest())
419 if (mode & (WRITE_SAVE | FREE_SAVE)) {
421 savelev0(fd, lev, mode);
423 if (mode != FREE_SAVE) {
424 level_info[lev].where = ACTIVE;
425 level_info[lev].time = moves;
426 level_info[lev].size = bytes_counted;
432 savelev0(fd,lev,mode)
445 /* if we're tearing down the current level without saving anything
446 (which happens upon entrance to the endgame or after an aborted
447 restore attempt) then we don't want to do any actual I/O */
448 if (mode == FREE_SAVE) goto skip_lots;
449 if (iflags.purge_monsters) {
450 /* purge any dead monsters (necessary if we're starting
451 * a panic save rather than a normal one, or sometimes
452 * when changing levels without taking time -- e.g.
453 * create statue trap then immediately level teleport) */
457 if(fd < 0) panic("Save on bad file!"); /* impossible */
459 count_only = (mode & COUNT_SAVE);
461 if (lev >= 0 && lev <= maxledgerno())
462 level_info[lev].flags |= VISITED;
463 bwrite(fd,(genericptr_t) &hackpid,sizeof(hackpid));
465 tlev=lev; tlev &= 0x00ff;
466 bwrite(fd,(genericptr_t) &tlev,sizeof(tlev));
468 bwrite(fd,(genericptr_t) &lev,sizeof(lev));
472 /* perform run-length encoding of rm structs */
473 struct rm *prm, *rgrm;
477 rgrm = &levl[0][0]; /* start matching at first rm */
480 for (y = 0; y < ROWNO; y++) {
481 for (x = 0; x < COLNO; x++) {
483 if (prm->glyph == rgrm->glyph
484 && prm->typ == rgrm->typ
485 && prm->seenv == rgrm->seenv
486 && prm->horizontal == rgrm->horizontal
487 && prm->flags == rgrm->flags
488 && prm->lit == rgrm->lit
489 && prm->waslit == rgrm->waslit
490 && prm->roomno == rgrm->roomno
491 && prm->edge == rgrm->edge) {
494 match = 254; /* undo this match */
498 /* the run has been broken,
499 * write out run-length encoding */
501 bwrite(fd, (genericptr_t)&match, sizeof(uchar));
502 bwrite(fd, (genericptr_t)rgrm, sizeof(struct rm));
503 /* start encoding again. we have at least 1 rm
504 * in the next run, viz. this one. */
511 bwrite(fd, (genericptr_t)&match, sizeof(uchar));
512 bwrite(fd, (genericptr_t)rgrm, sizeof(struct rm));
516 bwrite(fd,(genericptr_t) levl,sizeof(levl));
519 bwrite(fd,(genericptr_t) &monstermoves,sizeof(monstermoves));
520 bwrite(fd,(genericptr_t) &upstair,sizeof(stairway));
521 bwrite(fd,(genericptr_t) &dnstair,sizeof(stairway));
522 bwrite(fd,(genericptr_t) &upladder,sizeof(stairway));
523 bwrite(fd,(genericptr_t) &dnladder,sizeof(stairway));
524 bwrite(fd,(genericptr_t) &sstairs,sizeof(stairway));
525 bwrite(fd,(genericptr_t) &updest,sizeof(dest_area));
526 bwrite(fd,(genericptr_t) &dndest,sizeof(dest_area));
527 bwrite(fd,(genericptr_t) &level.flags,sizeof(level.flags));
528 bwrite(fd, (genericptr_t) doors, sizeof(doors));
529 save_rooms(fd); /* no dynamic memory to reclaim */
531 /* from here on out, saving also involves allocated memory cleanup */
533 /* must be saved before mons, objs, and buried objs */
534 save_timers(fd, mode, RANGE_LEVEL);
535 save_light_sources(fd, mode, RANGE_LEVEL);
537 savemonchn(fd, fmon, mode);
538 save_worm(fd, mode); /* save worm information */
539 savetrapchn(fd, ftrap, mode);
540 saveobjchn(fd, fobj, mode);
541 saveobjchn(fd, level.buriedobjlist, mode);
542 saveobjchn(fd, billobjs, mode);
543 if (release_data(mode)) {
547 level.buriedobjlist = 0;
550 save_engravings(fd, mode);
551 savedamage(fd, mode);
552 save_regions(fd, mode);
553 if (mode != FREE_SAVE) bflush(fd);
557 /* The runs of zero-run compression are flushed after the game state or a
558 * level is written out. This adds a couple bytes to a save file, where
559 * the runs could be mashed together, but it allows gluing together game
560 * state and level files to form a save file, and it means the flushing
561 * does not need to be specifically called for every other time a level
562 * file is written out.
565 #define RLESC '\0' /* Leading character for run of LRESC's */
566 #define flushoutrun(ln) (bputc(RLESC), bputc(ln), ln = -1)
568 #ifndef ZEROCOMP_BUFSIZ
569 # define ZEROCOMP_BUFSIZ BUFSZ
571 static NEARDATA unsigned char outbuf[ZEROCOMP_BUFSIZ];
572 static NEARDATA unsigned short outbufp = 0;
573 static NEARDATA short outrunlength = -1;
574 static NEARDATA int bwritefd;
575 static NEARDATA boolean compressing = FALSE;
579 HUP printf("outbufp %d outrunlength %d\n", outbufp,outrunlength);
591 if (outbufp >= sizeof outbuf) {
592 (void) write(bwritefd, outbuf, sizeof outbuf);
595 outbuf[outbufp++] = (unsigned char)c;
614 panic("closing file with buffered data still unwritten");
622 bflush(fd) /* flush run and buffer */
626 if (outrunlength >= 0) { /* flush run */
627 flushoutrun(outrunlength);
630 if (count_only) outbufp = 0;
634 if (write(fd, outbuf, outbufp) != outbufp) {
635 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
636 if (program_state.done_hup)
637 terminate(EXIT_FAILURE);
640 bclose(fd); /* panic (outbufp != 0) */
650 register unsigned num;
652 register unsigned char *bp = (unsigned char *)loc;
656 bytes_counted += num;
657 if (count_only) return;
659 if ((unsigned) write(fd, loc, num) != num) {
660 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
661 if (program_state.done_hup)
662 terminate(EXIT_FAILURE);
665 panic("cannot write %u bytes to file #%d", num, fd);
669 for (; num; num--, bp++) {
670 if (*bp == RLESC) { /* One more char in run */
671 if (++outrunlength == 0xFF) {
672 flushoutrun(outrunlength);
674 } else { /* end of run */
675 if (outrunlength >= 0) { /* flush run */
676 flushoutrun(outrunlength);
695 static int bw_fd = -1;
696 static FILE *bw_FILE = 0;
697 static boolean buffering = FALSE;
705 panic("double buffering unexpected");
707 if((bw_FILE = fdopen(fd, "w")) == 0)
708 panic("buffering of file %d failed", fd);
727 if(fflush(bw_FILE) == EOF)
728 panic("flush of savefile failed!");
737 register genericptr_t loc;
738 register unsigned num;
743 bytes_counted += num;
744 if (count_only) return;
750 panic("unbuffered write to fd %d (!= %d)", fd, bw_fd);
752 failed = (fwrite(loc, (int)num, 1, bw_FILE) != 1);
756 /* lint wants the 3rd arg of write to be an int; lint -p an unsigned */
757 #if defined(BSD) || defined(ULTRIX)
758 failed = (write(fd, loc, (int)num) != (int)num);
759 #else /* e.g. SYSV, __TURBOC__ */
760 failed = (write(fd, loc, num) != num);
765 #if defined(UNIX) || defined(VMS) || defined(__EMX__)
766 if (program_state.done_hup)
767 terminate(EXIT_FAILURE);
770 panic("cannot write %u bytes to file #%d", num, fd);
781 (void) fclose(bw_FILE);
789 #endif /* ZEROCOMP */
793 register int fd, mode;
795 s_level *tmplev, *tmplev2;
798 for (tmplev = sp_levchn; tmplev; tmplev = tmplev->next) cnt++;
799 if (perform_bwrite(mode))
800 bwrite(fd, (genericptr_t) &cnt, sizeof(int));
802 for (tmplev = sp_levchn; tmplev; tmplev = tmplev2) {
803 tmplev2 = tmplev->next;
804 if (perform_bwrite(mode))
805 bwrite(fd, (genericptr_t) tmplev, sizeof(s_level));
806 if (release_data(mode))
807 free((genericptr_t) tmplev);
809 if (release_data(mode))
815 register int fd, mode;
817 register struct damage *damageptr, *tmp_dam;
820 damageptr = level.damagelist;
821 for (tmp_dam = damageptr; tmp_dam; tmp_dam = tmp_dam->next)
823 if (perform_bwrite(mode))
824 bwrite(fd, (genericptr_t) &xl, sizeof(xl));
827 if (perform_bwrite(mode))
828 bwrite(fd, (genericptr_t) damageptr, sizeof(*damageptr));
830 damageptr = damageptr->next;
831 if (release_data(mode))
832 free((genericptr_t)tmp_dam);
834 if (release_data(mode))
835 level.damagelist = 0;
839 saveobjchn(fd, otmp, mode)
840 register int fd, mode;
841 register struct obj *otmp;
843 register struct obj *otmp2;
849 if (perform_bwrite(mode)) {
850 xl = otmp->oxlth + otmp->onamelth;
851 bwrite(fd, (genericptr_t) &xl, sizeof(int));
852 bwrite(fd, (genericptr_t) otmp, xl + sizeof(struct obj));
854 if (Has_contents(otmp))
855 saveobjchn(fd,otmp->cobj,mode);
856 if (release_data(mode)) {
857 if (otmp->oclass == FOOD_CLASS) food_disappears(otmp);
858 if (otmp->oclass == SPBOOK_CLASS) book_disappears(otmp);
859 otmp->where = OBJ_FREE; /* set to free so dealloc will work */
860 otmp->timed = 0; /* not timed any more */
861 otmp->lamplit = 0; /* caller handled lights */
866 if (perform_bwrite(mode))
867 bwrite(fd, (genericptr_t) &minusone, sizeof(int));
871 savemonchn(fd, mtmp, mode)
872 register int fd, mode;
873 register struct monst *mtmp;
875 register struct monst *mtmp2;
878 struct permonst *monbegin = &mons[0];
880 if (perform_bwrite(mode))
881 bwrite(fd, (genericptr_t) &monbegin, sizeof(monbegin));
885 if (perform_bwrite(mode)) {
886 xl = mtmp->mxlth + mtmp->mnamelth;
887 bwrite(fd, (genericptr_t) &xl, sizeof(int));
888 bwrite(fd, (genericptr_t) mtmp, xl + sizeof(struct monst));
891 saveobjchn(fd,mtmp->minvent,mode);
892 if (release_data(mode))
896 if (perform_bwrite(mode))
897 bwrite(fd, (genericptr_t) &minusone, sizeof(int));
901 savetrapchn(fd, trap, mode)
902 register int fd, mode;
903 register struct trap *trap;
905 register struct trap *trap2;
909 if (perform_bwrite(mode))
910 bwrite(fd, (genericptr_t) trap, sizeof(struct trap));
911 if (release_data(mode))
915 if (perform_bwrite(mode))
916 bwrite(fd, (genericptr_t)nulls, sizeof(struct trap));
919 /* save all the fruit names and ID's; this is used only in saving whole games
920 * (not levels) and in saving bones levels. When saving a bones level,
921 * we only want to save the fruits which exist on the bones level; the bones
922 * level routine marks nonexistent fruits by making the fid negative.
925 savefruitchn(fd, mode)
926 register int fd, mode;
928 register struct fruit *f2, *f1;
933 if (f1->fid >= 0 && perform_bwrite(mode))
934 bwrite(fd, (genericptr_t) f1, sizeof(struct fruit));
935 if (release_data(mode))
939 if (perform_bwrite(mode))
940 bwrite(fd, (genericptr_t)nulls, sizeof(struct fruit));
941 if (release_data(mode))
945 /* also called by prscore(); this probably belongs in dungeon.c... */
949 #ifdef FREE_ALL_MEMORY
950 savelevchn(0, FREE_SAVE);
951 save_dungeon(0, FALSE, TRUE);
960 free_invbuf(); /* let_to_name (invent.c) */
961 free_youbuf(); /* You_buf,&c (pline.c) */
962 tmp_at(DISP_FREEMEM, 0); /* temporary display effects */
963 #ifdef FREE_ALL_MEMORY
964 # define freeobjchn(X) (saveobjchn(0, X, FREE_SAVE), X = 0)
965 # define freemonchn(X) (savemonchn(0, X, FREE_SAVE), X = 0)
966 # define freetrapchn(X) (savetrapchn(0, X, FREE_SAVE), X = 0)
967 # define freefruitchn() savefruitchn(0, FREE_SAVE)
968 # define freenames() savenames(0, FREE_SAVE)
969 # define free_oracles() save_oracles(0, FREE_SAVE)
970 # define free_waterlevel() save_waterlevel(0, FREE_SAVE)
971 # define free_worm() save_worm(0, FREE_SAVE)
972 # define free_timers(R) save_timers(0, FREE_SAVE, R)
973 # define free_light_sources(R) save_light_sources(0, FREE_SAVE, R);
974 # define free_engravings() save_engravings(0, FREE_SAVE)
975 # define freedamage() savedamage(0, FREE_SAVE)
976 # define free_animals() mon_animal_list(FALSE)
978 /* move-specific data */
979 dmonsfree(); /* release dead monsters */
981 /* level-specific data */
982 free_timers(RANGE_LEVEL);
983 free_light_sources(RANGE_LEVEL);
985 free_worm(); /* release worm segment information */
988 freeobjchn(level.buriedobjlist);
989 freeobjchn(billobjs);
993 /* game-state data */
994 free_timers(RANGE_GLOBAL);
995 free_light_sources(RANGE_GLOBAL);
997 freeobjchn(migrating_objs);
998 freemonchn(migrating_mons);
999 freemonchn(mydogs); /* ascension or dungeon escape */
1000 /* freelevchn(); [folded into free_dungeons()] */
1008 /* some pointers in iflags */
1009 if (iflags.wc_font_map) free(iflags.wc_font_map);
1010 if (iflags.wc_font_message) free(iflags.wc_font_message);
1011 if (iflags.wc_font_text) free(iflags.wc_font_text);
1012 if (iflags.wc_font_menu) free(iflags.wc_font_menu);
1013 if (iflags.wc_font_status) free(iflags.wc_font_status);
1014 if (iflags.wc_tile_file) free(iflags.wc_tile_file);
1015 #ifdef AUTOPICKUP_EXCEPTIONS
1016 free_autopickup_exceptions();
1019 #endif /* FREE_ALL_MEMORY */
1028 char to[PATHLEN], from[PATHLEN];
1030 Sprintf(from, "%s%s", permbones, alllevels);
1031 Sprintf(to, "%s%s", levels, alllevels);
1032 set_levelfile_name(from, lev);
1033 set_levelfile_name(to, lev);
1034 if (iflags.checkspace) {
1035 while (level_info[lev].size > freediskspace(to))
1036 if (!swapout_oldest())
1041 pline("Swapping in `%s'.", from);
1046 (void) unlink(from);
1047 level_info[lev].where = ACTIVE;
1053 char to[PATHLEN], from[PATHLEN];
1059 for (i = 1, oldtime = 0, oldest = 0; i <= maxledgerno(); i++)
1060 if (level_info[i].where == ACTIVE
1061 && (!oldtime || level_info[i].time < oldtime)) {
1063 oldtime = level_info[i].time;
1067 Sprintf(from, "%s%s", levels, alllevels);
1068 Sprintf(to, "%s%s", permbones, alllevels);
1069 set_levelfile_name(from, oldest);
1070 set_levelfile_name(to, oldest);
1073 pline("Swapping out `%s'.", from);
1078 (void) unlink(from);
1079 level_info[oldest].where = SWAPPED;
1089 if (_copyfile(from, to))
1090 panic("Can't copy %s to %s", from, to);
1092 char buf[BUFSIZ]; /* this is system interaction, therefore
1093 * BUFSIZ instead of NetHack's BUFSZ */
1094 int nfrom, nto, fdfrom, fdto;
1096 if ((fdfrom = open(from, O_RDONLY | O_BINARY, FCMASK)) < 0)
1097 panic("Can't copy from %s !?", from);
1098 if ((fdto = open(to, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK)) < 0)
1099 panic("Can't copy to %s", to);
1101 nfrom = read(fdfrom, buf, BUFSIZ);
1102 nto = write(fdto, buf, nfrom);
1104 panic("Copyfile failed!");
1105 } while (nfrom == BUFSIZ);
1106 (void) close(fdfrom);
1112 co_false() /* see comment in bones.c */
1118 #endif /* MFLOPPY */