void iffputchunk(strid_t stream, const char *type, glui32 ulength) { glui32 c; unsigned char length[4]; c = glk_stream_get_position(stream); if(c & 1) glk_put_char_stream(stream, 0); /* Spew padding */ MSBencode4(length, ulength); w_glk_put_buffer_stream(stream, type, 4); w_glk_put_buffer_stream(stream, (char *) length, 4); }
glui32 emptystruct(strid_t stream, const unsigned *info, const glui32 *src) { unsigned char buffer[4]; unsigned e; glui32 len = 0;; for(e = 0; info[e]; e++) { if(info[e] > 4) { unsigned i; for(i = 0; i < info[e]; i++) { glk_put_char_stream(stream, *src++); len++; } } else { switch(info[e]) { case 1: MSBencode1(buffer, *src); break; case 2: MSBencode2(buffer, *src); break; case 3: MSBencode3(buffer, *src); break; case 4: MSBencode4(buffer, *src); break; } w_glk_put_buffer_stream(stream, (char *) buffer, info[e]); src++; len++; } } return len; }
void op_save5(void) { unsigned i; char filename[256]; unsigned length; strid_t file = NULL; offset end; switch(numoperands) { case 0: op_save4(); return; case 1: n_show_error(E_INSTR, "call save with bad number of operands", numoperands); mop_store_result(0); return; case 2: file = n_file_prompt(fileusage_Data | fileusage_BinaryMode, filemode_Write); break; default: length = LOBYTE(operand[2]); if(length > 13) n_show_port(E_INSTR, "save with filename > 13 characters", length); for(i = 0; i < length; i++) filename[i] = glk_char_to_upper(LOBYTE(operand[2] + 1 + i)); filename[length] = 0; file = n_file_name(fileusage_Data | fileusage_BinaryMode, filemode_Write, filename); break; } if(!file) { mop_store_result(0); return; } end = ((offset) operand[0]) + operand[1]; if(end > 65535 || end > total_size) { n_show_error(E_MEMORY, "attempt to save data out of range", end); mop_store_result(0); return; } w_glk_put_buffer_stream(file, (char *) z_memory + operand[0], operand[1]); glk_stream_close(file, NULL); mop_store_result(1); }
BOOL quetzal_stack_save(strid_t stream) { unsigned frame_num = 0; if(zversion == 6) frame_num++; if(!verify_stack()) { n_show_error(E_SAVE, "stack did not pass verification before saving", 0); return FALSE; } /* We have to look one ahead to see how much stack space a frame uses; when we get to the last frame, there will be no next frame, so this won't work if there wasn't a frame there earlier with the correct info. Add and remove a frame to make things happy */ add_stack_frame(0, 0, NULL, 0, 0); remove_stack_frame(); for(; frame_num <= frame_count; frame_num++) { unsigned n; int num_locals; unsigned stack_size; glui32 qframe[5]; const unsigned char argarray[8] = { b00000000, b00000001, b00000011, b00000111, b00001111, b00011111, b00111111, b01111111 }; qframe[qreturnPC] = stack_frames[frame_num].return_PC; qframe[qvar] = stack_frames[frame_num].result_variable; num_locals = stack_frames[frame_num].num_locals; if(num_locals > 15) { n_show_error(E_SAVE, "num_locals too big", num_locals); return FALSE; } qframe[qflags] = num_locals; if(stack_frames[frame_num].result_variable == -1) { qframe[qflags] |= b00010000; qframe[qvar] = 0; } if(stack_frames[frame_num].arguments > 7) { n_show_error(E_SAVE, "too many function arguments", stack_frames[frame_num].arguments); return FALSE; } qframe[qargs] = argarray[stack_frames[frame_num].arguments]; stack_size = (stack_frames[frame_num+1].stack_stack_start - stack_frames[frame_num].stack_stack_start - num_locals); qframe[qeval] = stack_size; if(frame_num == 0) { qframe[qreturnPC] = 0; qframe[qflags] = 0; qframe[qvar] = 0; qframe[qargs] = 0; } emptystruct(stream, qstackframe, qframe); for(n = 0; n < num_locals + stack_size; n++) { unsigned char v[ZWORD_SIZE]; zword z = stack_stack[stack_frames[frame_num].stack_stack_start + n]; MSBencodeZ(v, z); w_glk_put_buffer_stream(stream, (char *) v, ZWORD_SIZE); } } return TRUE; }