2 * Copyright 2010-2012 Chris Spiegel.
4 * This file is part of Bocfel.
6 * Bocfel is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License, version
8 * 2 or 3, as published by the Free Software Foundation.
10 * Bocfel is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with Bocfel. If not, see <http://www.gnu.org/licenses/>.
45 static struct call_frame *frames;
46 static struct call_frame *fp;
48 #define BASE_OF_FRAMES frames
49 static struct call_frame *TOP_OF_FRAMES;
50 #define CURRENT_FRAME (fp - 1)
51 #define NFRAMES ((long)(fp - frames))
53 static uint16_t *stack;
56 #define BASE_OF_STACK stack
57 static uint16_t *TOP_OF_STACK;
59 static void PUSH_STACK(uint16_t n) { ZASSERT(sp != TOP_OF_STACK, "stack overflow"); *sp++ = n; }
60 static uint16_t POP_STACK(void) { ZASSERT(sp > CURRENT_FRAME->sp, "stack underflow"); return *--sp; }
62 static struct save_state
73 struct call_frame *frames;
75 struct save_state *prev, *next;
76 } *saves_head, *saves_tail;
80 static void add_frame(uint32_t pc_, uint16_t *sp_, uint8_t nlocals, uint8_t nargs, uint16_t where)
82 ZASSERT(fp != TOP_OF_FRAMES, "call stack too deep: %ld", NFRAMES + 1);
86 fp->nlocals = nlocals;
95 /* Allocate space for the evaluation and call stacks.
96 * Clamp the size between 1 and the largest value that will not
97 * produce an overflow of size_t when multiplied by the size of the
99 * Also, the call stack can be no larger than 0xffff so that the
100 * result of a @catch will fit into a 16-bit integer.
104 #define MIN(a, b) ((a) < (b) ? (a) : (b))
105 #define CLAMP(n, a, b) ((n) < (a) ? (a) : (n) > (b) ? (b): (n))
106 options.eval_stack_size = CLAMP(options.eval_stack_size, 1, SIZE_MAX / sizeof *stack);
107 stack = malloc(options.eval_stack_size * sizeof *stack);
108 if(stack == NULL) die("unable to allocate %lu bytes for the evaluation stack", options.eval_stack_size * (unsigned long)sizeof *stack);
109 TOP_OF_STACK = &stack[options.eval_stack_size];
111 options.call_stack_size = CLAMP(options.call_stack_size, 1, MIN(0xffff, (SIZE_MAX / sizeof *frames) - sizeof *frames));
112 /* One extra to help with saving (thus the subtraction of sizeof *frames above). */
113 frames = malloc((options.call_stack_size + 1) * sizeof *frames);
114 if(frames == NULL) die("unable to allocate %lu bytes for the call stack", (options.call_stack_size + 1) * (unsigned long)sizeof *frames);
115 TOP_OF_FRAMES = &frames[options.call_stack_size];
123 /* Quetzal requires a dummy frame in non-V6 games, so do that here. */
124 if(zversion != 6) add_frame(0, sp, 0, 0, 0);
126 /* Free all previous save states (from @save_undo). */
127 while(saves_head != NULL)
129 struct save_state *tmp = saves_head;
130 saves_head = saves_head->next;
140 uint16_t variable(uint16_t var)
142 ZASSERT(var < 0x100, "unable to decode variable %u", (unsigned)var);
153 ZASSERT(var <= CURRENT_FRAME->nlocals, "attempting to read from nonexistent local variable %d: routine has %d", (int)var, CURRENT_FRAME->nlocals);
154 return CURRENT_FRAME->locals[var - 1];
161 return WORD(header.globals + (var * 2));
164 /* This is an “impossible” situation (ie, the game did something wrong).
165 * It will be caught above if safety checks are turned on, but if they
166 * are not, do what we can: lie.
171 void store_variable(uint16_t var, uint16_t n)
173 ZASSERT(var < 0x100, "unable to decode variable %u", (unsigned)var);
181 /* Local variables. */
184 ZASSERT(var <= CURRENT_FRAME->nlocals, "attempting to store to nonexistent local variable %d: routine has %d", (int)var, CURRENT_FRAME->nlocals);
185 CURRENT_FRAME->locals[var - 1] = n;
188 /* Global variables. */
192 STORE_WORD(header.globals + (var * 2), n);
196 uint16_t *stack_top_element(void)
198 ZASSERT(sp > CURRENT_FRAME->sp, "stack underflow");
205 PUSH_STACK(zargs[0]);
216 /* The z-spec 1.1 requires indirect variable references to the stack not to push/pop */
217 if(zargs[0] == 0) *stack_top_element() = v;
218 else store_variable(zargs[0], v);
228 uint16_t slots = user_word(zargs[0]) + 1;
230 v = user_word(zargs[0] + (2 * slots));
232 user_store_word(zargs[0], slots);
241 /* The z-spec 1.1 requires indirect variable references to the stack not to push/pop */
242 if(zargs[0] == 0) store(*stack_top_element());
243 else store(variable(zargs[0]));
248 /* The z-spec 1.1 requires indirect variable references to the stack not to push/pop */
249 if(zargs[0] == 0) *stack_top_element() = zargs[1];
250 else store_variable(zargs[0], zargs[1]);
253 void call(int do_store)
261 /* call(2) should never happen if zargs[0] is 0. */
262 if(do_store) store(0);
266 jmp_to = unpack(zargs[0], 0);
267 ZASSERT(jmp_to < memory_size - 1, "call to invalid address 0x%lx", (unsigned long)jmp_to);
269 nlocals = BYTE(jmp_to++);
270 ZASSERT(nlocals <= 15, "too many (%d) locals at 0x%lx", nlocals, (unsigned long)jmp_to - 1);
272 if(zversion <= 4) ZASSERT(jmp_to + (nlocals * 2) < memory_size, "call to invalid address 0x%lx", (unsigned long)jmp_to);
276 case 1: where = BYTE(pc++); break; /* Where to store return value */
277 case 0: where = 0xff + 1; break; /* Or a tag meaning no return value */
278 default: where = 0xff + 2; break; /* Or a tag meaning push the return value */
281 add_frame(pc, sp, nlocals, znargs - 1, where);
283 for(int i = 0; i < nlocals; i++)
287 CURRENT_FRAME->locals[i] = zargs[i + 1];
291 if(zversion <= 4) CURRENT_FRAME->locals[i] = WORD(jmp_to + (2 * i));
292 else CURRENT_FRAME->locals[i] = 0;
296 /* Take care of locals! */
297 if(zversion <= 4) jmp_to += nlocals * 2;
303 uint16_t direct_call(uint16_t routine)
305 uint16_t saved_args[znargs];
306 uint16_t saved_nargs;
308 memcpy(saved_args, zargs, sizeof saved_args);
309 saved_nargs = znargs;
315 process_instructions();
317 memcpy(zargs, saved_args, sizeof saved_args);
318 znargs = saved_nargs;
324 void zcall_store(void)
328 void zcall_nostore(void)
333 void do_return(uint16_t retval)
337 ZASSERT(NFRAMES > 1, "return attempted outside of a function");
339 pc = CURRENT_FRAME->pc;
340 sp = CURRENT_FRAME->sp;
341 where = CURRENT_FRAME->where;
346 store_variable(where, retval);
348 else if(where == 0xff + 2)
351 break_from(interrupt_level());
355 void zret_popped(void)
357 do_return(POP_STACK());
367 ZASSERT(zversion == 6 || NFRAMES > 1, "@catch called outside of a function");
369 /* Must account for the dummy frame in non-V6 stories. */
370 store(zversion == 6 ? NFRAMES : NFRAMES - 1);
375 /* As with @catch, account for the dummy frame. */
376 if(zversion != 6) zargs[1]++;
378 ZASSERT(zversion == 6 || NFRAMES > 1, "@throw called outside of a function");
379 ZASSERT(zargs[1] <= NFRAMES, "unwinding too far");
381 fp = BASE_OF_FRAMES + zargs[1];
401 void zcheck_arg_count(void)
403 ZASSERT(zversion == 6 || NFRAMES > 1, "@check_arg_count called outside of a function");
405 branch_if(zargs[0] <= CURRENT_FRAME->nargs);
408 void zpop_stack(void)
412 for(uint16_t i = 0; i < zargs[0]; i++) POP_STACK();
416 user_store_word(zargs[1], user_word(zargs[1]) + zargs[0]);
420 void zpush_stack(void)
422 uint16_t slots = user_word(zargs[1]);
430 user_store_word(zargs[1] + (2 * slots), zargs[0]);
431 user_store_word(zargs[1], slots - 1);
436 /* Compress dynamic memory according to Quetzal. Memory is allocated
437 * for the passed-in pointer, and must be freed by the caller. The
438 * return value is the size of compressed memory, or 0 on failure.
440 static uint32_t compress_memory(uint8_t **compressed)
446 /* The output buffer needs to be 1.5× the size of dynamic memory for
447 * the worst-case scenario: every other byte in memory differs from
448 * the story file. This will cause every other byte to take up two
449 * bytes in the output, thus creating 3 bytes of output for every 2 of
450 * input. This should round up for the extreme case of alternating
451 * zero/non-zero bytes with zeroes at the beginning and end, but due
452 * to the fact that trailing zeroes are not stored, it does not need
455 tmp = malloc((3 * header.static_start) / 2);
456 if(tmp == NULL) return 0;
462 /* Count zeroes. Stop counting when:
463 * • The end of dynamic memory is reached
464 * • A non-zero value is found
466 while(i < header.static_start && (BYTE(i) ^ dynamic_memory[i]) == 0)
473 /* A run of zeroes at the end need not be written. */
474 if(i == header.static_start) break;
476 /* If there has been a run of zeroes, write them out
482 tmp[ret++] = (run > 256 ? 255 : run - 1);
486 /* The current byte differs from the story, so write it. */
487 tmp[ret++] = BYTE(i) ^ dynamic_memory[i];
492 *compressed = realloc(tmp, ret);
493 if(*compressed == NULL) *compressed = tmp;
498 /* Reverse of the above function. */
499 static int uncompress_memory(const uint8_t *compressed, uint32_t size)
501 uint32_t memory_index = 0;
503 memcpy(memory, dynamic_memory, header.static_start);
505 for(uint32_t i = 0; i < size; i++)
507 if(compressed[i] != 0)
509 if(memory_index == header.static_start) return -1;
510 STORE_BYTE(memory_index, BYTE(memory_index) ^ compressed[i]);
515 if(++i == size) return -1;
517 if(memory_index + (compressed[i] + 1) > header.static_start) return -1;
518 memory_index += (compressed[i] + 1);
525 /* Push the current game state onto the game-state stack. */
528 struct save_state *new;
530 if(options.max_saves == 0) return -1;
532 new = malloc(sizeof *new);
533 if(new == NULL) goto err;
539 new->stack_size = sp - BASE_OF_STACK;
540 new->stack = malloc(new->stack_size * sizeof *new->stack);
541 if(new->stack == NULL) goto err;
542 memcpy(new->stack, BASE_OF_STACK, new->stack_size * sizeof *new->stack);
544 new->nframes = NFRAMES;
545 new->frames = malloc(new->nframes * sizeof *new->frames);
546 if(new->frames == NULL) goto err;
547 memcpy(new->frames, BASE_OF_FRAMES, new->nframes * sizeof *new->frames);
549 if(options.disable_undo_compression)
551 new->memory = malloc(header.static_start);
552 if(new->memory == NULL) goto err;
553 memcpy(new->memory, memory, header.static_start);
557 new->memsize = compress_memory(&new->memory);
558 if(new->memsize == 0) goto err;
561 /* If the maximum number has been reached, drop the last element.
562 * A negative value for max_saves means there is no maximum.
564 if(options.max_saves > 0 && nsaves == options.max_saves)
566 struct save_state *tmp = saves_tail;
567 saves_tail = saves_tail->prev;
568 if(saves_tail == NULL) saves_head = NULL;
569 else saves_tail->next = NULL;
577 new->next = saves_head;
579 if(new->next != NULL) new->next->prev = new;
581 if(saves_tail == NULL) saves_tail = new;
598 /* Pop the last-stored game state and jump to it. */
601 struct save_state *p;
603 if(nsaves == 0) return 0;
609 if(options.disable_undo_compression)
611 memcpy(memory, p->memory, header.static_start);
615 /* If this fails it’s a bug: unlike Quetzal files, the contents of
616 * p->memory are known to be good, because the compression was done
617 * by us with no chance for corruption (apart, again, from bugs).
619 if(uncompress_memory(p->memory, p->memsize) == -1) die("error uncompressing memory: unable to continue");
622 sp = BASE_OF_STACK + p->stack_size;
623 memcpy(BASE_OF_STACK, p->stack, sizeof *sp * p->stack_size);
625 fp = BASE_OF_FRAMES + p->nframes;
626 memcpy(BASE_OF_FRAMES, p->frames, sizeof *p->frames * p->nframes);
628 /* Never pop off the last state. A story has every right to call
629 * @restore_undo as many times as it called @save_undo. However, if
630 * there aren’t enough save slots, popping off the last state would
631 * cause @restore_undo to return failure when it should not.
635 saves_head = saves_head->next;
636 saves_head->prev = NULL;
649 void zsave_undo(void)
651 if(interrupt_level() != 0) die("@save_undo called inside of an interrupt");
656 void zrestore_undo(void)
660 /* §6.1.2: Flags 2 should be preserved. */
663 STORE_WORD(0x10, flags2);
666 /* Quetzal save/restore functions. */
667 static jmp_buf exception;
668 #define WRITE8(v) do { uint8_t v_ = (v); if(zterp_io_write(savefile, &v_, sizeof v_) != sizeof v_) longjmp(exception, 1); local_written += 1; } while(0)
669 #define WRITE16(v) do { uint16_t w_ = (v); WRITE8(w_ >> 8); WRITE8(w_ & 0xff); } while(0)
670 #define WRITE32(v) do { uint32_t x_ = (v); WRITE8(x_ >> 24); WRITE8((x_ >> 16) & 0xff); WRITE8((x_ >> 8) & 0xff); WRITE8(x_ & 0xff); } while(0)
671 #define WRITEID(v) WRITE32(STRID(v))
673 static size_t quetzal_write_stack(zterp_io *savefile)
675 size_t local_written = 0;
677 /* Add one more “fake” call frame with just enough information to
678 * calculate the evaluation stack used by the current routine.
681 for(struct call_frame *p = BASE_OF_FRAMES; p != fp; p++)
685 WRITE8((p->pc >> 16) & 0xff);
686 WRITE8((p->pc >> 8) & 0xff);
687 WRITE8((p->pc >> 0) & 0xff);
690 if(p->where > 0xff) temp |= 0x10;
693 if(p->where > 0xff) WRITE8(0);
694 else WRITE8(p->where);
696 WRITE8((1U << p->nargs) - 1);
698 /* number of words of evaluation stack used */
699 WRITE16((p + 1)->sp - p->sp);
701 /* local variables */
702 for(int i = 0; i < p->nlocals; i++) WRITE16(p->locals[i]);
704 /* evaluation stack */
705 for(ptrdiff_t i = 0; i < (p + 1)->sp - p->sp; i++) WRITE16(p->sp[i]);
708 return local_written;
711 int save_quetzal(zterp_io *savefile, int is_meta)
713 if(setjmp(exception) != 0) return 0;
715 size_t local_written = 0;
719 uint8_t *mem = memory;
724 WRITEID(" "); /* to be filled in */
725 WRITEID(is_meta ? "BFMS" : "IFZS");
729 WRITE16(header.release);
730 zterp_io_write(savefile, header.serial, 6);
732 WRITE16(header.checksum);
736 WRITE8(0); /* padding */
738 /* Store the filename in an IntD chunk. */
739 game_len = 12 + strlen(game_file);
747 zterp_io_write(savefile, game_file, game_len - 12);
748 local_written += (game_len - 12);
749 if(game_len & 1) WRITE8(0);
751 memsize = compress_memory(&compressed);
753 /* It is possible for the compressed memory size to be larger than
754 * uncompressed; in this case, just store the uncompressed memory.
756 if(memsize > 0 && memsize < header.static_start)
763 memsize = header.static_start;
767 zterp_io_write(savefile, mem, memsize);
768 local_written += memsize;
769 if(memsize & 1) WRITE8(0); /* padding */
773 stks_pos = zterp_io_tell(savefile);
774 WRITEID(" "); /* to be filled in */
775 stack_size = quetzal_write_stack(savefile);
776 local_written += stack_size;
777 if(stack_size & 1) WRITE8(0); /* padding */
779 zterp_io_seek(savefile, 4, SEEK_SET);
780 WRITE32(local_written - 8); /* entire file size minus 8 (FORM + size) */
782 zterp_io_seek(savefile, stks_pos, SEEK_SET);
783 WRITE32(stack_size); /* size of the stacks chunk */
788 /* Restoring can put the system in an inconsistent state by restoring
789 * only part of memory: the save file may be corrupt and cause failure
790 * part way through updating memory, for example. This set of functions
791 * takes a snapshot of the current state of dynamic memory and the
792 * stacks so they can be restored on failure.
794 static uint8_t *memory_backup;
795 static uint16_t *stack_backup;
796 static int stack_backup_size;
797 static struct call_frame *frames_backup;
798 static int frames_backup_size;
800 static void memory_snapshot_free(void)
806 memory_backup = NULL;
808 frames_backup = NULL;
811 static void memory_snapshot(void)
813 memory_snapshot_free();
815 memory_backup = malloc(header.static_start);
816 if(memory_backup == NULL) goto err;
818 memcpy(memory_backup, memory, header.static_start);
820 stack_backup_size = sp - stack;
821 if(stack_backup_size != 0)
823 stack_backup = malloc(stack_backup_size * sizeof *stack);
824 if(stack_backup == NULL) goto err;
825 memcpy(stack_backup, stack, stack_backup_size * sizeof *stack);
828 frames_backup_size = fp - frames;
829 if(frames_backup_size != 0)
831 frames_backup = malloc(frames_backup_size * sizeof *frames);
832 if(frames_backup == NULL) goto err;
833 memcpy(frames_backup, frames, frames_backup_size * sizeof *frames);
839 memory_snapshot_free();
844 static int memory_restore(void)
846 /* stack_backup and frames_backup will be NULL if the stacks were
847 * empty, so use memory_backup to determine if a snapshot has been
850 if(memory_backup == NULL) return 0;
852 memcpy(memory, memory_backup, header.static_start);
853 if(stack_backup != NULL) memcpy(stack, stack_backup, stack_backup_size * sizeof *stack);
854 sp = stack + stack_backup_size;
855 if(frames_backup != NULL) memcpy(frames, frames_backup, frames_backup_size * sizeof *frames);
856 fp = frames + frames_backup_size;
858 memory_snapshot_free();
863 #define goto_err(...) do { show_message("save file error: " __VA_ARGS__); goto err; } while(0)
864 #define goto_death(...) do { show_message("save file error: " __VA_ARGS__); goto death; } while(0)
866 int restore_quetzal(zterp_io *savefile, int is_meta)
873 iff = zterp_iff_parse(savefile, is_meta ? "BFMS" : "IFZS");
876 !zterp_iff_find(iff, "IFhd", &size) ||
878 zterp_io_read(savefile, ifhd, sizeof ifhd) != sizeof ifhd)
880 goto_err("corrupted save file or not a save file at all");
883 if(((ifhd[0] << 8) | ifhd[1]) != header.release ||
884 memcmp(&ifhd[2], header.serial, sizeof header.serial) != 0 ||
885 ((ifhd[8] << 8) | ifhd[9]) != header.checksum)
887 goto_err("wrong game or version");
892 if(zterp_iff_find(iff, "CMem", &size))
894 uint8_t buf[size]; /* Too big for the stack? */
896 if(zterp_io_read(savefile, buf, size) != size) goto_err("unexpected eof reading compressed memory");
898 if(uncompress_memory(buf, size) == -1) goto_death("memory cannot be uncompressed");
900 else if(zterp_iff_find(iff, "UMem", &size))
902 if(size != header.static_start) goto_err("memory size mismatch");
903 if(zterp_io_read(savefile, memory, header.static_start) != header.static_start) goto_death("unexpected eof reading memory");
907 goto_err("no memory chunk found");
910 if(!zterp_iff_find(iff, "Stks", &size)) goto_death("no stacks chunk found");
922 if(zterp_io_read(savefile, frame, sizeof frame) != sizeof frame) goto_death("unexpected eof reading stack frame");
925 nlocals = frame[3] & 0xf;
926 nstack = (frame[6] << 8) | frame[7];
928 while(frame[5] >>= 1) nargs++;
930 add_frame((frame[0] << 16) | (frame[1] << 8) | frame[2], sp, nlocals, nargs, (frame[3] & 0x10) ? 0xff + 1 : frame[4]);
932 for(int i = 0; i < nlocals; i++)
936 if(!zterp_io_read16(savefile, &l)) goto_death("unexpected eof reading local variable");
937 CURRENT_FRAME->locals[i] = l;
942 for(uint16_t i = 0; i < nstack; i++)
946 if(!zterp_io_read16(savefile, &s)) goto_death("unexpected eof reading stack entry");
953 if(n != size) goto_death("stack size mismatch");
956 memory_snapshot_free();
958 pc = (ifhd[10] << 16) | (ifhd[11] << 8) | ifhd[12];
963 /* At this point, something vital (memory and/or the stacks) has been
964 * scribbed upon; if there was a successful backup, restore it.
965 * Otherwise the only course of action is to exit.
967 if(!memory_restore()) die("the system is likely in an inconsistent state");
970 /* A snapshot may have been taken, but neither memory nor the stacks
971 * have been overwritten, so just free the snapshot.
973 memory_snapshot_free();
981 /* Perform all aspects of a save, apart from storing/branching.
982 * Returns true if the save was success, false if not.
983 * “is_meta” is true if this save file is from a meta-save.
985 int do_save(int is_meta)
990 savefile = zterp_io_open(NULL, ZTERP_IO_WRONLY | ZTERP_IO_SAVE);
993 warning("unable to open save file");
997 success = save_quetzal(savefile, is_meta);
999 zterp_io_close(savefile);
1004 /* The suggested filename is ignored, because Glk and, at least as of
1005 * right now, zterp_io_open(), do not provide a method to do this.
1006 * The “prompt” argument added by standard 1.1 is thus also ignored.
1010 if(interrupt_level() != 0) die("@save called inside of an interrupt");
1012 int success = do_save(0);
1014 if(zversion <= 3) branch_if(success);
1015 else store(success);
1018 /* Perform all aspects of a restore, apart from storing/branching.
1019 * Returns true if the restore was success, false if not.
1020 * “is_meta” is true if this save file is expected to be from a
1023 int do_restore(int is_meta)
1029 savefile = zterp_io_open(NULL, ZTERP_IO_RDONLY | ZTERP_IO_SAVE);
1030 if(savefile == NULL)
1032 warning("unable to open save file");
1036 flags2 = WORD(0x10);
1038 success = restore_quetzal(savefile, is_meta);
1040 zterp_io_close(savefile);
1044 /* On a successful restore, we are outside of any interrupt (since
1045 * @save cannot be called inside an interrupt), so reset the level
1046 * back to zero. In addition, there may be pending read events that
1047 * need to be canceled, so do that, too.
1050 cancel_all_events();
1053 if(zversion == 3) close_upper_window();
1055 /* The save might be from a different interpreter with different
1056 * capabilities, so update the header to indicate what the current
1057 * capabilities are...
1061 /* ...except that flags2 should be preserved (§6.1.2). */
1062 STORE_WORD(0x10, flags2);
1064 /* Redraw the status line in games that use one. */
1065 if(zversion <= 3) zshow_status();
1073 int success = do_restore(0);
1075 if(zversion <= 3) branch_if(success);
1076 else store(success ? 2 : 0);