Moved some more console commands to ScummVM's debug console

svn-id: r41127
This commit is contained in:
Filippos Karapetis 2009-06-02 21:07:34 +00:00
parent 780926991e
commit ac544e73e9
4 changed files with 422 additions and 345 deletions

View file

@ -32,6 +32,7 @@
#include "sci/engine/savegame.h"
#include "sci/engine/state.h"
#include "sci/engine/gc.h"
#include "sci/engine/kernel_types.h" // for determine_reg_type
#include "sci/gfx/gfx_gui.h" // for sciw_set_status_bar
#include "sci/gfx/gfx_state_internal.h"
#include "sci/gfx/gfx_widgets.h" // for getPort
@ -51,6 +52,190 @@ int _kdebug_cheap_event_hack = 0;
bool _kdebug_track_mouse_clicks = false;
int _weak_validations = 1; // Some validation errors are reduced to warnings if non-0
int parse_reg_t(EngineState *s, const char *str, reg_t *dest) { // Returns 0 on success
int rel_offsetting = 0;
const char *offsetting = NULL;
// Non-NULL: Parse end of string for relative offsets
char *endptr;
if (*str == '$') { // Register
rel_offsetting = 1;
if (!scumm_strnicmp(str + 1, "PC", 2)) {
*dest = s->_executionStack.back().addr.pc;
offsetting = str + 3;
} else if (!scumm_strnicmp(str + 1, "P", 1)) {
*dest = s->_executionStack.back().addr.pc;
offsetting = str + 2;
} else if (!scumm_strnicmp(str + 1, "PREV", 4)) {
*dest = s->r_prev;
offsetting = str + 5;
} else if (!scumm_strnicmp(str + 1, "ACC", 3)) {
*dest = s->r_acc;
offsetting = str + 4;
} else if (!scumm_strnicmp(str + 1, "A", 1)) {
*dest = s->r_acc;
offsetting = str + 2;
} else if (!scumm_strnicmp(str + 1, "OBJ", 3)) {
*dest = s->_executionStack.back().objp;
offsetting = str + 4;
} else if (!scumm_strnicmp(str + 1, "O", 1)) {
*dest = s->_executionStack.back().objp;
offsetting = str + 2;
} else
return 1; // No matching register
if (!*offsetting)
offsetting = NULL;
else if (*offsetting != '+' && *offsetting != '-')
return 1;
} else if (*str == '&') {
int script_nr;
// Look up by script ID
char *colon = (char *)strchr(str, ':');
if (!colon)
return 1;
*colon = 0;
offsetting = colon + 1;
script_nr = strtol(str + 1, &endptr, 10);
if (*endptr)
return 1;
dest->segment = s->seg_manager->segGet(script_nr);
if (!dest->segment) {
return 1;
}
} else if (*str == '?') {
int index = -1;
int times_found = 0;
char *tmp;
const char *str_objname;
char *str_suffix;
char suffchar = 0;
uint i;
// Parse obj by name
tmp = (char *)strchr(str, '+');
str_suffix = (char *)strchr(str, '-');
if (tmp < str_suffix)
str_suffix = tmp;
if (str_suffix) {
suffchar = (*str_suffix);
*str_suffix = 0;
}
tmp = (char *)strchr(str, '.');
if (tmp) {
*tmp = 0;
index = strtol(tmp + 1, &endptr, 16);
if (*endptr)
return -1;
}
str_objname = str + 1;
// Now all values are available; iterate over all objects.
for (i = 0; i < s->seg_manager->_heap.size(); i++) {
MemObject *mobj = s->seg_manager->_heap[i];
int idx = 0;
int max_index = 0;
if (mobj) {
if (mobj->getType() == MEM_OBJ_SCRIPT)
max_index = (*(Script *)mobj)._objects.size();
else if (mobj->getType() == MEM_OBJ_CLONES)
max_index = (*(CloneTable *)mobj)._table.size();
}
while (idx < max_index) {
int valid = 1;
Object *obj = NULL;
reg_t objpos;
objpos.offset = 0;
objpos.segment = i;
if (mobj->getType() == MEM_OBJ_SCRIPT) {
obj = &(*(Script *)mobj)._objects[idx];
objpos.offset = obj->pos.offset;
} else if (mobj->getType() == MEM_OBJ_CLONES) {
obj = &((*(CloneTable *)mobj)._table[idx]);
objpos.offset = idx;
valid = ((CloneTable *)mobj)->isValidEntry(idx);
}
if (valid) {
const char *objname = obj_get_name(s, objpos);
if (!strcmp(objname, str_objname)) {
// Found a match!
if ((index < 0) && (times_found > 0)) {
if (times_found == 1) {
// First time we realized the ambiguity
printf("Ambiguous:\n");
printf(" %3x: [%04x:%04x] %s\n", 0, PRINT_REG(*dest), str_objname);
}
printf(" %3x: [%04x:%04x] %s\n", times_found, PRINT_REG(objpos), str_objname);
}
if (index < 0 || times_found == index)
*dest = objpos;
++times_found;
}
}
++idx;
}
}
if (!times_found)
return 1;
if (times_found > 1 && index < 0) {
printf("Ambiguous: Aborting.\n");
return 1; // Ambiguous
}
if (times_found <= index)
return 1; // Not found
offsetting = str_suffix;
if (offsetting)
*str_suffix = suffchar;
rel_offsetting = 1;
} else {
char *colon = (char *)strchr(str, ':');
if (!colon) {
offsetting = str;
dest->segment = 0;
} else {
*colon = 0;
offsetting = colon + 1;
dest->segment = strtol(str, &endptr, 16);
if (*endptr)
return 1;
}
}
if (offsetting) {
int val = strtol(offsetting, &endptr, 16);
if (rel_offsetting)
dest->offset += val;
else
dest->offset = val;
if (*endptr)
return 1;
}
return 0;
}
Console::Console(SciEngine *vm) : GUI::Debugger() {
_vm = vm;
@ -60,7 +245,6 @@ Console::Console(SciEngine *vm) : GUI::Debugger() {
DCmd_Register("selectors", WRAP_METHOD(Console, cmdSelectors));
DCmd_Register("kernel_names", WRAP_METHOD(Console, cmdKernelNames));
DCmd_Register("registers", WRAP_METHOD(Console, cmdRegisters));
DCmd_Register("dissect_script", WRAP_METHOD(Console, cmdDissectScript));
DCmd_Register("weak_validations", WRAP_METHOD(Console, cmdWeakValidations));
// Parser
DCmd_Register("suffixes", WRAP_METHOD(Console, cmdSuffixes));
@ -113,17 +297,26 @@ Console::Console(SciEngine *vm) : GUI::Debugger() {
DCmd_Register("gc", WRAP_METHOD(Console, cmdGCInvoke));
DCmd_Register("gc_objects", WRAP_METHOD(Console, cmdGCObjects));
DCmd_Register("gc_interval", WRAP_METHOD(Console, cmdGCInterval));
// VM
DCmd_Register("vm_varlist", WRAP_METHOD(Console, cmdVMVarlist));
DCmd_Register("stack", WRAP_METHOD(Console, cmdStack));
DCmd_Register("sleep_factor", WRAP_METHOD(Console, cmdSleepFactor));
DCmd_Register("script_steps", WRAP_METHOD(Console, cmdScriptSteps));
DCmd_Register("exit", WRAP_METHOD(Console, cmdExit));
DCmd_Register("gc_reachable", WRAP_METHOD(Console, cmdGCShowReachable));
DCmd_Register("gc_freeable", WRAP_METHOD(Console, cmdGCShowFreeable));
DCmd_Register("gc_normalize", WRAP_METHOD(Console, cmdGCNormalize));
// Music/SFX
DCmd_Register("songlib", WRAP_METHOD(Console, cmdSongLib));
DCmd_Register("is_sample", WRAP_METHOD(Console, cmdIsSample));
DCmd_Register("sfx01_header", WRAP_METHOD(Console, cmdSfx01Header));
DCmd_Register("sfx01_track", WRAP_METHOD(Console, cmdSfx01Track));
DCmd_Register("stop_sfx", WRAP_METHOD(Console, cmdStopSfx));
// Script
DCmd_Register("addresses", WRAP_METHOD(Console, cmdAddresses));
DCmd_Register("dissect_script", WRAP_METHOD(Console, cmdDissectScript));
DCmd_Register("script_steps", WRAP_METHOD(Console, cmdScriptSteps));
DCmd_Register("set_acc", WRAP_METHOD(Console, cmdSetAccumulator));
// VM
DCmd_Register("vm_varlist", WRAP_METHOD(Console, cmdVMVarlist));
DCmd_Register("stack", WRAP_METHOD(Console, cmdStack));
DCmd_Register("value_type", WRAP_METHOD(Console, cmdValueType));
DCmd_Register("sleep_factor", WRAP_METHOD(Console, cmdSleepFactor));
DCmd_Register("exit", WRAP_METHOD(Console, cmdExit));
// These were in sci.cpp
/*
@ -219,16 +412,16 @@ bool Console::cmdRegisters(int argc, const char **argv) {
DebugPrintf("Current register values:\n");
#if 0
// TODO: p_restadjust
sciprintf("acc=%04x:%04x prev=%04x:%04x &rest=%x\n", PRINT_REG(g_EngineState->r_acc), PRINT_REG(g_EngineState->r_prev), *p_restadjust);
DebugPrintf("acc=%04x:%04x prev=%04x:%04x &rest=%x\n", PRINT_REG(g_EngineState->r_acc), PRINT_REG(g_EngineState->r_prev), *p_restadjust);
#endif
if (!g_EngineState->_executionStack.empty()) {
#if 0
// TODO: p_pc, p_objp, p_pp, p_sp
sciprintf("pc=%04x:%04x obj=%04x:%04x fp=ST:%04x sp=ST:%04x\n", PRINT_REG(*p_pc), PRINT_REG(*p_objp), PRINT_STK(*p_pp), PRINT_STK(*p_sp));
DebugPrintf("pc=%04x:%04x obj=%04x:%04x fp=ST:%04x sp=ST:%04x\n", PRINT_REG(*p_pc), PRINT_REG(*p_objp), PRINT_STK(*p_pp), PRINT_STK(*p_sp));
#endif
} else
sciprintf("<no execution stack: pc,obj,fp omitted>\n");
DebugPrintf("<no execution stack: pc,obj,fp omitted>\n");
return true;
}
@ -1324,6 +1517,99 @@ bool Console::cmdGCInterval(int argc, const char **argv) {
return true;
}
// TODO/FIXME: This should be using DebugPrintf
void _print_address(void * _, reg_t addr) {
if (addr.segment)
sciprintf(" %04x:%04x\n", PRINT_REG(addr));
}
bool Console::cmdGCShowReachable(int argc, const char **argv) {
if (argc != 2) {
DebugPrintf("Prints all addresses directly reachable from the memory object specified as parameter.\n");
DebugPrintf("Usage: %s <address>\n", argv[0]);
DebugPrintf("Check the \"addresses\" command on how to use addresses\n");
return true;
}
reg_t addr;
if (parse_reg_t(g_EngineState, argv[1], &addr)) {
DebugPrintf("Invalid address passed.\n");
DebugPrintf("Check the \"addresses\" command on how to use addresses\n");
return true;
}
MemObject *mobj = GET_SEGMENT_ANY(*g_EngineState->seg_manager, addr.segment);
if (!mobj) {
DebugPrintf("Unknown segment : %x\n", addr.segment);
return 1;
}
DebugPrintf("Reachable from %04x:%04x:\n", PRINT_REG(addr));
mobj->listAllOutgoingReferences(g_EngineState, addr, NULL, _print_address);
return true;
}
bool Console::cmdGCShowFreeable(int argc, const char **argv) {
if (argc != 2) {
DebugPrintf("Prints all addresses freeable in the segment associated with the\n");
DebugPrintf("given address (offset is ignored).\n");
DebugPrintf("Usage: %s <address>\n", argv[0]);
DebugPrintf("Check the \"addresses\" command on how to use addresses\n");
return true;
}
reg_t addr;
if (parse_reg_t(g_EngineState, argv[1], &addr)) {
DebugPrintf("Invalid address passed.\n");
DebugPrintf("Check the \"addresses\" command on how to use addresses\n");
return true;
}
MemObject *mobj = GET_SEGMENT_ANY(*g_EngineState->seg_manager, addr.segment);
if (!mobj) {
DebugPrintf("Unknown segment : %x\n", addr.segment);
return true;
}
DebugPrintf("Freeable in segment %04x:\n", addr.segment);
mobj->listAllDeallocatable(addr.segment, NULL, _print_address);
return true;
}
bool Console::cmdGCNormalize(int argc, const char **argv) {
if (argc != 2) {
DebugPrintf("Prints the \"normal\" address of a given address,\n");
DebugPrintf("i.e. the address we would free in order to free\n");
DebugPrintf("the object associated with the original address.\n");
DebugPrintf("Usage: %s <address>\n", argv[0]);
DebugPrintf("Check the \"addresses\" command on how to use addresses\n");
return true;
}
reg_t addr;
if (parse_reg_t(g_EngineState, argv[1], &addr)) {
DebugPrintf("Invalid address passed.\n");
DebugPrintf("Check the \"addresses\" command on how to use addresses\n");
return true;
}
MemObject *mobj = GET_SEGMENT_ANY(*g_EngineState->seg_manager, addr.segment);
if (!mobj) {
DebugPrintf("Unknown segment : %x\n", addr.segment);
return true;
}
addr = mobj->findCanonicAddress(g_EngineState->seg_manager, addr);
DebugPrintf(" %04x:%04x\n", PRINT_REG(addr));
return true;
}
bool Console::cmdVMVarlist(int argc, const char **argv) {
const char *varnames[] = {"global", "local", "temp", "param"};
@ -1368,6 +1654,52 @@ bool Console::cmdStack(int argc, const char **argv) {
return true;
}
bool Console::cmdValueType(int argc, const char **argv) {
if (argc != 2) {
DebugPrintf("Determines the type of a value.\n");
DebugPrintf("The type can be one of the following:\n");
DebugPrintf("Invalid, list, object, reference or arithmetic\n");
DebugPrintf("Usage: %s <address>\n", argv[0]);
DebugPrintf("Check the \"addresses\" command on how to use addresses\n");
return true;
}
reg_t val;
if (parse_reg_t(g_EngineState, argv[1], &val)) {
DebugPrintf("Invalid address passed.\n");
DebugPrintf("Check the \"addresses\" command on how to use addresses\n");
return true;
}
int t = determine_reg_type(g_EngineState, val, 1);
int invalid = t & KSIG_INVALID;
switch (t & ~KSIG_INVALID) {
case 0:
DebugPrintf("Invalid");
break;
case KSIG_LIST:
DebugPrintf("List");
break;
case KSIG_OBJECT:
DebugPrintf("Object");
break;
case KSIG_REF:
DebugPrintf("Reference");
break;
case KSIG_ARITHMETIC:
DebugPrintf("Arithmetic");
break;
default:
DebugPrintf("Erroneous unknown type %02x(%d decimal)\n", t, t);
}
DebugPrintf("%s\n", invalid ? " (invalid)" : "");
return true;
}
bool Console::cmdSleepFactor(int argc, const char **argv) {
if (argc != 2) {
DebugPrintf("Factor to multiply with wait times in kWait().\n");
@ -1388,6 +1720,27 @@ bool Console::cmdScriptSteps(int argc, const char **argv) {
return true;
}
bool Console::cmdSetAccumulator(int argc, const char **argv) {
if (argc != 2) {
DebugPrintf("Sets the accumulator.\n");
DebugPrintf("Usage: %s <address>\n", argv[0]);
DebugPrintf("Check the \"addresses\" command on how to use addresses\n");
return true;
}
reg_t val;
if (parse_reg_t(g_EngineState, argv[1], &val)) {
DebugPrintf("Invalid address passed.\n");
DebugPrintf("Check the \"addresses\" command on how to use addresses\n");
return true;
}
g_EngineState->r_acc = val;
return true;
}
bool Console::cmdIsSample(int argc, const char **argv) {
if (argc != 2) {
DebugPrintf("Tests whether a given sound resource is a PCM sample, \n");
@ -1613,6 +1966,37 @@ bool Console::cmdSfx01Track(int argc, const char **argv) {
return true;
}
bool Console::cmdStopSfx(int argc, const char **argv) {
if (argc != 2) {
DebugPrintf("Stops a playing sound\n");
DebugPrintf("Usage: %s <address>\n", argv[0]);
DebugPrintf("Where <address> is the address of the sound to stop.\n");
DebugPrintf("Check the \"addresses\" command on how to use addresses\n");
return true;
}
reg_t id;
if (parse_reg_t(g_EngineState, argv[1], &id)) {
DebugPrintf("Invalid address passed.\n");
DebugPrintf("Check the \"addresses\" command on how to use addresses\n");
return true;
}
int handle = id.segment << 16 | id.offset; // frobnicate handle
EngineState* s = g_EngineState; // for PUT_SEL32V
if (id.segment) {
g_EngineState->_sound.sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
g_EngineState->_sound.sfx_remove_song(handle);
PUT_SEL32V(id, signal, -1);
PUT_SEL32V(id, nodePtr, 0);
PUT_SEL32V(id, handle, 0);
}
return true;
}
bool Console::cmdExit(int argc, const char **argv) {
if (argc != 2) {
DebugPrintf("%s game - exit gracefully\n", argv[0]);
@ -1635,4 +2019,21 @@ bool Console::cmdExit(int argc, const char **argv) {
return false;
}
bool Console::cmdAddresses(int argc, const char **argv) {
DebugPrintf("Address parameters may be passed in one of three forms:\n");
DebugPrintf(" - ssss:oooo -- where 'ssss' denotes a segment and 'oooo' an offset.\n");
DebugPrintf(" Example: \"a:c5\" would address something in segment 0xa at offset 0xc5.\n");
DebugPrintf(" - &scr:oooo -- where 'scr' is a script number and oooo an offset within that script; will\n");
DebugPrintf(" fail if the script is not currently loaded\n");
DebugPrintf(" - $REG -- where 'REG' is one of 'PC', 'ACC', 'PREV' or 'OBJ': References the address\n");
DebugPrintf(" indicated by the register of this name.\n");
DebugPrintf(" - $REG+n (or -n) -- Like $REG, but modifies the offset part by a specific amount (which\n");
DebugPrintf(" is specified in hexadecimal).\n");
DebugPrintf(" - ?obj -- Looks up an object with the specified name, uses its address. This will abort if\n");
DebugPrintf(" the object name is ambiguous; in that case, a list of addresses and indices is provided.\n");
DebugPrintf(" ?obj.idx may be used to disambiguate 'obj' by the index 'idx'.\n");
return true;
}
} // End of namespace Sci

View file

@ -34,6 +34,9 @@ namespace Sci {
class SciEngine;
// Refer to the "addresses" command on how to pass address parameters
int parse_reg_t(EngineState *s, const char *str, reg_t *dest);
class Console : public GUI::Debugger {
public:
Console(SciEngine *vm);
@ -92,14 +95,21 @@ private:
bool cmdGCInvoke(int argc, const char **argv);
bool cmdGCObjects(int argc, const char **argv);
bool cmdGCInterval(int argc, const char **argv);
bool cmdGCShowReachable(int argc, const char **argv);
bool cmdGCShowFreeable(int argc, const char **argv);
bool cmdGCNormalize(int argc, const char **argv);
bool cmdVMVarlist(int argc, const char **argv);
bool cmdStack(int argc, const char **argv);
bool cmdValueType(int argc, const char **argv);
bool cmdSleepFactor(int argc, const char **argv);
bool cmdIsSample(int argc, const char **argv);
bool cmdSfx01Header(int argc, const char **argv);
bool cmdSfx01Track(int argc, const char **argv);
bool cmdScriptSteps(int argc, const char **argv);
bool cmdSetAccumulator(int argc, const char **argv);
bool cmdExit(int argc, const char **argv);
bool cmdAddresses(int argc, const char **argv);
bool cmdStopSfx(int argc, const char **argv);
bool segmentInfo(int nr);
void printList(List *l);

View file

@ -24,6 +24,7 @@
*/
#include "sci/sci.h"
#include "sci/console.h" // for parse_reg_t
#include "sci/resource.h"
#include "sci/engine/state.h"
#include "sci/engine/kernel.h"
@ -239,203 +240,6 @@ enum Movecnt {
static Movecnt handle_movecnt = UNINITIALIZED; // FIXME: Avoid non-const global vars
/**
* Address parameters may be passed in one of three forms:
* - ssss:oooo -- where 'ssss' denotes a segment and 'oooo' an offset.
* Example: "a:c5" would address something in segment 0xa at offset 0xc5.
* - &scr:oooo -- where 'scr' is a script number and oooo an offset within that script; will
* fail if the script is not currently loaded
* - $REG -- where 'REG' is one of 'PC', 'ACC', 'PREV' or 'OBJ': References the address
* indicated by the register of this name.
* - $REG+n (or -n) -- Like $REG, but modifies the offset part by a specific amount (which
* is specified in hexadecimal).
* - ?obj -- Looks up an object with the specified name, uses its address. This will abort if
* the object name is ambiguous; in that case, a list of addresses and indices is provided.
* ?obj.idx may be used to disambiguate 'obj' by the index 'idx'.
**/
int parse_reg_t(EngineState *s, const char *str, reg_t *dest) { // Returns 0 on success
int rel_offsetting = 0;
const char *offsetting = NULL;
// Non-NULL: Parse end of string for relative offsets
char *endptr;
if (*str == '$') { // Register
rel_offsetting = 1;
if (!scumm_strnicmp(str + 1, "PC", 2)) {
*dest = s->_executionStack.back().addr.pc;
offsetting = str + 3;
} else if (!scumm_strnicmp(str + 1, "P", 1)) {
*dest = s->_executionStack.back().addr.pc;
offsetting = str + 2;
} else if (!scumm_strnicmp(str + 1, "PREV", 4)) {
*dest = s->r_prev;
offsetting = str + 5;
} else if (!scumm_strnicmp(str + 1, "ACC", 3)) {
*dest = s->r_acc;
offsetting = str + 4;
} else if (!scumm_strnicmp(str + 1, "A", 1)) {
*dest = s->r_acc;
offsetting = str + 2;
} else if (!scumm_strnicmp(str + 1, "OBJ", 3)) {
*dest = s->_executionStack.back().objp;
offsetting = str + 4;
} else if (!scumm_strnicmp(str + 1, "O", 1)) {
*dest = s->_executionStack.back().objp;
offsetting = str + 2;
} else
return 1; // No matching register
if (!*offsetting)
offsetting = NULL;
else if (*offsetting != '+' && *offsetting != '-')
return 1;
} else if (*str == '&') {
int script_nr;
// Look up by script ID
char *colon = (char *)strchr(str, ':');
if (!colon)
return 1;
*colon = 0;
offsetting = colon + 1;
script_nr = strtol(str + 1, &endptr, 10);
if (*endptr)
return 1;
dest->segment = s->seg_manager->segGet(script_nr);
if (!dest->segment) {
return 1;
}
} else if (*str == '?') {
int index = -1;
int times_found = 0;
char *tmp;
const char *str_objname;
char *str_suffix;
char suffchar = 0;
uint i;
// Parse obj by name
tmp = (char *)strchr(str, '+');
str_suffix = (char *)strchr(str, '-');
if (tmp < str_suffix)
str_suffix = tmp;
if (str_suffix) {
suffchar = (*str_suffix);
*str_suffix = 0;
}
tmp = (char *)strchr(str, '.');
if (tmp) {
*tmp = 0;
index = strtol(tmp + 1, &endptr, 16);
if (*endptr)
return -1;
}
str_objname = str + 1;
// Now all values are available; iterate over all objects.
for (i = 0; i < s->seg_manager->_heap.size(); i++) {
MemObject *mobj = s->seg_manager->_heap[i];
int idx = 0;
int max_index = 0;
if (mobj) {
if (mobj->getType() == MEM_OBJ_SCRIPT)
max_index = (*(Script *)mobj)._objects.size();
else if (mobj->getType() == MEM_OBJ_CLONES)
max_index = (*(CloneTable *)mobj)._table.size();
}
while (idx < max_index) {
int valid = 1;
Object *obj = NULL;
reg_t objpos;
objpos.offset = 0;
objpos.segment = i;
if (mobj->getType() == MEM_OBJ_SCRIPT) {
obj = &(*(Script *)mobj)._objects[idx];
objpos.offset = obj->pos.offset;
} else if (mobj->getType() == MEM_OBJ_CLONES) {
obj = &((*(CloneTable *)mobj)._table[idx]);
objpos.offset = idx;
valid = ((CloneTable *)mobj)->isValidEntry(idx);
}
if (valid) {
const char *objname = obj_get_name(s, objpos);
if (!strcmp(objname, str_objname)) {
// Found a match!
if ((index < 0) && (times_found > 0)) {
if (times_found == 1) {
// First time we realized the ambiguity
sciprintf("Ambiguous:\n");
sciprintf(" %3x: [%04x:%04x] %s\n", 0, PRINT_REG(*dest), str_objname);
}
sciprintf(" %3x: [%04x:%04x] %s\n", times_found, PRINT_REG(objpos), str_objname);
}
if (index < 0 || times_found == index)
*dest = objpos;
++times_found;
}
}
++idx;
}
}
if (!times_found)
return 1;
if (times_found > 1 && index < 0) {
sciprintf("Ambiguous: Aborting.\n");
return 1; // Ambiguous
}
if (times_found <= index)
return 1; // Not found
offsetting = str_suffix;
if (offsetting)
*str_suffix = suffchar;
rel_offsetting = 1;
} else {
char *colon = (char *)strchr(str, ':');
if (!colon) {
offsetting = str;
dest->segment = 0;
} else {
*colon = 0;
offsetting = colon + 1;
dest->segment = strtol(str, &endptr, 16);
if (*endptr)
return 1;
}
}
if (offsetting) {
int val = strtol(offsetting, &endptr, 16);
if (rel_offsetting)
dest->offset += val;
else
dest->offset = val;
if (*endptr)
return 1;
}
return 0;
}
static int checksum_bytes(byte *data, int size) {
int result = 0;
int i;

View file

@ -1069,11 +1069,6 @@ static int c_go(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
return 0;
}
static int c_set_acc(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
s->r_acc = cmdParams[0].reg;
return 0;
}
static int c_send(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
reg_t object = cmdParams[0].reg;
const char *selector_name = cmdParams[1].str;
@ -1131,30 +1126,6 @@ static int c_send(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
}
struct generic_config_flag_t {
const char *name;
const char option;
unsigned int flag;
};
#define SFX_DEBUG_MODES 2
#define FROBNICATE_HANDLE(reg) ((reg).segment << 16 | (reg).offset)
static int c_sfx_remove(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
reg_t id = cmdParams[0].reg;
int handle = FROBNICATE_HANDLE(id);
if (id.segment) {
s->_sound.sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
s->_sound.sfx_remove_song(handle);
PUT_SEL32V(id, signal, -1);
PUT_SEL32V(id, nodePtr, 0);
PUT_SEL32V(id, handle, 0);
}
return 0;
}
#define GETRECT(ll, rr, tt, bb) \
ll = GET_SELECTOR(pos, ll); \
rr = GET_SELECTOR(pos, rr); \
@ -1427,90 +1398,6 @@ int c_se(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
return 0;
}
int c_type(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
int t = determine_reg_type(s, cmdParams[0].reg, 1);
int invalid = t & KSIG_INVALID;
switch (t & ~KSIG_INVALID) {
case 0:
sciprintf("Invalid");
break;
case KSIG_LIST:
sciprintf("List");
break;
case KSIG_OBJECT:
sciprintf("Object");
break;
case KSIG_REF:
sciprintf("Reference");
break;
case KSIG_ARITHMETIC:
sciprintf("Arithmetic");
break;
default:
sciprintf("Erroneous unknown type %02x(%d decimal)\n", t, t);
}
sciprintf("%s\n", invalid ? " (invalid)" : "");
return 0;
}
static void _print_address(void * _, reg_t addr) {
if (addr.segment)
sciprintf(" %04x:%04x\n", PRINT_REG(addr));
}
static int c_gc_show_reachable(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
reg_t addr = cmdParams[0].reg;
MemObject *mobj = GET_SEGMENT_ANY(*s->seg_manager, addr.segment);
if (!mobj) {
sciprintf("Unknown segment : %x\n", addr.segment);
return 1;
}
sciprintf("Reachable from %04x:%04x:\n", PRINT_REG(addr));
mobj->listAllOutgoingReferences(s, addr, NULL, _print_address);
return 0;
}
static int c_gc_show_freeable(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
reg_t addr = cmdParams[0].reg;
MemObject *mobj = GET_SEGMENT_ANY(*s->seg_manager, addr.segment);
if (!mobj) {
sciprintf("Unknown segment : %x\n", addr.segment);
return 1;
}
sciprintf("Freeable in segment %04x:\n", addr.segment);
mobj->listAllDeallocatable(addr.segment, NULL, _print_address);
return 0;
}
static int c_gc_normalise(EngineState *s, const Common::Array<cmd_param_t> &cmdParams) {
reg_t addr = cmdParams[0].reg;
MemObject *mobj = GET_SEGMENT_ANY(*s->seg_manager, addr.segment);
if (!mobj) {
sciprintf("Unknown segment : %x\n", addr.segment);
return 1;
}
addr = mobj->findCanonicAddress(s->seg_manager, addr);
sciprintf(" %04x:%04x\n", PRINT_REG(addr));
return 0;
}
void script_debug(EngineState *s, reg_t *pc, StackPtr *sp, StackPtr *pp, reg_t *objp, int *restadjust,
SegmentId *segids, reg_t **variables, reg_t **variables_base, int *variables_nr, int bp) {
// Do we support a separate console?
@ -1608,7 +1495,6 @@ void script_debug(EngineState *s, reg_t *pc, StackPtr *sp, StackPtr *pp, reg_t *
if (_debug_commands_not_hooked) {
_debug_commands_not_hooked = 0;
con_hook_command(c_sfx_remove, "sfx_remove", "!a", "Kills a playing sound.");
con_hook_command(c_vmvars, "vmvars", "!sia*", "Displays or changes variables in the VM\n\nFirst parameter is either g(lobal), l(ocal), t(emp) or p(aram).\nSecond parameter is the var number\nThird parameter (if specified) is the value to set the variable to");
con_hook_command(c_step, "s", "i*", "Executes one or several operations\n\nEXAMPLES\n\n"
" s 4\n\n Execute 4 commands\n\n s\n\n Execute next command");
@ -1631,7 +1517,6 @@ void script_debug(EngineState *s, reg_t *pc, StackPtr *sp, StackPtr *pp, reg_t *
con_hook_command(c_snk, "snk", "s*", "Steps forward until it hits the next\n callk operation.\n"
" If invoked with a parameter, it will\n look for that specific callk.\n");
con_hook_command(c_se, "se", "", "Steps forward until an SCI event is received.\n");
con_hook_command(c_set_acc, "set_acc", "!a", "Sets the accumulator");
con_hook_command(c_send, "send", "!asa*", "Sends a message to an object\nExample: send ?fooScript cue");
con_hook_command(c_sret, "sret", "", "Steps forward until ret is called\n on the current execution stack\n level.");
con_hook_command(c_bpx, "bpx", "s", "Sets a breakpoint on the execution of\n the specified method.\n\n EXAMPLE:\n"
@ -1666,32 +1551,9 @@ void script_debug(EngineState *s, reg_t *pc, StackPtr *sp, StackPtr *pp, reg_t *
"Steps until the global variable with the\n"
"specified index is modified.\n\nSEE ALSO\n\n"
" s.1, snk.1, so.1, bpx.1");
con_hook_command(c_type, "type", "!a",
"Determines the type of a value\n\n"
"SEE ALSO\n\n addresses.3, vo.1");
con_hook_command(c_shownode, "shownode", "!a",
"Prints information about a list node\n"
" or list base.\n\n");
con_hook_command(c_gc_show_reachable, "gc-list-reachable", "!a",
"Prints all addresses directly reachable from\n"
" the memory object specified as parameter.\n\n"
"SEE ALSO\n\n"
" gc-list-freeable.1, gc-normalise.1, gc.1,\n"
" gc-all-reachable.1");
con_hook_command(c_gc_show_freeable, "gc-list-freeable", "!a",
"Prints all addresses freeable in the segment\n"
" associated with the address (offset is ignored).\n\n"
"SEE ALSO\n\n"
" gc-list-freeable.1, gc-normalise.1, gc.1,\n"
" gc-all-reachable.1");
con_hook_command(c_gc_normalise, "gc-normalise", "!a",
"Prints the \"normal\" address of a given address,\n"
" i.e. the address we would free in order to free\n"
" the object associated with the original address.\n\n"
"SEE ALSO\n\n"
" gc-list-freeable.1, gc-list-reachable.1, gc.1,\n"
" gc-all-reachable.1");
/*
con_hook_int(&script_abort_flag, "script_abort_flag", "Set != 0 to abort execution\n");
*/