]> granicus.if.org Git - nethack/commitdiff
*** empty log message ***
authorjwalz <jwalz>
Sat, 5 Jan 2002 21:06:00 +0000 (21:06 +0000)
committerjwalz <jwalz>
Sat, 5 Jan 2002 21:06:00 +0000 (21:06 +0000)
util/recover.c [new file with mode: 0644]

diff --git a/util/recover.c b/util/recover.c
new file mode 100644 (file)
index 0000000..94ab547
--- /dev/null
@@ -0,0 +1,359 @@
+/*     SCCS Id: @(#)recover.c  3.3     99/10/23        */
+/*     Copyright (c) Janet Walz, 1992.                           */
+/* NetHack may be freely redistributed.  See license for details. */
+
+/*
+ *  Utility for reconstructing NetHack save file from a set of individual
+ *  level files.  Requires that the `checkpoint' option be enabled at the
+ *  time NetHack creates those level files.
+ */
+#include "config.h"
+#if !defined(O_WRONLY) && !defined(LSC) && !defined(AZTEC_C)
+#include <fcntl.h>
+#endif
+#ifdef WIN32
+#include "win32api.h"
+#endif
+
+#ifdef VMS
+extern int FDECL(vms_creat, (const char *,unsigned));
+extern int FDECL(vms_open, (const char *,int,unsigned));
+#endif /* VMS */
+
+int FDECL(restore_savefile, (char *));
+void FDECL(set_levelfile_name, (int));
+int FDECL(open_levelfile, (int));
+int NDECL(create_savefile);
+void FDECL(copy_bytes, (int,int));
+
+#define Fprintf        (void)fprintf
+#define Close  (void)close
+
+#ifdef UNIX
+#define SAVESIZE       (PL_NSIZ + 13)  /* save/99999player.e */
+#else
+# ifdef VMS
+#define SAVESIZE       (PL_NSIZ + 22)  /* [.save]<uid>player.e;1 */
+# else
+#  ifdef WIN32
+#define SAVESIZE       (PL_NSIZ + 40)  /* username-player.NetHack-saved-game */
+#  else
+#define SAVESIZE       FILENAME        /* from macconf.h or pcconf.h */
+#  endif
+# endif
+#endif
+
+#if defined(EXEPATH)
+char *FDECL(exepath, (char *));
+#endif
+
+#if defined(__BORLANDC__) && !defined(_WIN32)
+extern unsigned _stklen = STKSIZ;
+#endif
+char savename[SAVESIZE]; /* holds relative path of save file from playground */
+
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+       int argno;
+       const char *dir = (char *)0;
+#ifdef AMIGA
+       char *startdir = (char *)0;
+#endif
+
+
+       if (!dir) dir = getenv("NETHACKDIR");
+       if (!dir) dir = getenv("HACKDIR");
+#if defined(EXEPATH)
+       if (!dir) dir = exepath(argv[0]);
+#endif
+       if (argc == 1 || (argc == 2 && !strcmp(argv[1], "-"))) {
+           Fprintf(stderr,
+               "Usage: %s [ -d directory ] base1 [ base2 ... ]\n", argv[0]);
+#if defined(WIN32) || defined(MSDOS)
+           if (dir) {
+               Fprintf(stderr, "\t(Unless you override it with -d, recover will look \n");
+               Fprintf(stderr, "\t in the %s directory on your system)\n", dir);
+           }
+#endif
+           exit(EXIT_FAILURE);
+       }
+
+       argno = 1;
+       if (!strncmp(argv[argno], "-d", 2)) {
+               dir = argv[argno]+2;
+               if (*dir == '=' || *dir == ':') dir++;
+               if (!*dir && argc > argno) {
+                       argno++;
+                       dir = argv[argno];
+               }
+               if (!*dir) {
+                   Fprintf(stderr,
+                       "%s: flag -d must be followed by a directory name.\n",
+                       argv[0]);
+                   exit(EXIT_FAILURE);
+               }
+               argno++;
+       }
+#if defined(SECURE) && !defined(VMS)
+       if (dir
+# ifdef HACKDIR
+               && strcmp(dir, HACKDIR)
+# endif
+               ) {
+               (void) setgid(getgid());
+               (void) setuid(getuid());
+       }
+#endif /* SECURE && !VMS */
+
+#ifdef HACKDIR
+       if (!dir) dir = HACKDIR;
+#endif
+
+#ifdef AMIGA
+       startdir = getcwd(0,255);
+#endif
+       if (dir && chdir((char *) dir) < 0) {
+               Fprintf(stderr, "%s: cannot chdir to %s.\n", argv[0], dir);
+               exit(EXIT_FAILURE);
+       }
+
+       while (argc > argno) {
+               if (restore_savefile(argv[argno]) == 0)
+                   Fprintf(stderr, "recovered \"%s\" to %s\n",
+                           argv[argno], savename);
+               argno++;
+       }
+#ifdef AMIGA
+       if (startdir) (void)chdir(startdir);
+#endif
+       exit(EXIT_SUCCESS);
+       /*NOTREACHED*/
+       return 0;
+}
+
+static char lock[256];
+
+void
+set_levelfile_name(lev)
+int lev;
+{
+       char *tf;
+
+       tf = rindex(lock, '.');
+       if (!tf) tf = lock + strlen(lock);
+       (void) sprintf(tf, ".%d", lev);
+#ifdef VMS
+       (void) strcat(tf, ";1");
+#endif
+}
+
+int
+open_levelfile(lev)
+int lev;
+{
+       int fd;
+
+       set_levelfile_name(lev);
+#if defined(MICRO) || defined(WIN32) || defined(MSDOS)
+       fd = open(lock, O_RDONLY | O_BINARY);
+#else
+       fd = open(lock, O_RDONLY, 0);
+#endif
+       return fd;
+}
+
+int
+create_savefile()
+{
+       int fd;
+
+#if defined(MICRO) || defined(WIN32) || defined(MSDOS)
+       fd = open(savename, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK);
+#else
+       fd = creat(savename, FCMASK);
+#endif
+       return fd;
+}
+
+void
+copy_bytes(ifd, ofd)
+int ifd, ofd;
+{
+       char buf[BUFSIZ];
+       int nfrom, nto;
+
+       do {
+               nfrom = read(ifd, buf, BUFSIZ);
+               nto = write(ofd, buf, nfrom);
+               if (nto != nfrom) {
+                       Fprintf(stderr, "file copy failed!\n");
+                       exit(EXIT_FAILURE);
+               }
+       } while (nfrom == BUFSIZ);
+}
+
+int
+restore_savefile(basename)
+char *basename;
+{
+       int gfd, lfd, sfd;
+       int lev, savelev, hpid;
+       xchar levc;
+       struct version_info version_data;
+
+       /* level 0 file contains:
+        *      pid of creating process (ignored here)
+        *      level number for current level of save file
+        *      name of save file nethack would have created
+        *      and game state
+        */
+       (void) strcpy(lock, basename);
+       gfd = open_levelfile(0);
+       if (gfd < 0) {
+           Fprintf(stderr, "Cannot open level 0 for %s.\n", basename);
+           return(-1);
+       }
+       if (read(gfd, (genericptr_t) &hpid, sizeof hpid) != sizeof hpid) {
+           Fprintf(stderr, "%s\n%s%s%s\n",
+            "Checkpoint data incompletely written or subsequently clobbered;",
+                   "recovery for \"", basename, "\" impossible.");
+           Close(gfd);
+           return(-1);
+       }
+       if (read(gfd, (genericptr_t) &savelev, sizeof(savelev))
+                                                       != sizeof(savelev)) {
+           Fprintf(stderr,
+           "Checkpointing was not in effect for %s -- recovery impossible.\n",
+                   basename);
+           Close(gfd);
+           return(-1);
+       }
+       if ((read(gfd, (genericptr_t) savename, sizeof savename)
+               != sizeof savename) ||
+           (read(gfd, (genericptr_t) &version_data, sizeof version_data)
+               != sizeof version_data)) {
+           Fprintf(stderr, "Error reading %s -- can't recover.\n", lock);
+           Close(gfd);
+           return(-1);
+       }
+
+       /* save file should contain:
+        *      version info
+        *      current level (including pets)
+        *      (non-level-based) game state
+        *      other levels
+        */
+       sfd = create_savefile();
+       if (sfd < 0) {
+           Fprintf(stderr, "Cannot create savefile %s.\n", savename);
+           Close(gfd);
+           return(-1);
+       }
+
+       lfd = open_levelfile(savelev);
+       if (lfd < 0) {
+           Fprintf(stderr, "Cannot open level of save for %s.\n", basename);
+           Close(gfd);
+           Close(sfd);
+           return(-1);
+       }
+
+       if (write(sfd, (genericptr_t) &version_data, sizeof version_data)
+               != sizeof version_data) {
+           Fprintf(stderr, "Error writing %s; recovery failed.\n", savename);
+           Close(gfd);
+           Close(sfd);
+           return(-1);
+       }
+
+       copy_bytes(lfd, sfd);
+       Close(lfd);
+       (void) unlink(lock);
+
+       copy_bytes(gfd, sfd);
+       Close(gfd);
+       set_levelfile_name(0);
+       (void) unlink(lock);
+
+       for (lev = 1; lev < 256; lev++) {
+               /* level numbers are kept in xchars in save.c, so the
+                * maximum level number (for the endlevel) must be < 256
+                */
+               if (lev != savelev) {
+                       lfd = open_levelfile(lev);
+                       if (lfd >= 0) {
+                               /* any or all of these may not exist */
+                               levc = (xchar) lev;
+                               write(sfd, (genericptr_t) &levc, sizeof(levc));
+                               copy_bytes(lfd, sfd);
+                               Close(lfd);
+                               (void) unlink(lock);
+                       }
+               }
+       }
+
+       Close(sfd);
+
+#if 0 /* OBSOLETE, HackWB is no longer in use */
+#ifdef AMIGA
+                       /* we need to create an icon for the saved game
+                        * or HackWB won't notice the file.
+                        */
+       {
+       char iconfile[FILENAME];
+       int in, out;
+
+       (void) sprintf(iconfile, "%s.info", savename);
+       in = open("NetHack:default.icon", O_RDONLY);
+       out = open(iconfile, O_WRONLY | O_TRUNC | O_CREAT);
+       if(in > -1 && out > -1){
+               copy_bytes(in,out);
+       }
+       if(in > -1)close(in);
+       if(out > -1)close(out);
+       }
+#endif
+#endif
+       return(0);
+}
+
+#ifdef EXEPATH
+# ifdef __DJGPP__
+#define PATH_SEPARATOR '/'
+# else
+#define PATH_SEPARATOR '\\'
+# endif
+
+#define EXEPATHBUFSZ 256
+char exepathbuf[EXEPATHBUFSZ];
+
+char *exepath(str)
+char *str;
+{
+       char *tmp, *tmp2;
+       int bsize;
+
+       if (!str) return (char *)0;
+       bsize = EXEPATHBUFSZ;
+       tmp = exepathbuf;
+# ifndef WIN32
+       strcpy (tmp, str);
+# else
+       *(tmp + GetModuleFileName((HANDLE)0, tmp, bsize)) = '\0';
+# endif
+       tmp2 = strrchr(tmp, PATH_SEPARATOR);
+       if (tmp2) *tmp2 = '\0';
+       return tmp;
+}
+#endif /* EXEPATH */
+
+#ifdef AMIGA
+#include "date.h"
+const char amiga_version_string[] = AMIGA_VERSION_STRING;
+#endif
+
+/*recover.c*/