* This is used only by save_quetzal. It probably should be allocated
* dynamically rather than statically.
*/
-
-static zword frames[STACK_SIZE/4+1];
+static zword frames[STACK_SIZE / 4 + 1];
/*
* ID types.
*/
-
#define makeid(a,b,c,d) ((zlong) (((zlong)(a)<<24) | ((zlong)(b)<<16) | ((zlong)(c)<<8) | (zlong)(d)))
#define ID_FORM makeid ('F','O','R','M')
/*
* Various parsing states within restoration.
*/
-
#define GOT_HEADER 0x01
#define GOT_STACK 0x02
#define GOT_MEMORY 0x04
/*
* Macros used to write the files.
*/
-
#define write_byte(fp,b) (put_c (b, fp) != EOF)
#define write_bytx(fp,b) write_byte (fp, (b) & 0xFF)
#define write_word(fp,w) \
- (write_bytx (fp, (w) >> 8) && write_bytx (fp, (w)))
+ (write_bytx (fp, (w) >> 8) && write_bytx (fp, (w)))
#define write_long(fp,l) \
- (write_bytx (fp, (l) >> 24) && write_bytx (fp, (l) >> 16) && \
- write_bytx (fp, (l) >> 8) && write_bytx (fp, (l)))
+ (write_bytx (fp, (l) >> 24) && write_bytx (fp, (l) >> 16) && \
+ write_bytx (fp, (l) >> 8) && write_bytx (fp, (l)))
#define write_chnk(fp,id,len) \
- (write_long (fp, (id)) && write_long (fp, (len)))
+ (write_long (fp, (id)) && write_long (fp, (len)))
#define write_run(fp,run) \
- (write_byte (fp, 0) && write_byte (fp, (run)))
+ (write_byte (fp, 0) && write_byte (fp, (run)))
+
/* Read one word from file; return TRUE if OK. */
-static bool read_word (FILE *f, zword *result)
+static bool read_word(FILE * f, zword * result)
{
- int a, b;
+ int a, b;
- if ((a = get_c (f)) == EOF) return FALSE;
- if ((b = get_c (f)) == EOF) return FALSE;
+ if ((a = get_c(f)) == EOF)
+ return FALSE;
+ if ((b = get_c(f)) == EOF)
+ return FALSE;
- *result = ((zword) a << 8) | (zword) b;
- return TRUE;
+ *result = ((zword) a << 8) | (zword) b;
+ return TRUE;
}
+
/* Read one long from file; return TRUE if OK. */
-static bool read_long (FILE *f, zlong *result)
+static bool read_long(FILE * f, zlong * result)
{
- int a, b, c, d;
-
- if ((a = get_c (f)) == EOF) return FALSE;
- if ((b = get_c (f)) == EOF) return FALSE;
- if ((c = get_c (f)) == EOF) return FALSE;
- if ((d = get_c (f)) == EOF) return FALSE;
-
- *result = ((zlong) a << 24) | ((zlong) b << 16) |
- ((zlong) c << 8) | (zlong) d;
- return TRUE;
+ int a, b, c, d;
+
+ if ((a = get_c(f)) == EOF)
+ return FALSE;
+ if ((b = get_c(f)) == EOF)
+ return FALSE;
+ if ((c = get_c(f)) == EOF)
+ return FALSE;
+ if ((d = get_c(f)) == EOF)
+ return FALSE;
+
+ *result = ((zlong) a << 24) | ((zlong) b << 16) |
+ ((zlong) c << 8) | (zlong) d;
+ return TRUE;
}
* Restore a saved game using Quetzal format. Return 2 if OK, 0 if an error
* occurred before any damage was done, -1 on a fatal error.
*/
-zword restore_quetzal (FILE *svf, FILE *stf)
+zword restore_quetzal(FILE * svf, FILE * stf)
{
- zlong ifzslen, currlen, tmpl;
- zlong pc;
- zword i, tmpw;
- zword fatal = 0; /* Set to -1 when errors must be fatal. */
- zbyte skip, progress = GOT_NONE;
- int x, y;
-
- /* Check it's really an `IFZS' file. */
- if (!read_long (svf, &tmpl)
- || !read_long (svf, &ifzslen)
- || !read_long (svf, &currlen)) return 0;
- if (tmpl != ID_FORM || currlen != ID_IFZS)
- {
- print_string ("This is not a saved game file!\n");
- return 0;
- }
- if ((ifzslen & 1) || ifzslen<4) /* Sanity checks. */ return 0;
- ifzslen -= 4;
-
- /* Read each chunk and process it. */
- while (ifzslen > 0)
- {
- /* Read chunk header. */
- if (ifzslen < 8) /* Couldn't contain a chunk. */ return 0;
- if (!read_long (svf, &tmpl)
- || !read_long (svf, &currlen)) return 0;
- ifzslen -= 8; /* Reduce remaining by size of header. */
-
- /* Handle chunk body. */
- if (ifzslen < currlen) /* Chunk goes past EOF?! */ return 0;
- skip = currlen & 1;
- ifzslen -= currlen + (zlong) skip;
-
- switch (tmpl)
- {
- /* `IFhd' header chunk; must be first in file. */
- case ID_IFhd:
- if (progress & GOT_HEADER)
- {
- print_string ("Save file has two IFZS chunks!\n");
- return fatal;
- }
- progress |= GOT_HEADER;
- if (currlen < 13 || !read_word (svf, &tmpw))
- return fatal;
- if (tmpw != h_release)
- progress = GOT_ERROR;
-
- for (i=H_SERIAL; i<H_SERIAL+6; ++i)
- {
- if ((x = get_c (svf)) == EOF) return fatal;
- if (x != zmp[i])
- progress = GOT_ERROR;
- }
-
- if (!read_word (svf, &tmpw)) return fatal;
- if (tmpw != h_checksum)
- progress = GOT_ERROR;
+ zlong ifzslen, currlen, tmpl;
+ zlong pc;
+ zword i, tmpw;
+ zword fatal = 0; /* Set to -1 when errors must be fatal. */
+ zbyte skip, progress = GOT_NONE;
+ int x, y;
+
+ /* Check it's really an `IFZS' file. */
+ if (!read_long(svf, &tmpl)
+ || !read_long(svf, &ifzslen)
+ || !read_long(svf, &currlen))
+ return 0;
+ if (tmpl != ID_FORM || currlen != ID_IFZS) {
+ print_string("This is not a saved game file!\n");
+ return 0;
+ }
+ if ((ifzslen & 1) || ifzslen < 4) /* Sanity checks. */
+ return 0;
+ ifzslen -= 4;
+
+ /* Read each chunk and process it. */
+ while (ifzslen > 0) {
+ /* Read chunk header. */
+ if (ifzslen < 8) /* Couldn't contain a chunk. */
+ return 0;
+ if (!read_long(svf, &tmpl)
+ || !read_long(svf, &currlen))
+ return 0;
+ ifzslen -= 8; /* Reduce remaining by size of header. */
+
+ /* Handle chunk body. */
+ if (ifzslen < currlen) /* Chunk goes past EOF?! */
+ return 0;
+ skip = currlen & 1;
+ ifzslen -= currlen + (zlong) skip;
+
+ switch (tmpl) {
+ /* `IFhd' header chunk; must be first in file. */
+ case ID_IFhd:
+ if (progress & GOT_HEADER) {
+ print_string
+ ("Save file has two IFZS chunks!\n");
+ return fatal;
+ }
+ progress |= GOT_HEADER;
+ if (currlen < 13 || !read_word(svf, &tmpw))
+ return fatal;
+ if (tmpw != h_release)
+ progress = GOT_ERROR;
+
+ for (i = H_SERIAL; i < H_SERIAL + 6; ++i) {
+ if ((x = get_c(svf)) == EOF)
+ return fatal;
+ if (x != zmp[i])
+ progress = GOT_ERROR;
+ }
- if (progress & GOT_ERROR)
- {
- print_string ("File was not saved from this story!\n");
- return fatal;
- }
- if ((x = get_c (svf)) == EOF) return fatal;
- pc = (zlong) x << 16;
- if ((x = get_c (svf)) == EOF) return fatal;
- pc |= (zlong) x << 8;
- if ((x = get_c (svf)) == EOF) return fatal;
- pc |= (zlong) x;
- fatal = -1; /* Setting PC means errors must be fatal. */
- SET_PC (pc);
-
- for (i=13; i<currlen; ++i)
- (void) get_c (svf); /* Skip rest of chunk. */
- break;
- /* `Stks' stacks chunk; restoring this is quite complex. ;) */
- case ID_Stks:
- if (progress & GOT_STACK)
- {
- print_string ("File contains two stack chunks!\n");
- break;
- }
- progress |= GOT_STACK;
-
- fatal = -1; /* Setting SP means errors must be fatal. */
- sp = stack + STACK_SIZE;
-
- /*
- * All versions other than V6 may use evaluation stack outside
- * any function context. As a result a faked function context
- * will be present in the file here. We skip this context, but
- * load the associated stack onto the stack proper...
- */
- if (h_version != V6)
- {
- if (currlen < 8) return fatal;
- for (i=0; i<6; ++i)
- if (get_c (svf) != 0) return fatal;
- if (!read_word (svf, &tmpw)) return fatal;
- if (tmpw > STACK_SIZE)
- {
- print_string ("Save-file has too much stack (and I can't cope).\n");
- return fatal;
- }
- currlen -= 8;
- if (currlen < tmpw*2) return fatal;
- for (i=0; i<tmpw; ++i)
- if (!read_word (svf, --sp)) return fatal;
- currlen -= tmpw*2;
- }
+ if (!read_word(svf, &tmpw))
+ return fatal;
+ if (tmpw != h_checksum)
+ progress = GOT_ERROR;
- /* We now proceed to load the main block of stack frames. */
- for (fp = stack+STACK_SIZE, frame_count = 0;
- currlen > 0;
- currlen -= 8, ++frame_count)
- {
- if (currlen < 8) return fatal;
- if (sp - stack < 4) /* No space for frame. */
- {
- print_string ("Save-file has too much stack (and I can't cope).\n");
- return fatal;
- }
-
- /* Read PC, procedure flag and formal param count. */
- if (!read_long (svf, &tmpl)) return fatal;
- y = (int) (tmpl & 0x0F); /* Number of formals. */
- tmpw = y << 8;
-
- /* Read result variable. */
- if ((x = get_c (svf)) == EOF) return fatal;
-
- /* Check the procedure flag... */
- if (tmpl & 0x10)
- {
- tmpw |= 0x1000; /* It's a procedure. */
- tmpl >>= 8; /* Shift to get PC value. */
- }
- else
- {
- /* Functions have type 0, so no need to or anything. */
- tmpl >>= 8; /* Shift to get PC value. */
- --tmpl; /* Point at result byte. */
- /* Sanity check on result variable... */
- if (zmp[tmpl] != (zbyte) x)
- {
- print_string ("Save-file has wrong variable number on stack (possibly wrong game version?)\n");
- return fatal;
+ if (progress & GOT_ERROR) {
+ print_string
+ ("File was not saved from this story!\n");
+ return fatal;
}
- }
- *--sp = (zword) (tmpl >> 9); /* High part of PC */
- *--sp = (zword) (tmpl & 0x1FF); /* Low part of PC */
- *--sp = (zword) (fp - stack - 1); /* FP */
-
- /* Read and process argument mask. */
- if ((x = get_c (svf)) == EOF) return fatal;
- ++x; /* Should now be a power of 2 */
- for (i=0; i<8; ++i)
- if (x & (1<<i))
- break;
- if (x ^ (1<<i)) /* Not a power of 2 */
- {
- print_string ("Save-file uses incomplete argument lists (which I can't handle)\n");
- return fatal;
- }
- *--sp = tmpw | i;
- fp = sp; /* FP for next frame. */
-
- /* Read amount of eval stack used. */
- if (!read_word (svf, &tmpw)) return fatal;
-
- tmpw += y; /* Amount of stack + number of locals. */
- if (sp - stack <= tmpw)
- {
- print_string ("Save-file has too much stack (and I can't cope).\n");
- return fatal;
- }
- if (currlen < tmpw*2) return fatal;
- for (i=0; i<tmpw; ++i)
- if (!read_word (svf, --sp)) return fatal;
- currlen -= tmpw*2;
- }
- /* End of `Stks' processing... */
- break;
- /* Any more special chunk types must go in HERE or ABOVE. */
- /* `CMem' compressed memory chunk; uncompress it. */
- case ID_CMem:
- if (!(progress & GOT_MEMORY)) /* Don't complain if two. */
- {
- (void) os_storyfile_seek (stf, 0, SEEK_SET);
- i=0; /* Bytes written to data area. */
- for (; currlen > 0; --currlen)
- {
- if ((x = get_c (svf)) == EOF) return fatal;
- if (x == 0) /* Start run. */
- {
- /* Check for bogus run. */
- if (currlen < 2)
- {
- print_string ("File contains bogus `CMem' chunk.\n");
- for (; currlen > 0; --currlen)
- (void) get_c (svf); /* Skip rest. */
- currlen = 1;
- i = 0xFFFF;
- break; /* Keep going; may be a `UMem' too. */
- }
- /* Copy story file to memory during the run. */
- --currlen;
- if ((x = get_c (svf)) == EOF) return fatal;
- for (; x >= 0 && i<h_dynamic_size; --x, ++i)
- if ((y = get_c (stf)) == EOF) return fatal;
- else
- zmp[i] = (zbyte) y;
+ if ((x = get_c(svf)) == EOF)
+ return fatal;
+ pc = (zlong) x << 16;
+ if ((x = get_c(svf)) == EOF)
+ return fatal;
+ pc |= (zlong) x << 8;
+ if ((x = get_c(svf)) == EOF)
+ return fatal;
+ pc |= (zlong) x;
+ fatal = -1; /* Setting PC means errors must be fatal. */
+ SET_PC(pc);
+
+ for (i = 13; i < currlen; ++i)
+ (void)get_c(svf); /* Skip rest of chunk. */
+ break;
+ /* `Stks' stacks chunk; restoring this is quite complex. ;) */
+ case ID_Stks:
+ if (progress & GOT_STACK) {
+ print_string
+ ("File contains two stack chunks!\n");
+ break;
}
- else /* Not a run. */
- {
- if ((y = get_c (stf)) == EOF) return fatal;
- zmp[i] = (zbyte) (x ^ y);
- ++i;
+ progress |= GOT_STACK;
+
+ fatal = -1; /* Setting SP means errors must be fatal. */
+ sp = stack + STACK_SIZE;
+
+ /*
+ * All versions other than V6 may use evaluation stack outside
+ * any function context. As a result a faked function context
+ * will be present in the file here. We skip this context, but
+ * load the associated stack onto the stack proper...
+ */
+ if (h_version != V6) {
+ if (currlen < 8)
+ return fatal;
+ for (i = 0; i < 6; ++i)
+ if (get_c(svf) != 0)
+ return fatal;
+ if (!read_word(svf, &tmpw))
+ return fatal;
+ if (tmpw > STACK_SIZE) {
+ print_string
+ ("Save-file has too much stack (and I can't cope).\n");
+ return fatal;
+ }
+ currlen -= 8;
+ if (currlen < tmpw * 2)
+ return fatal;
+ for (i = 0; i < tmpw; ++i)
+ if (!read_word(svf, --sp))
+ return fatal;
+ currlen -= tmpw * 2;
}
- /* Make sure we don't load too much. */
- if (i > h_dynamic_size)
- {
- print_string ("warning: `CMem' chunk too long!\n");
- for (; currlen > 1; --currlen)
- (void) get_c (svf); /* Skip rest. */
- break; /* Keep going; there may be a `UMem' too. */
+
+ /* We now proceed to load the main block of stack frames. */
+ for (fp = stack + STACK_SIZE, frame_count = 0;
+ currlen > 0; currlen -= 8, ++frame_count) {
+ if (currlen < 8)
+ return fatal;
+ if (sp - stack < 4) { /* No space for frame. */
+ print_string
+ ("Save-file has too much stack (and I can't cope).\n");
+ return fatal;
+ }
+
+ /* Read PC, procedure flag and formal param count. */
+ if (!read_long(svf, &tmpl))
+ return fatal;
+ y = (int)(tmpl & 0x0F); /* Number of formals. */
+ tmpw = y << 8;
+
+ /* Read result variable. */
+ if ((x = get_c(svf)) == EOF)
+ return fatal;
+
+ /* Check the procedure flag... */
+ if (tmpl & 0x10) {
+ tmpw |= 0x1000; /* It's a procedure. */
+ tmpl >>= 8; /* Shift to get PC value. */
+ } else {
+ /* Functions have type 0, so no need to or anything. */
+ tmpl >>= 8; /* Shift to get PC value. */
+ --tmpl; /* Point at result byte. */
+ /* Sanity check on result variable... */
+ if (zmp[tmpl] != (zbyte) x) {
+ print_string
+ ("Save-file has wrong variable number on stack (possibly wrong game version?)\n");
+ return fatal;
+ }
+ }
+ *--sp = (zword) (tmpl >> 9); /* High part of PC */
+ *--sp = (zword) (tmpl & 0x1FF); /* Low part of PC */
+ *--sp = (zword) (fp - stack - 1); /* FP */
+
+ /* Read and process argument mask. */
+ if ((x = get_c(svf)) == EOF)
+ return fatal;
+ ++x; /* Should now be a power of 2 */
+ for (i = 0; i < 8; ++i)
+ if (x & (1 << i))
+ break;
+ if (x ^ (1 << i)) { /* Not a power of 2 */
+ print_string
+ ("Save-file uses incomplete argument lists (which I can't handle)\n");
+ return fatal;
+ }
+ *--sp = tmpw | i;
+ fp = sp; /* FP for next frame. */
+
+ /* Read amount of eval stack used. */
+ if (!read_word(svf, &tmpw))
+ return fatal;
+
+ tmpw += y; /* Amount of stack + number of locals. */
+ if (sp - stack <= tmpw) {
+ print_string
+ ("Save-file has too much stack (and I can't cope).\n");
+ return fatal;
+ }
+ if (currlen < tmpw * 2)
+ return fatal;
+ for (i = 0; i < tmpw; ++i)
+ if (!read_word(svf, --sp))
+ return fatal;
+ currlen -= tmpw * 2;
+ }
+ /* End of `Stks' processing... */
+ break;
+ /* Any more special chunk types must go in HERE or ABOVE. */
+ /* `CMem' compressed memory chunk; uncompress it. */
+ case ID_CMem:
+ if (!(progress & GOT_MEMORY)) { /* Don't complain if two. */
+ (void)os_storyfile_seek(stf, 0, SEEK_SET);
+ i = 0; /* Bytes written to data area. */
+ for (; currlen > 0; --currlen) {
+ if ((x = get_c(svf)) == EOF)
+ return fatal;
+ if (x == 0) { /* Start run. */
+ /* Check for bogus run. */
+ if (currlen < 2) {
+ print_string
+ ("File contains bogus `CMem' chunk.\n");
+ for (; currlen > 0;
+ --currlen)
+ (void)get_c(svf); /* Skip rest. */
+ currlen = 1;
+ i = 0xFFFF;
+ break; /* Keep going; may be a `UMem' too. */
+ }
+ /* Copy story file to memory during the run. */
+ --currlen;
+ if ((x = get_c(svf)) == EOF)
+ return fatal;
+ for (;
+ x >= 0
+ && i < h_dynamic_size;
+ --x, ++i)
+ if ((y =
+ get_c(stf)) == EOF)
+ return fatal;
+ else
+ zmp[i] =
+ (zbyte) y;
+ } else { /* Not a run. */
+ if ((y = get_c(stf)) == EOF)
+ return fatal;
+ zmp[i] = (zbyte) (x ^ y);
+ ++i;
+ }
+ /* Make sure we don't load too much. */
+ if (i > h_dynamic_size) {
+ print_string
+ ("warning: `CMem' chunk too long!\n");
+ for (; currlen > 1; --currlen)
+ (void)get_c(svf); /* Skip rest. */
+ break; /* Keep going; there may be a `UMem' too. */
+ }
+ }
+ /* If chunk is short, assume a run. */
+ for (; i < h_dynamic_size; ++i)
+ if ((y = get_c(stf)) == EOF)
+ return fatal;
+ else
+ zmp[i] = (zbyte) y;
+ if (currlen == 0)
+ progress |= GOT_MEMORY; /* Only if succeeded. */
+ break;
}
- }
- /* If chunk is short, assume a run. */
- for (; i<h_dynamic_size; ++i)
- if ((y = get_c (stf)) == EOF) return fatal;
- else
- zmp[i] = (zbyte) y;
- if (currlen == 0)
- progress |= GOT_MEMORY; /* Only if succeeded. */
- break;
- }
- /* Already GOT_MEMORY */
- (void) fseek (svf, currlen, SEEK_CUR); /* Skip chunk. */
- break;
- /* `UMem' uncompressed memory chunk; load it. */
- case ID_UMem:
- if (!(progress & GOT_MEMORY)) /* Don't complain if two. */
- {
- /* Must be exactly the right size. */
- if (currlen == h_dynamic_size)
- {
- if (fread (zmp, currlen, 1, svf) == 1)
- {
- progress |= GOT_MEMORY; /* Only on success. */
- break;
+ /* Already GOT_MEMORY */
+ (void)fseek(svf, currlen, SEEK_CUR); /* Skip chunk. */
+ break;
+ /* `UMem' uncompressed memory chunk; load it. */
+ case ID_UMem:
+ if (!(progress & GOT_MEMORY)) { /* Don't complain if two. */
+ /* Must be exactly the right size. */
+ if (currlen == h_dynamic_size) {
+ if (fread(zmp, currlen, 1, svf) == 1) {
+ progress |= GOT_MEMORY; /* Only on success. */
+ break;
+ }
+ } else
+ /* actually handle the problem outside if statement by skipping chunk. */
+ print_string
+ ("`UMem' chunk wrong size!\n");
}
- }
- else
- /* actually handle the problem outside if statement by skipping chunk. */
- print_string ("`UMem' chunk wrong size!\n");
+ /* Already GOT_MEMORY */
+ (void)fseek(svf, currlen, SEEK_CUR); /* Skip chunk. */
+ break;
+ /* Unrecognised chunk type; skip it. */
+ default:
+ (void)fseek(svf, currlen, SEEK_CUR); /* Skip chunk. */
+ break;
}
- /* Already GOT_MEMORY */
- (void) fseek (svf, currlen, SEEK_CUR); /* Skip chunk. */
- break;
- /* Unrecognised chunk type; skip it. */
- default:
- (void) fseek (svf, currlen, SEEK_CUR); /* Skip chunk. */
- break;
+ if (skip)
+ (void)get_c(svf); /* Skip pad byte. */
}
- if (skip)
- (void) get_c (svf); /* Skip pad byte. */
- }
-
- /*
- * We've reached the end of the file. For the restoration to have been a
- * success, we must have had one of each of the required chunks.
- */
- if (!(progress & GOT_HEADER))
- print_string ("error: no valid header (`IFhd') chunk in file.\n");
- if (!(progress & GOT_STACK))
- print_string ("error: no valid stack (`Stks') chunk in file.\n");
- if (!(progress & GOT_MEMORY))
- print_string ("error: no valid memory (`CMem' or `UMem') chunk in file.\n");
-
- return (progress == GOT_ALL ? 2 : fatal);
+
+ /*
+ * We've reached the end of the file. For the restoration to have been a
+ * success, we must have had one of each of the required chunks.
+ */
+ if (!(progress & GOT_HEADER))
+ print_string
+ ("error: no valid header (`IFhd') chunk in file.\n");
+ if (!(progress & GOT_STACK))
+ print_string("error: no valid stack (`Stks') chunk in file.\n");
+ if (!(progress & GOT_MEMORY))
+ print_string
+ ("error: no valid memory (`CMem' or `UMem') chunk in file.\n");
+
+ return (progress == GOT_ALL ? 2 : fatal);
}
/*
* Save a game using Quetzal format. Return 1 if OK, 0 if failed.
*/
-zword save_quetzal (FILE *svf, FILE *stf)
+zword save_quetzal(FILE * svf, FILE * stf)
{
- zlong ifzslen = 0, cmemlen = 0, stkslen = 0;
- zlong pc;
- zword i, j, n;
- zword nvars, nargs, nstk, *p;
- zbyte var;
- long cmempos, stkspos;
- int c;
-
- /* Write `IFZS' header. */
- if (!write_chnk (svf, ID_FORM, 0)) return 0;
- if (!write_long (svf, ID_IFZS)) return 0;
-
- /* Write `IFhd' chunk. */
- GET_PC (pc);
- if (!write_chnk (svf, ID_IFhd, 13)) return 0;
- if (!write_word (svf, h_release)) return 0;
- for (i=H_SERIAL; i<H_SERIAL+6; ++i)
- if (!write_byte (svf, zmp[i])) return 0;
- if (!write_word (svf, h_checksum)) return 0;
- if (!write_long (svf, pc << 8)) /* Includes pad. */ return 0;
-
- /* Write `CMem' chunk. */
- if ((cmempos = ftell (svf)) < 0) return 0;
- if (!write_chnk (svf, ID_CMem, 0)) return 0;
- (void) os_storyfile_seek (stf, 0, SEEK_SET);
- /* j holds current run length. */
- for (i=0, j=0, cmemlen=0; i < h_dynamic_size; ++i)
- {
- if ((c = get_c (stf)) == EOF) return 0;
- c ^= (int) zmp[i];
- if (c == 0)
- ++j; /* It's a run of equal bytes. */
- else
- {
- /* Write out any run there may be. */
- if (j > 0)
- {
- for (; j > 0x100; j -= 0x100)
- {
- if (!write_run (svf, 0xFF)) return 0;
- cmemlen += 2;
+ zlong ifzslen = 0, cmemlen = 0, stkslen = 0;
+ zlong pc;
+ zword i, j, n;
+ zword nvars, nargs, nstk, *p;
+ zbyte var;
+ long cmempos, stkspos;
+ int c;
+
+ /* Write `IFZS' header. */
+ if (!write_chnk(svf, ID_FORM, 0))
+ return 0;
+ if (!write_long(svf, ID_IFZS))
+ return 0;
+
+ /* Write `IFhd' chunk. */
+ GET_PC(pc);
+ if (!write_chnk(svf, ID_IFhd, 13))
+ return 0;
+ if (!write_word(svf, h_release))
+ return 0;
+ for (i = H_SERIAL; i < H_SERIAL + 6; ++i)
+ if (!write_byte(svf, zmp[i]))
+ return 0;
+ if (!write_word(svf, h_checksum))
+ return 0;
+ if (!write_long(svf, pc << 8)) /* Includes pad. */
+ return 0;
+
+ /* Write `CMem' chunk. */
+ if ((cmempos = ftell(svf)) < 0)
+ return 0;
+ if (!write_chnk(svf, ID_CMem, 0))
+ return 0;
+ (void)os_storyfile_seek(stf, 0, SEEK_SET);
+ /* j holds current run length. */
+ for (i = 0, j = 0, cmemlen = 0; i < h_dynamic_size; ++i) {
+ if ((c = get_c(stf)) == EOF)
+ return 0;
+ c ^= (int)zmp[i];
+ if (c == 0)
+ ++j; /* It's a run of equal bytes. */
+ else {
+ /* Write out any run there may be. */
+ if (j > 0) {
+ for (; j > 0x100; j -= 0x100) {
+ if (!write_run(svf, 0xFF))
+ return 0;
+ cmemlen += 2;
+ }
+ if (!write_run(svf, j - 1))
+ return 0;
+ cmemlen += 2;
+ j = 0;
+ }
+ /* Any runs are now written. Write this (nonzero) byte. */
+ if (!write_byte(svf, (zbyte) c))
+ return 0;
+ ++cmemlen;
}
- if (!write_run (svf, j-1)) return 0;
- cmemlen += 2;
- j = 0;
- }
- /* Any runs are now written. Write this (nonzero) byte. */
- if (!write_byte (svf, (zbyte) c)) return 0;
- ++cmemlen;
}
- }
- /*
- * Reached end of dynamic memory. We ignore any unwritten run there may be
- * at this point.
- */
- if (cmemlen & 1) /* Chunk length must be even. */
- if (!write_byte (svf, 0)) return 0;
-
- /* Write `Stks' chunk. You are not expected to understand this. ;) */
- if ((stkspos = ftell (svf)) < 0) return 0;
- if (!write_chnk (svf, ID_Stks, 0)) return 0;
-
- /*
- * We construct a list of frame indices, most recent first, in `frames'.
- * These indices are the offsets into the `stack' array of the word before
- * the first word pushed in each frame.
- */
- frames[0] = sp - stack; /* The frame we'd get by doing a call now. */
- for (i = fp - stack + 4, n=0; i < STACK_SIZE+4; i = stack[i-3] + 5)
- frames[++n] = i;
-
- /*
- * All versions other than V6 can use evaluation stack outside a function
- * context. We write a faked stack frame (most fields zero) to cater for
- * this.
- */
- if (h_version != V6)
- {
- for (i=0; i<6; ++i)
- if (!write_byte (svf, 0)) return 0;
- nstk = STACK_SIZE - frames[n];
- if (!write_word (svf, nstk)) return 0;
- for (j=STACK_SIZE-1; j >= frames[n]; --j)
- if (!write_word (svf, stack[j])) return 0;
- stkslen = 8 + 2*nstk;
- }
-
- /* Write out the rest of the stack frames. */
- for (i=n; i>0; --i)
- {
- p = stack + frames[i] - 4; /* Points to call frame. */
- nvars = (p[0] & 0x0F00) >> 8;
- nargs = p[0] & 0x00FF;
- nstk = frames[i] - frames[i-1] - nvars - 4;
- pc = ((zlong) p[3] << 9) | p[2];
-
- switch (p[0] & 0xF000) /* Check type of call. */
- {
- case 0x0000: /* Function. */
- var = zmp[pc];
- pc = ((pc + 1) << 8) | nvars;
- break;
- case 0x1000: /* Procedure. */
- var = 0;
- pc = (pc << 8) | 0x10 | nvars; /* Set procedure flag. */
- break;
- /* case 0x2000: */
- default:
- runtime_error (ERR_SAVE_IN_INTER);
+
+ /*
+ * Reached end of dynamic memory. We ignore any unwritten run there may be
+ * at this point.
+ */
+ if (cmemlen & 1) /* Chunk length must be even. */
+ if (!write_byte(svf, 0))
+ return 0;
+
+ /* Write `Stks' chunk. You are not expected to understand this. ;) */
+ if ((stkspos = ftell(svf)) < 0)
+ return 0;
+ if (!write_chnk(svf, ID_Stks, 0))
return 0;
+
+ /*
+ * We construct a list of frame indices, most recent first, in `frames'.
+ * These indices are the offsets into the `stack' array of the word before
+ * the first word pushed in each frame.
+ */
+ frames[0] = sp - stack; /* The frame we'd get by doing a call now. */
+ for (i = fp - stack + 4, n = 0; i < STACK_SIZE + 4;
+ i = stack[i - 3] + 5)
+ frames[++n] = i;
+
+ /*
+ * All versions other than V6 can use evaluation stack outside a function
+ * context. We write a faked stack frame (most fields zero) to cater for
+ * this.
+ */
+ if (h_version != V6) {
+ for (i = 0; i < 6; ++i)
+ if (!write_byte(svf, 0))
+ return 0;
+ nstk = STACK_SIZE - frames[n];
+ if (!write_word(svf, nstk))
+ return 0;
+ for (j = STACK_SIZE - 1; j >= frames[n]; --j)
+ if (!write_word(svf, stack[j]))
+ return 0;
+ stkslen = 8 + 2 * nstk;
+ }
+
+ /* Write out the rest of the stack frames. */
+ for (i = n; i > 0; --i) {
+ p = stack + frames[i] - 4; /* Points to call frame. */
+ nvars = (p[0] & 0x0F00) >> 8;
+ nargs = p[0] & 0x00FF;
+ nstk = frames[i] - frames[i - 1] - nvars - 4;
+ pc = ((zlong) p[3] << 9) | p[2];
+
+ switch (p[0] & 0xF000) { /* Check type of call. */
+ case 0x0000: /* Function. */
+ var = zmp[pc];
+ pc = ((pc + 1) << 8) | nvars;
+ break;
+ case 0x1000: /* Procedure. */
+ var = 0;
+ pc = (pc << 8) | 0x10 | nvars; /* Set procedure flag. */
+ break;
+ /* case 0x2000: */
+ default:
+ runtime_error(ERR_SAVE_IN_INTER);
+ return 0;
+ }
+ if (nargs != 0)
+ nargs = (1 << nargs) - 1; /* Make args into bitmap. */
+
+ /* Write the main part of the frame... */
+ if (!write_long(svf, pc)
+ || !write_byte(svf, var)
+ || !write_byte(svf, nargs)
+ || !write_word(svf, nstk))
+ return 0;
+
+ /* Write the variables and eval stack. */
+ for (j = 0, --p; j < nvars + nstk; ++j, --p)
+ if (!write_word(svf, *p))
+ return 0;
+
+ /* Calculate length written thus far. */
+ stkslen += 8 + 2 * (nvars + nstk);
}
- if (nargs != 0)
- nargs = (1 << nargs) - 1; /* Make args into bitmap. */
-
- /* Write the main part of the frame... */
- if (!write_long (svf, pc)
- || !write_byte (svf, var)
- || !write_byte (svf, nargs)
- || !write_word (svf, nstk)) return 0;
-
- /* Write the variables and eval stack. */
- for (j=0, --p; j<nvars+nstk; ++j, --p)
- if (!write_word (svf, *p)) return 0;
-
- /* Calculate length written thus far. */
- stkslen += 8 + 2 * (nvars + nstk);
- }
-
- /* Fill in variable chunk lengths. */
- ifzslen = 3*8 + 4 + 14 + cmemlen + stkslen;
- if (cmemlen & 1)
- ++ifzslen;
- (void) fseek (svf, 4, SEEK_SET);
- if (!write_long (svf, ifzslen)) return 0;
- (void) fseek (svf, cmempos+4, SEEK_SET);
- if (!write_long (svf, cmemlen)) return 0;
- (void) fseek (svf, stkspos+4, SEEK_SET);
- if (!write_long (svf, stkslen)) return 0;
-
- /* After all that, still nothing went wrong! */
- return 1;
+
+ /* Fill in variable chunk lengths. */
+ ifzslen = 3 * 8 + 4 + 14 + cmemlen + stkslen;
+ if (cmemlen & 1)
+ ++ifzslen;
+ (void)fseek(svf, 4, SEEK_SET);
+ if (!write_long(svf, ifzslen))
+ return 0;
+ (void)fseek(svf, cmempos + 4, SEEK_SET);
+ if (!write_long(svf, cmemlen))
+ return 0;
+ (void)fseek(svf, stkspos + 4, SEEK_SET);
+ if (!write_long(svf, stkslen))
+ return 0;
+
+ /* After all that, still nothing went wrong! */
+ return 1;
}