Mercurial > hg > early-roguelike
diff rogue4/save.c @ 12:9535a08ddc39
Import Rogue 5.2 from the Roguelike Restoration Project (r1490)
author | edwarj4 |
---|---|
date | Sat, 24 Oct 2009 16:52:52 +0000 |
parents | |
children | 63b9fd7d70ce |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rogue4/save.c Sat Oct 24 16:52:52 2009 +0000 @@ -0,0 +1,342 @@ +/* + * save and restore routines + * + * @(#)save.c 4.15 (Berkeley) 5/10/82 + * + * Rogue: Exploring the Dungeons of Doom + * Copyright (C) 1980, 1981, 1982 Michael Toy, Ken Arnold and Glenn Wichman + * All rights reserved. + * + * See the file LICENSE.TXT for full copyright and licensing information. + */ + +#include <curses.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#define KERNEL +#include <signal.h> +#undef KERNEL +#include "rogue.h" + +typedef struct stat STAT; + +extern char version[], encstr[]; +extern bool _endwin; + +STAT sbuf; + +/* + * save_game: + * Implement the "save game" command + */ +save_game() +{ + register FILE *savef; + register int c; + char buf[MAXSTR]; + + /* + * get file name + */ + mpos = 0; +over: + if (file_name[0] != '\0') + { + for (;;) + { + msg("save file (%s)? ", file_name); + c = getchar(); + mpos = 0; + if (c == ESCAPE) + { + msg(""); + return FALSE; + } + else if (c == 'n' || c == 'N' || c == 'y' || c == 'Y') + break; + else + msg("please answer Y or N"); + } + if (c == 'y' || c == 'Y') + { + strcpy(buf, file_name); + goto gotfile; + } + } + + do + { + mpos = 0; + msg("file name: "); + buf[0] = '\0'; + if (get_str(buf, stdscr) == QUIT) + { +quit: + msg(""); + return FALSE; + } + mpos = 0; +gotfile: + /* + * test to see if the file exists + */ + if (stat(buf, &sbuf) >= 0) + { + for (;;) + { + msg("File exists. Do you wish to overwrite it?"); + mpos = 0; + if ((c = readchar()) == ESCAPE) + goto quit; + if (c == 'y' || c == 'Y') + break; + else if (c == 'n' || c == 'N') + goto over; + else + msg("Please answer Y or N"); + } + msg("file name: %s", buf); + } + strcpy(file_name, buf); + if ((savef = fopen(file_name, "w")) == NULL) + msg(strerror(errno)); /* fake perror() */ + } while (savef == NULL); + + /* + * write out encrpyted file (after a stat) + * The fwrite is to force allocation of the buffer before the write + */ + save_file(savef); + return TRUE; +} + +/* + * auto_save: + * Automatically save a file. This is used if a HUP signal is + * recieved + */ +void +auto_save(int sig) +{ + register FILE *savef; + + md_ignore_signals(); + + if (file_name[0] != '\0' && (savef = fopen(file_name, "w")) != NULL) + save_file(savef); + endwin(); + exit(1); +} + +/* + * save_file: + * Write the saved game on the file + */ +save_file(savef) +register FILE *savef; +{ + int slines = LINES; + int scols = COLS; + + /* + * close any open score file + */ + close(fd); + move(LINES-1, 0); + refresh(); + fstat(md_fileno(savef), &sbuf); + /* + * DO NOT DELETE. This forces stdio to allocate the output buffer + * so that malloc doesn't get confused on restart + */ + fwrite("junk", 1, 5, savef); + + fseek(savef, 0L, 0); + + encwrite(version,strlen(version)+1,savef); + encwrite(&sbuf.st_ino,sizeof(sbuf.st_ino),savef); + encwrite(&sbuf.st_dev,sizeof(sbuf.st_dev),savef); + encwrite(&sbuf.st_ctime,sizeof(sbuf.st_ctime),savef); + encwrite(&sbuf.st_mtime,sizeof(sbuf.st_mtime),savef); + encwrite(&slines,sizeof(slines),savef); + encwrite(&scols,sizeof(scols),savef); + msg(""); + rs_save_file(savef); + + fclose(savef); +} + +/* + * restore: + * Restore a saved game from a file with elaborate checks for file + * integrity from cheaters + */ +restore(file, envp) +register char *file; +char **envp; +{ + register int inf; + register bool syml; + extern char **environ; + char buf[MAXSTR]; + STAT sbuf2; + int slines, scols; + + if (strcmp(file, "-r") == 0) + file = file_name; + +#ifdef SIGTSTP + /* + * If a process can be suspended, this code wouldn't work + */ + signal(SIGTSTP, SIG_IGN); +#endif + + if ((inf = open(file, 0)) < 0) + { + perror(file); + return FALSE; + } + + fflush(stdout); + encread(buf, strlen(version) + 1, inf); + if (strcmp(buf, version) != 0) + { + printf("Sorry, saved game is out of date.\n"); + return FALSE; + } + + fstat(inf, &sbuf2); + fflush(stdout); + syml = issymlink(file); + if ( +#ifdef WIZARD + !wizard && +#endif + md_unlink(file) < 0) + { + printf("Cannot unlink file\n"); + return FALSE; + } + + fflush(stdout); + + encread(&sbuf.st_ino,sizeof(sbuf.st_ino), inf); + encread(&sbuf.st_dev,sizeof(sbuf.st_dev), inf); + encread(&sbuf.st_ctime,sizeof(sbuf.st_ctime), inf); + encread(&sbuf.st_mtime,sizeof(sbuf.st_mtime), inf); + encread(&slines,sizeof(slines),inf); + encread(&scols,sizeof(scols),inf); + + /* + * we do not close the file so that we will have a hold of the + * inode for as long as possible + */ + + initscr(); + + if (slines > LINES) + { + printf("Sorry, original game was played on a screen with %d lines.\n",slines); + printf("Current screen only has %d lines. Unable to restore game\n",LINES); + return(FALSE); + } + + if (scols > COLS) + { + printf("Sorry, original game was played on a screen with %d columns.\n",scols); + printf("Current screen only has %d columns. Unable to restore game\n",COLS); + return(FALSE); + } + + hw = newwin(LINES, COLS, 0, 0); + keypad(stdscr,1); + + mpos = 0; + mvprintw(0, 0, "%s: %s", file, ctime(&sbuf2.st_mtime)); + + /* + * defeat multiple restarting from the same place + */ +#ifdef WIZARD + if (!wizard) +#endif + if (sbuf2.st_nlink != 1 || syml) + { + printf("Cannot restore from a linked file\n"); + return FALSE; + } + + if (rs_restore_file(inf) == FALSE) + { + endwin(); + printf("Cannot restore file\n"); + return(FALSE); + } + +#ifdef SIGTSTP + signal(SIGTSTP, tstp); +#endif + environ = envp; + strcpy(file_name, file); + setup(); + clearok(curscr, TRUE); + touchwin(stdscr); + srand(getpid()); + msg("file name: %s", file); + status(); + playit(); + return 0; +} + +/* + * encwrite: + * Perform an encrypted write + */ +encwrite(starta, size, outf) +void *starta; +unsigned int size; +register FILE *outf; +{ + register char *ep; + register char *start = (char *) starta; + ep = encstr; + + while (size--) + { + putc(*start++ ^ *ep++, outf); + if (*ep == '\0') + ep = encstr; + } +} + +/* + * encread: + * Perform an encrypted read + */ +encread(starta, size, inf) +register void *starta; +unsigned int size; +register int inf; +{ + register char *ep; + register int read_size; + register char *start = (char *) starta; + + if ((read_size = read(inf, start, size)) == -1 || read_size == 0) + return read_size; + + ep = encstr; + + while (size--) + { + *start++ ^= *ep++; + if (*ep == '\0') + ep = encstr; + } + + return read_size; +}