1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "glk/frotz/processor.h"
24 
25 namespace Glk {
26 namespace Frotz {
27 
flagsChanged(zbyte value)28 void Processor::flagsChanged(zbyte value) {
29 	if (value & SCRIPTING_FLAG) {
30 		if (!ostream_script)
31 			script_open();
32 	} else {
33 		if (ostream_script)
34 			script_close();
35 	}
36 }
37 
save_undo()38 int Processor::save_undo() {
39 	long diff_size;
40 	zword stack_size;
41 	undo_t *p;
42 
43 	if (_undo_slots == 0)
44 		// undo feature unavailable
45 		return -1;
46 
47 	// save undo possible
48 	while (last_undo != curr_undo) {
49 		p = last_undo;
50 		last_undo = last_undo->prev;
51 		delete p;
52 		undo_count--;
53 	}
54 	if (last_undo)
55 		last_undo->next = nullptr;
56 	else
57 		first_undo = nullptr;
58 
59 	if (undo_count == _undo_slots)
60 		free_undo(1);
61 
62 	diff_size = mem_diff(zmp, prev_zmp, h_dynamic_size, undo_diff);
63 	stack_size = _stack + STACK_SIZE - _sp;
64 	do {
65 		p = (undo_t *) malloc(sizeof(undo_t) + diff_size + stack_size * sizeof(*_sp));
66 		if (p == nullptr)
67 			free_undo(1);
68 	} while (!p && undo_count);
69 	if (p == nullptr)
70 		return -1;
71 
72 	GET_PC(p->pc);
73 	p->frame_count = _frameCount;
74 	p->diff_size = diff_size;
75 	p->stack_size = stack_size;
76 	p->frame_offset = _fp - _stack;
77 	memcpy(p + 1, undo_diff, diff_size);
78 	memcpy((zbyte *)(p + 1) + diff_size, _sp, stack_size * sizeof(*_sp));
79 
80 	if (!first_undo) {
81 		p->prev = nullptr;
82 		first_undo = p;
83 	} else {
84 		last_undo->next = p;
85 		p->prev = last_undo;
86 	}
87 
88 	p->next = nullptr;
89 	curr_undo = last_undo = p;
90 	undo_count++;
91 
92 	return 1;
93 }
94 
restore_undo(void)95 int Processor::restore_undo(void) {
96 	if (_undo_slots == 0)
97 		// undo feature unavailable
98 		return -1;
99 
100 	if (curr_undo == nullptr)
101 		// no saved game state
102 		return 0;
103 
104 	// undo possible
105 	memcpy(zmp, prev_zmp, h_dynamic_size);
106 	SET_PC(curr_undo->pc);
107 	_sp = _stack + STACK_SIZE - curr_undo->stack_size;
108 	_fp = _stack + curr_undo->frame_offset;
109 	_frameCount = curr_undo->frame_count;
110 	mem_undiff((zbyte *)(curr_undo + 1), curr_undo->diff_size, prev_zmp);
111 	memcpy(_sp, (zbyte *)(curr_undo + 1) + curr_undo->diff_size,
112 		curr_undo->stack_size * sizeof(*_sp));
113 
114 	curr_undo = curr_undo->prev;
115 
116 	restart_header();
117 
118 	return 2;
119 }
120 
121 /**
122  * TOR: glkify -- this is for V6 only
123  */
get_max_width(zword win)124 static zword get_max_width(zword win) { return 80; }
125 
memory_open(zword table,zword xsize,bool buffering)126 void Processor::memory_open(zword table, zword xsize, bool buffering) {
127 	if (_redirect.size() < MAX_NESTING) {
128 		if (!buffering)
129 			xsize = 0xffff;
130 		if (buffering && (short)xsize <= 0)
131 			xsize = get_max_width((zword)(-(short)xsize));
132 
133 		storew(table, 0);
134 
135 		_redirect.push(Redirect(xsize, table));
136 		ostream_memory = true;
137 	} else {
138 		runtimeError(ERR_STR3_NESTING);
139 	}
140 }
141 
memory_new_line()142 void Processor::memory_new_line() {
143 	zword size;
144 	zword addr;
145 
146 	Redirect &r = _redirect.top();
147 	r._total += r._width;
148 	r._width = 0;
149 
150 	addr = r._table;
151 
152 	LOW_WORD(addr, size);
153 	addr += 2;
154 
155 	if (r._xSize != 0xffff) {
156 		r._table = addr + size;
157 		size = 0;
158 	} else {
159 		storeb((zword)(addr + (size++)), 13);
160 	}
161 
162 	storew(r._table, size);
163 }
164 
memory_word(const zchar * s)165 void Processor::memory_word(const zchar *s) {
166 	zword size;
167 	zword addr;
168 	zchar c;
169 
170 	Redirect &r = _redirect.top();
171 	if (h_version == V6) {
172 		int width = os_string_width(s);
173 
174 		if (r._xSize != 0xffff) {
175 			if (r._width + width > r._xSize) {
176 
177 				if (*s == ' ' || *s == ZC_INDENT || *s == ZC_GAP)
178 					width = os_string_width(++s);
179 
180 				memory_new_line();
181 			}
182 		}
183 
184 		r._width += width;
185 	}
186 
187 	addr = r._table;
188 
189 	LOW_WORD(addr, size);
190 	addr += 2;
191 
192 	while ((c = *s++) != 0)
193 		storeb((zword)(addr + (size++)), translate_to_zscii(c));
194 
195 	storew(r._table, size);
196 }
197 
memory_close(void)198 void Processor::memory_close(void) {
199 	if (!_redirect.empty()) {
200 		Redirect &r = _redirect.top();
201 
202 		if (r._xSize != 0xffff)
203 			memory_new_line();
204 
205 		if (h_version == V6) {
206 			h_line_width = (r._xSize != 0xffff) ? r._total : r._width;
207 
208 			SET_WORD(H_LINE_WIDTH, h_line_width);
209 		}
210 
211 		_redirect.pop();
212 		if (_redirect.empty())
213 			ostream_memory = false;
214 	}
215 }
216 
217 } // End of namespace Frotz
218 } // End of namespace Glk
219