scummvm/engines/glk/frotz/processor_buffer.cpp
2019-07-21 11:31:33 -07:00

192 lines
4.8 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "glk/frotz/processor.h"
#include "common/algorithm.h"
#include "common/textconsole.h"
namespace Glk {
namespace Frotz {
const char *const Processor::ERR_MESSAGES[ERR_NUM_ERRORS] = {
"Text buffer overflow",
"Store out of dynamic memory",
"Division by zero",
"Illegal object",
"Illegal attribute",
"No such property",
"Stack overflow",
"Call to illegal address",
"Call to non-routine",
"Stack underflow",
"Illegal opcode",
"Bad stack frame",
"Jump to illegal address",
"Can't save while in interrupt",
"Nesting stream #3 too deep",
"Illegal window",
"Illegal window property",
"Print at illegal address",
"Illegal dictionary word length",
"@jin called with object 0",
"@get_child called with object 0",
"@get_parent called with object 0",
"@get_sibling called with object 0",
"@get_prop_addr called with object 0",
"@get_prop called with object 0",
"@put_prop called with object 0",
"@clear_attr called with object 0",
"@set_attr called with object 0",
"@test_attr called with object 0",
"@move_object called moving object 0",
"@move_object called moving into object 0",
"@remove_object called with object 0",
"@get_next_prop called with object 0"
};
void Processor::flush_buffer() {
/* Make sure we stop when flush_buffer is called from flush_buffer.
* Note that this is difficult to avoid as we might print a newline
* during flush_buffer, which might cause a newline interrupt, that
* might execute any arbitrary opcode, which might flush the buffer.
*/
if (_locked || bufferEmpty())
return;
// Send the buffer to the output streams
_buffer[_bufPos] = '\0';
_locked = true;
stream_word(_buffer);
_locked = false;
// Reset the buffer
_bufPos = 0;
_prevC = '\0';
}
void Processor::print_char(zchar c) {
static bool flag = false;
if (message || ostream_memory || enable_buffering) {
if (!flag) {
// Characters 0 and ZC_RETURN are special cases
if (c == ZC_RETURN) {
new_line();
return;
}
if (c == 0)
return;
// Flush the buffer before a whitespace or after a hyphen
if (c == ' ' || c == ZC_INDENT || c == ZC_GAP || (_prevC == '-' && c != '-'))
flush_buffer();
// Set the flag if this is part one of a style or font change
if (c == ZC_NEW_FONT || c == ZC_NEW_STYLE)
flag = true;
// Remember the current character code
_prevC = c;
} else {
flag = false;
}
// Insert the character into the buffer
_buffer[_bufPos++] = c;
if (_bufPos == TEXT_BUFFER_SIZE)
error("Text buffer overflow");
} else {
stream_char(c);
}
}
void Processor::print_string(const char *s) {
char c;
while ((c = *s++) != 0) {
if (c == '\n')
new_line();
else
print_char(c);
}
}
void Processor::print_long(uint value, int base) {
unsigned long i;
char c;
for (i = (base == 10 ? 1000000000 : 0x10000000); i != 0; i /= base) {
if (value >= i || i == 1) {
c = (value / i) % base;
print_char(c + (c <= 9 ? '0' : 'a' - 10));
}
}
}
void Processor::new_line() {
flush_buffer();
stream_new_line();
}
void Processor::runtimeError(ErrorCode errNum) {
int wasfirst;
if (errNum <= 0 || errNum > ERR_NUM_ERRORS)
return;
if (_err_report_mode == ERR_REPORT_FATAL
|| (!_ignore_errors && errNum <= ERR_MAX_FATAL)) {
flush_buffer();
error("%s", ERR_MESSAGES[errNum - 1]);
return;
}
wasfirst = (_errorCount[errNum - 1] == 0);
_errorCount[errNum - 1]++;
if ((_err_report_mode == ERR_REPORT_ALWAYS)
|| (_err_report_mode == ERR_REPORT_ONCE && wasfirst)) {
offset_t pc;
GET_PC(pc);
print_string("Warning: ");
print_string(ERR_MESSAGES[errNum - 1]);
print_string(" (PC = ");
print_long(pc, 16);
print_char(')');
if (_err_report_mode == ERR_REPORT_ONCE) {
print_string(" (will ignore further occurrences)");
} else {
print_string(" (occurence ");
print_long(_errorCount[errNum - 1], 10);
print_char(')');
}
new_line();
}
}
} // End of namespace Frotz
} // End of namespace Glk