From f5e0c3c4ca0de8eedaadf135d2b6fd5ccbd2d059 Mon Sep 17 00:00:00 2001 From: David Griffith Date: Sat, 21 Sep 2019 18:12:52 -0700 Subject: [PATCH] Convert quetzal.c to K&R style. --- src/common/quetzal.c | 918 ++++++++++++++++++++++--------------------- 1 file changed, 479 insertions(+), 439 deletions(-) diff --git a/src/common/quetzal.c b/src/common/quetzal.c index b50cb3f..da0c1d7 100644 --- a/src/common/quetzal.c +++ b/src/common/quetzal.c @@ -53,13 +53,11 @@ typedef unsigned long zlong; * 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') @@ -73,7 +71,6 @@ static zword frames[STACK_SIZE/4+1]; /* * Various parsing states within restoration. */ - #define GOT_HEADER 0x01 #define GOT_STACK 0x02 #define GOT_MEMORY 0x04 @@ -84,44 +81,51 @@ static zword frames[STACK_SIZE/4+1]; /* * 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; } @@ -129,437 +133,473 @@ static bool read_long (FILE *f, zlong *result) * 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 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 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 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< 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 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 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