scummvm/engines/sci/engine/scriptconsole.cpp
2009-02-15 23:49:42 +00:00

1280 lines
32 KiB
C++

/***************************************************************************
console.c Copyright (C) 1999..2002 Christoph Reichenbach, TU Darmstadt
This program may be modified and copied freely according to the terms of
the GNU general public license (GPL), as long as the above copyright
notice and the licensing information contained herein are preserved.
Please refer to www.gnu.org for licensing details.
This work is provided AS IS, without warranty of any kind, expressed or
implied, including but not limited to the warranties of merchantibility,
noninfringement, and fitness for a specific purpose. The author will not
be held liable for any damage caused by this work or derivatives of it.
By using this source code, you agree to the licensing terms as stated
above.
Please contact the maintainer for bug reports or inquiries.
Current Maintainer:
Christoph Reichenbach (CJR) [creichen@rbg.informatik.tu-darmstadt.de]
***************************************************************************/
/* Second half of the console implementation: VM dependent stuff */
/* Remember, it doesn't have to be fast. */
#include "sci/include/sci_memory.h"
#include "sci/include/engine.h"
#ifdef SCI_CONSOLE
state_t *con_gamestate = NULL;
/***************************************************************************/
/* console commands */
static int c_version(struct _state *s); /* displays the package and version number */
static int c_list(struct _state *s); /* lists various types of things */
static int c_man(struct _state *s); /* 'manual page' */
static int c_set(struct _state *s); /* sets an int variable */
static int c_print(struct _state *s); /* prints a variable */
static int c_size(struct _state *s); /* displays the size of a resource */
static int c_dump(struct _state *s); /* gives a hex dump of a resource */
//static int c_objinfo(struct _state *s); /* shows some info about one class */
//static int c_objmethods(struct _state *s); /* Disassembles all methods of a class */
static int c_hexgrep(struct _state *s); /* Searches a string in one resource or resource class */
static int c_selectornames(struct _state *s); /* Displays all selector names */
static int c_kernelnames(struct _state *s); /* Displays all kernel function names */
static int c_dissectscript(struct _state *s); /* Splits a script into objects and explains them */
typedef struct {
const char *name;
const char *description;
} cmd_mm_entry_t; /* All later structures must "extend" this */
typedef cmd_mm_entry_t cmd_page_t; /* Simple info page */
typedef struct {
const char *name;
const char *description;
int (*command)(state_t *);
const char *param;
} cmd_command_t;
typedef struct {
const char *name;
const char *description;
union {
int *intp;
char **charpp;
reg_t *reg;
} var;
} cmd_var_t;
typedef void printfunc_t(cmd_mm_entry_t *data, int full);
typedef struct {
const char *name;
void *data; /* cmd_mm_entry_t */
size_t size_per_entry;
printfunc_t *print;
int entries; /* Number of used entries */
int allocated; /* Number of allocated entries */
} cmd_mm_struct_t;
#define CMD_MM_ENTRIES 3 /* command console memory and manual page manager */
#define CMD_MM_DEFAULT_ALLOC 4 /* Number of table entries to allocate per default */
#define CMD_MM_CMD 0 /* Commands */
#define CMD_MM_VAR 1 /* Variables */
#define CMD_MM_DOC 2 /* Misc. documentation */
static const char *cmd_mm_names[CMD_MM_ENTRIES] = {
"Commands",
"Variables",
"Documentation"
};
static size_t cmd_mm_sizes_per_entry[CMD_MM_ENTRIES] = {
sizeof(cmd_command_t),
sizeof(cmd_var_t),
sizeof(cmd_page_t)
};
static void _cmd_print_command(cmd_mm_entry_t *data, int full);
static void _cmd_print_var(cmd_mm_entry_t *data, int full);
static void _cmd_print_page(cmd_mm_entry_t *data, int full);
static printfunc_t *cmd_mm_printers[CMD_MM_ENTRIES] = {
_cmd_print_command,
_cmd_print_var,
_cmd_print_page
};
static cmd_mm_struct_t cmd_mm[CMD_MM_ENTRIES];
static int _cmd_initialized = 0;
static int _lists_need_sorting = 0;
unsigned int cmd_paramlength;
cmd_param_t *cmd_params;
/********** dmalloc functions **********/
#ifdef WITH_DMALLOC
int
c_dm_stats(state_t * s) {
dmalloc_log_stats();
return 0;
}
int
c_dm_log_unfreed(state_t * s) {
dmalloc_log_unfreed();
return 0;
}
int
c_dm_verify(state_t * s) {
unsigned long pointer_var;
void *ptr;
pointer_var = strtoul(cmd_params[0].str, NULL, 0);
ptr = (void *) pointer_var;
dmalloc_verify(ptr);
return 0;
}
int
c_dm_debug(state_t * s) {
if (cmd_paramlength) {
long newval = strtol(cmd_params[0].str, NULL, 0);
sciprintf("Setting dmalloc_debug(%ld)\n", newval);
dmalloc_debug(newval);
} else
sciprintf("dmalloc_debug is at 0x%lx\n", dmalloc_debug_current());
return 0;
}
int
c_dm_mark(state_t * s) {
unsigned long mark = dmalloc_mark();
dmalloc_message("------------- MARK 0x%lx ---------------\n", mark);
sciprintf("mark 0x%lx\n", mark);
return 0;
}
int
c_dm_chmark(state_t * s) {
unsigned long mark = strtoul(cmd_params[0].str, NULL, 0);
sciprintf("Checking mark 0x%lx\n", mark);
dmalloc_message("--- Mark 0x%lx:\n", mark);
dmalloc_log_changed(mark, 1, 1, 1);
return 0;
}
int
c_dm_print(state_t * s) {
int i;
for (i = 0; i < cmd_paramlength; i++)
dmalloc_message("%s\n", cmd_params[i].str);
return 0;
}
void
con_init_dmalloc() {
con_hook_command(c_dm_stats, "dm_stats", "",
"Prints memory usage stats\n to the dmalloc output file\n\n dm_stats");
con_hook_command(c_dm_log_unfreed, "dm_log_unfreed", "",
"Prints unfreed pointer\n information to the dmalloc\n output file\n\n"
"USAGE\n\n dm_log_unfreed");
con_hook_command(c_dm_verify, "dm_verify", "s",
"Verifies one pointer,\n prints output to dmalloc file\n\nUSAGE\n\n"
" dm_verify <ptr>\n dm_verify 0\n\n 'dm_verify 0' will verify\n ALL current pointers.\n");
con_hook_command(c_dm_debug, "dm_debug", "s*",
"Sets the dmalloc debug\n state or displays it\n\nUSAGE\n\n dm_debug <mode>\n dm_debug");
con_hook_command(c_dm_mark, "dm_mark", "",
"Gets a mark describing\n the current heap state\n\nUSAGE\n\n dm_mark\n\n"
" The mark is written to the\n dmalloc output file and\n to sci output.\n\nSEE ALSO\n\n cm_chmark");
con_hook_command(c_dm_chmark, "dm_chmark", "s",
"Checks changes in the\n heap state since a certain\n mark was retrieved\n\n"
"USAGE\n\n c_dm_chmark <mark>\n\n Output is written to the\n dmalloc output file.\n\n Use dm_mark to retrieve a\n"
" mark.\n\nSEE ALSO\n\n c_dm_mark");
con_hook_command(c_dm_print, "dm_print", "s*",
"Prints something to the\n dmalloc output.\n\nUSAGE\n\n dm_print <text>");
}
#else /* WITH_DMALLOC */
void
con_init_dmalloc(void) {
}
#endif /* WITH_DMALLOC */
void
_cmd_exit(void) {
int t;
for (t = 0; t < CMD_MM_ENTRIES; t++)
free(cmd_mm[t].data);
}
static cmd_mm_entry_t *
cmd_mm_find(char *name, int type) {
int i;
for (i = 0; i < cmd_mm[type].entries; i++)
if (!strcmp(((cmd_mm_entry_t *)((byte *)cmd_mm[type].data + i * cmd_mm[type].size_per_entry))->name, name))
return ((cmd_mm_entry_t *)((byte *)cmd_mm[type].data + i * cmd_mm[type].size_per_entry));
return NULL;
}
static int
_cmd_mm_comp(const void *a, const void *b) {
return strcmp(((cmd_mm_entry_t *) a)->name, ((cmd_mm_entry_t *) b)->name);
}
void
con_sort_all(void) {
int i;
for (i = 0; i < CMD_MM_ENTRIES; i++)
if (cmd_mm[i].entries && _lists_need_sorting & (1 << i))
qsort(cmd_mm[i].data, cmd_mm[i].entries, cmd_mm[i].size_per_entry,
_cmd_mm_comp);
_lists_need_sorting = 0;
}
void
con_init(void) {
if (!_cmd_initialized) {
int i;
_cmd_initialized = 1;
for (i = 0; i < CMD_MM_ENTRIES; i++) {
cmd_mm[i].name = cmd_mm_names[i];
cmd_mm[i].size_per_entry = cmd_mm_sizes_per_entry[i];
cmd_mm[i].entries = 0;
cmd_mm[i].allocated = CMD_MM_DEFAULT_ALLOC;
cmd_mm[i].data = sci_calloc(cmd_mm[i].allocated, cmd_mm[i].size_per_entry);
cmd_mm[i].print = cmd_mm_printers[i];
}
atexit(_cmd_exit);
/* Hook up some commands */
con_hook_command(&c_version, "version", "",
"Displays the version number");
con_hook_command(&c_list, "list", "s*",
"Lists various things (try 'list')");
con_hook_command(&c_man, "man", "s",
"Gives a short description of something");
con_hook_command(&c_print, "print", "s", "Prints an int variable");
con_hook_command(&c_set, "set", "si", "Sets an int variable");
con_hook_command(&c_size, "size", "si",
"Displays the size of a resource");
con_hook_command(&c_dump, "dump", "si", "HexDumps a resource");
con_hook_command(&c_hexgrep, "hexgrep", "shh*",
"Searches some resources for a\n"
" particular sequence of bytes, re-\n presented"
" as hexadecimal numbers.\n\n"
"EXAMPLES:\n hexgrep script e8 03 c8 00\n"
" hexgrep pic.042 fe");
con_hook_command(&c_dissectscript, "dissectscript", "i",
"Examines a script.");
con_hook_page("addresses",
"Passing address parameters\n\n"
" Address parameters may be passed in one of\n"
" three forms:\n"
" - ssss:oooo -- where 'ssss' denotes a\n"
" segment and 'oooo' an offset. Example:\n"
" \"a:c5\" would address something in seg-\n"
" ment 0xa at offset 0xc5.\n"
" - &scr:oooo -- where 'scr' is a script number\n"
" and oooo an offset within that script; will\n"
" fail if the script is not currently loaded\n"
" - $REG -- where 'REG' is one of 'PC', 'ACC',\n"
" 'PREV' or 'OBJ': References the address\n"
" indicated by the register of this name.\n"
" - $REG+n (or -n) -- Like $REG, but modifies\n"
" the offset part by a specific amount (which\n"
" is specified in hexadecimal).\n"
" - ?obj -- Looks up an object with the specified\n"
" name, uses its address. This will abort if\n"
" the object name is ambiguous; in that case,\n"
" a list of addresses and indices is provided.\n"
" ?obj.idx may be used to disambiguate 'obj'\n"
" by the index 'idx'.\n");
con_init_dmalloc();
con_hook_int(&con_passthrough, "con_passthrough",
"scicon->stdout passthrough");
}
}
static inline int
clone_is_used(clone_table_t *t, int idx) {
return ENTRY_IS_VALID(t, idx);
}
int
parse_reg_t(state_t *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 (!s) {
sciprintf("Addresses can only be parsed if a global state is present");
return 1; /* Requires a valid state */
}
if (*str == '$') { /* Register */
rel_offsetting = 1;
if (!strncasecmp(str + 1, "PC", 2)) {
*dest = s->execution_stack[s->execution_stack_pos].addr.pc;
offsetting = str + 3;
} else if (!strncasecmp(str + 1, "P", 1)) {
*dest = s->execution_stack[s->execution_stack_pos].addr.pc;
offsetting = str + 2;
} else if (!strncasecmp(str + 1, "PREV", 4)) {
*dest = s->r_prev;
offsetting = str + 5;
} else if (!strncasecmp(str + 1, "ACC", 3)) {
*dest = s->r_acc;
offsetting = str + 4;
} else if (!strncasecmp(str + 1, "A", 1)) {
*dest = s->r_acc;
offsetting = str + 2;
} else if (!strncasecmp(str + 1, "OBJ", 3)) {
*dest = s->execution_stack[s->execution_stack_pos].objp;
offsetting = str + 4;
} else if (!strncasecmp(str + 1, "O", 1)) {
*dest = s->execution_stack[s->execution_stack_pos].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 = sm_seg_get(&s->seg_manager, 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; /* Supress spurious -Wall warning */
int 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++) {
mem_obj_t *mobj = s->seg_manager.heap[i];
int idx = 0;
int max_index = 0;
if (mobj) {
if (mobj->type == MEM_OBJ_SCRIPT)
max_index = mobj->data.script.objects_nr;
else if (mobj->type == MEM_OBJ_CLONES)
max_index = mobj->data.clones.max_entry;
}
while (idx < max_index) {
int valid = 1;
object_t *obj = NULL; /* Surpress spurious warning */
reg_t objpos;
objpos.offset = 0;
objpos.segment = i;
if (mobj->type == MEM_OBJ_SCRIPT) {
obj = mobj->data.script.objects + idx;
objpos.offset = obj->pos.offset;
} else if (mobj->type == MEM_OBJ_CLONES) {
obj = &(mobj->data.clones.table[idx].entry);
objpos.offset = idx;
valid = clone_is_used(&mobj->data.clones, idx);
}
if (valid) {
char *objname = (char *) obj->base
+ obj->variables[SCRIPT_NAME_SELECTOR].offset;
if (!strcmp(objname, str_objname)) {
/* Found a match! */
if (index < 0 ||
times_found == index)
*dest = objpos;
else if (times_found < 0 && index) {
if (index == 1) {
/* First time we realized
** the ambiguity */
sciprintf("Ambiguous:\n");
sciprintf(" %3x: ["PREG"] %s\n", 0, PRINT_REG(*dest), str_objname);
}
sciprintf(" %3x: ["PREG"] %s\n", index, PRINT_REG(objpos), str_objname);
}
++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;
}
void
con_parse(state_t *s, const char *command) {
int quote = 0; /* quoting? */
int done = 0; /* are we done yet? */
int cdone = 0; /* Done with the current command? */
const char *paramt; /* parameter types */
char *cmd = (command && command[0]) ? (char *) sci_strdup(command) :
(char *) sci_strdup(" ");
char *_cmd = cmd;
int pos = 0;
if (!_cmd_initialized)
con_init();
while (!done) {
cmd_command_t *command_todo;
int onvar = 1; /* currently working on a variable? */
unsigned int parammem = 0;
unsigned int i;
cdone = 0;
pos = 0;
/* cmd_params = sci_realloc(cmd_params, parammem); */
cmd_paramlength = 0;
while (*cmd == ' ')
cmd++;
while (!cdone) {
switch (cmd[pos]) {
case 0:
done = 1;
case ';':
if (!quote)
cdone = 1;
case ' ':
if (!quote)
cmd[pos] = onvar = 0;
break;
case '\\': /* don't check next char for special meaning */
memmove(cmd + pos, cmd + pos + 1, strlen(cmd + pos) - 1);
break;
case '"':
quote ^= 1;
memmove(cmd + pos, cmd + pos + 1, strlen(cmd + pos));
pos--;
break;
default:
if (!onvar) {
onvar = 1;
if (cmd_paramlength == parammem)
cmd_params = (cmd_param_t*)sci_realloc(cmd_params,
sizeof(cmd_param_t)
* (parammem += 8));
cmd_params[cmd_paramlength].str = cmd + pos;
cmd_paramlength++;
}
break;
}
pos++;
}
if (quote)
sciprintf("unbalanced quotes\n");
else if (strcmp(cmd, "") != 0) {
command_todo = (cmd_command_t *) cmd_mm_find(cmd, CMD_MM_CMD);
if (!command_todo)
sciprintf("%s: not found\n", cmd);
else {
unsigned int minparams;
int need_state = 0;
paramt = command_todo->param;
if (command_todo->param[0] == '!') {
need_state = 1;
paramt++;
}
minparams = strlen(paramt);
if ((paramt[0] != 0) && (paramt[strlen(paramt) - 1] == '*'))
minparams -= 2;
if (cmd_paramlength < minparams)
sciprintf("%s: needs more than %d parameters\n",
cmd, cmd_paramlength);
else if ((cmd_paramlength > strlen(paramt))
&& ((strlen(paramt) == 0)
|| paramt[strlen(paramt) - 1] != '*'))
sciprintf("%s: too many parameters", cmd);
else {
int do_execute = !need_state || s; /* /me wants an
** implication arrow */
char paramtype;
int paramtypepos = 0;
char *endptr;
for (i = 0; i < cmd_paramlength; i++) {
paramtype = paramt[paramtypepos];
if ((paramt[paramtypepos + 1])
&& (paramt[paramtypepos + 1] != '*'))
paramtypepos++;
/* seek next param type unless end of string or '* ' */
switch (paramtype) {
/* Now turn the parameters into variables of the appropriate types,
** unless they're strings, and store them in the global cmd_params[]
** structure */
case 'a': {
char *oldname = cmd_params[i].str;
if (parse_reg_t(s, oldname,
&(cmd_params[i].reg))) {
sciprintf("%s: '%s' is not an address or object\n", cmd, oldname);
do_execute = 0;
}
break;
}
case 'i': {
char *orgstr = cmd_params[i].str;
cmd_params[i].val = strtol(orgstr, &endptr, 0);
if (*endptr != '\0') {
do_execute = 0;
sciprintf("%s: '%s' is not an int\n", cmd, orgstr);
}
}
break;
case 'h': {
char *orgstr = cmd_params[i].str;
cmd_params[i].val = strtol(orgstr, &endptr, 16);
if (*endptr != '\0') {
do_execute = 0;
sciprintf("%s: '%s' is not a hex number\n", cmd, orgstr);
}
cmd_params[i].val &= 0xff; /* Clip hex numbers to 0x00 ... 0xff */
}
break;
case 's':
break;
default:
fprintf(stderr, "Internal error: Heap corruption or prior assertion failed:\n"
"Unknown parameter type '%c' for funtion\n", paramtype);
}
}
if (do_execute) {
command_todo->command(s);
} else fprintf(stderr, "Skipping command...\n");
}
}
}
cmd += pos;
}
free(_cmd);
if (cmd_params)
free(cmd_params);
cmd_params = NULL;
}
/* (unused)
static cmd_mm_entry_t *
con_iterate_entry(int ID, int *counter)
{
byte *retval;
con_init();
if (*counter >= cmd_mm[ID].entries)
return 0;
retval = cmd_mm[ID].data;
retval += (*counter) * cmd_mm[ID].size_per_entry;
(*counter)++;
return (cmd_mm_entry_t *) retval;
}
*/
static cmd_mm_entry_t *
con_alloc_page_entry(int ID) {
int entry;
con_init();
if (cmd_mm[ID].entries >= cmd_mm[ID].allocated) {
int nextsize = cmd_mm[ID].allocated;
if (nextsize >= 64)
nextsize += 16;
else
nextsize <<= 1;
cmd_mm[ID].data = sci_realloc(cmd_mm[ID].data,
nextsize * cmd_mm[ID].size_per_entry);
cmd_mm[ID].allocated = nextsize;
}
_lists_need_sorting |= (1 << ID);
entry = cmd_mm[ID].entries++;
return (cmd_mm_entry_t *)(((byte *)cmd_mm[ID].data)
+ entry * cmd_mm[ID].size_per_entry);
}
int
con_hook_page(const char *name, const char *body) {
cmd_page_t *page = (cmd_page_t *) con_alloc_page_entry(CMD_MM_DOC);
page->name = name;
page->description = body;
return 0;
}
int
con_hook_command(int command(state_t *), const char *name, const char *param,
const char *description) {
cmd_command_t *cmd = NULL;
unsigned int i;
if (NULL == name) {
sciprintf("console.c: con_hook_command(): NULL passed for name\n");
return -1;
}
if (command == NULL)
return 1;
if (param == NULL)
param = "";
if (description == NULL)
description = "";
i = 0;
while (param[i] != 0) {
switch (param[i]) {
case '*':
if (param[i + 1] != 0)
return 1;
if (i == 0)
return 1;
case 'h':
case '!':
case 'i':
case 'a':
case 's':
case 'r':
break;
default:
return 1;
}
i++;
}
cmd = (cmd_command_t *) con_alloc_page_entry(CMD_MM_CMD);
cmd->command = command;
cmd->name = name;
cmd->param = param;
cmd->description = description;
return 0;
}
int
con_hook_int(int *pointer, const char *name, const char *description) {
cmd_var_t *var;
if (pointer == NULL)
return 1;
if (description == NULL)
description = "";
var = (cmd_var_t *) con_alloc_page_entry(CMD_MM_VAR);
var->var.intp = pointer;
var->name = name;
var->description = description;
return 0;
}
/***************************************************************************
* Console commands and support functions
***************************************************************************/
static int
get_resource_number(char *resid)
/* Gets the resource number of a resource string, or returns -1 */
{
int i, res = -1;
for (i = 0; i < sci_invalid_resource; i++)
if (strcmp(sci_resource_types[i], resid) == 0)
res = i;
return res;
}
static int
c_version(state_t * s) {
if (NULL == s) {
sciprintf("console.c: c_version: NULL passed for parameter s\n");
return -1;
}
sciprintf("FreeSCI, version " VERSION "\n");
sciprintf("Resource file version: %s\n", sci_version_types[s->resmgr->sci_version]);
sciprintf("Emulated interpreter version: %d.%03d.%03d\n",
SCI_VERSION_MAJOR(s->version),
SCI_VERSION_MINOR(s->version),
SCI_VERSION_PATCHLEVEL(s->version));
return 0;
}
static int
c_list_words(state_t *s) {
word_t **words;
int words_nr;
int i;
words = vocab_get_words(s->resmgr, &words_nr);
if (!words) {
sciprintf("No vocabulary.\n");
return 1;
}
for (i = 0; i < words_nr; i++)
sciprintf("%4d: %03x [%03x] %s\n",
i,
words[i]->w_class,
words[i]->group,
words[i]->word);
vocab_free_words(words, words_nr);
return 0;
}
int
c_list_suffices(state_t *s) {
suffix_t **suffices;
int suffices_nr;
int i;
char word_buf[256], alt_buf[256];
suffices = vocab_get_suffices(s->resmgr, &suffices_nr);
if (!suffices) {
sciprintf("No suffix vocabulary.\n");
return 1;
}
for (i = 0; i < suffices_nr; i++) {
suffix_t *suf = suffices[i];
strncpy(word_buf, suf->word_suffix,
suf->word_suffix_length);
word_buf[suf->word_suffix_length] = 0;
strncpy(alt_buf, suf->alt_suffix,
suf->alt_suffix_length);
alt_buf[suf->alt_suffix_length] = 0;
sciprintf("%4d: (%03x) -%12s => -%12s (%03x)\n",
i, suf->class_mask, word_buf,
alt_buf, suf->result_class);
}
vocab_free_suffices(s->resmgr, suffices, suffices_nr);
return 0;
}
static void
_cmd_print_command(cmd_mm_entry_t *data, int full) {
const char *paramseeker = ((cmd_command_t *) data)->param;
if (full) {
sciprintf("SYNOPSIS\n\n %s ", data->name, paramseeker);
while (*paramseeker) {
switch (*paramseeker) {
case '!':
break;
case 'i':
sciprintf(" (int)");
break;
case 'a':
sciprintf(" (addr)");
break;
case 's':
sciprintf(" (string)");
break;
case 'h':
sciprintf(" (hexbyte)");
break;
case '*':
sciprintf("*");
break;
default:
sciprintf(" (Unknown(%c))", *paramseeker);
}
paramseeker++;
}
sciprintf("\n\nDESCRIPTION\n\n %s",
data->description);
} else
sciprintf(" %s", data->name);
}
static void
_cmd_print_var(cmd_mm_entry_t *data, int full) {
cmd_var_t *var = (cmd_var_t *) data;
if (full)
sciprintf("VALUE\n\n");
sciprintf(" %s = %d\n", var->name, *(var->var.intp));
if (full)
sciprintf("\n\nDESCRIPTION\n\n %s",
data->description);
}
static void
_cmd_print_page(cmd_mm_entry_t *data, int full) {
if (full)
sciprintf("\n\nDESCRIPTION\n\n %s\n",
data->description);
else sciprintf("%s\n", data->name);
}
static int
c_list(state_t * s) {
if (_lists_need_sorting)
con_sort_all();
if (cmd_paramlength == 0) {
sciprintf("usage: list [type]\nwhere type is one of the following:\n"
"cmds - lists all commands\n"
"vars - lists all variables\n"
"docs - lists all misc. documentation\n"
"\n"
"restypes - lists all resource types\n"
"selectors - lists all selectors\n"
"syscalls - lists all kernel functions\n"
"words - lists all kernel words\n"
"suffixes - lists all suffix replacements\n"
"[resource] - lists all [resource]s");
} else if (cmd_paramlength == 1) {
const char *mm_subsects[3] = {"cmds", "vars", "docs"};
int mm_found = -1;
int i;
for (i = 0; i < 3; i++)
if (mm_subsects[i] && !strcmp(mm_subsects[i], cmd_params[0].str))
mm_found = i;
if (mm_found >= 0)
for (i = 0; i < cmd_mm[mm_found].entries; i++)
cmd_mm[mm_found].print((cmd_mm_entry_t *)
(((byte *)cmd_mm[mm_found].data)
+ i * cmd_mm[mm_found].size_per_entry), 0);
else {
if (!s) {
sciprintf("You need a state to do that!\n");
return 1;
}
if (!strcmp("selectors", cmd_params[0].str))
return c_selectornames(s);
else if (!strcmp("syscalls", cmd_params[0].str))
return c_kernelnames(s);
else if (!strcmp("suffixes", cmd_params[0].str)
|| !strcmp("suffices", cmd_params[0].str)
|| !strcmp("sufficos", cmd_params[0].str))
/* sufficos: Accusative Plural of 'suffix' */
return c_list_suffices(s);
else if (!strcmp("words", cmd_params[0].str))
return c_list_words(s);
else if (strcmp("restypes", cmd_params[0].str) == 0) {
for (i = 0; i < sci_invalid_resource; i++)
sciprintf("%s\n", sci_resource_types[i]);
} else {
int res = get_resource_number(cmd_params[0].str);
if (res == -1)
sciprintf("Unknown resource type: '%s'\n", cmd_params[0].str);
else {
for (i = 0; i < sci_max_resource_nr[s->resmgr->sci_version]; i++)
if (scir_test_resource(s->resmgr, res, i))
sciprintf("%s.%03d\n", sci_resource_types[res], i);
}
}
}
} else
sciprintf("list can only be used with one argument");
return 0;
}
static int
c_man(state_t * s) {
int section = 0;
unsigned int i;
char *name = cmd_params[0].str;
char *c = strchr(name, '.');
cmd_mm_entry_t *entry = 0;
if (c) {
*c = 0;
section = atoi(c + 1);
}
if (section < 0 || section >= CMD_MM_ENTRIES) {
sciprintf("Invalid section %d\n",
section);
return 1;
}
sciprintf("section:%d\n", section);
if (section)
entry = cmd_mm_find(name, section - 1);
else
for (i = 0; i < CMD_MM_ENTRIES && !section; i++) {
if ((entry = cmd_mm_find(name, i)))
section = i + 1;
}
if (!entry) {
sciprintf("No manual entry\n");
return 1;
}
sciprintf("-- %s: %s.%d\n", cmd_mm[section - 1].name, name, section);
cmd_mm[section - 1].print(entry, 1);
return 0;
}
static int
c_set(state_t * s) {
cmd_var_t *var = (cmd_var_t *) cmd_mm_find(cmd_params[0].str, CMD_MM_VAR);
if (var)
*(var->var.intp) = cmd_params[1].val;
return 0;
}
static int
c_print(state_t * s) {
cmd_var_t *var = (cmd_var_t *) cmd_mm_find(cmd_params[0].str, CMD_MM_VAR);
if (var)
sciprintf("%d", *(var->var.intp));
else
sciprintf("Not defined.");
return 0;
}
static int
c_size(state_t * s) {
int res = get_resource_number(cmd_params[0].str);
if (res == -1)
sciprintf("Resource type '%s' is not valid\n", cmd_params[0].str);
else {
resource_t *resource = scir_find_resource(s->resmgr, res, cmd_params[1].val, 0);
if (resource) {
sciprintf("Size: %d\n", resource->size);
} else
sciprintf("Resource %s.%03d not found\n", cmd_params[0].str,
cmd_params[1].val);
}
return 0;
}
static int
c_dump(state_t * s) {
int res = get_resource_number(cmd_params[0].str);
if (res == -1)
sciprintf("Resource type '%s' is not valid\n", cmd_params[0].str);
else {
resource_t *resource = scir_find_resource(s->resmgr, res, cmd_params[1].val, 0);
if (resource)
sci_hexdump(resource->data, resource->size, 0);
else
sciprintf("Resource %s.%03d not found\n", cmd_params[0].str,
cmd_params[1].val);
}
return 0;
}
static int
c_hexgrep(state_t * s) {
int i, seeklen, resnr, restype, resmax;
unsigned char *seekstr = NULL;
resource_t *script = NULL;
char *dot = strchr(cmd_params[0].str, '.');
if (NULL == s) {
fprintf(stderr, "console.c: c_hexgrep(): NULL passed for s\r\n");
return(-1);
}
seekstr = (unsigned char*)sci_malloc(seeklen = (cmd_paramlength - 1));
if (NULL == seekstr) {
fprintf(stderr, "console.c: c_hexgrep(): malloc failed for seekstr\r\n");
return(-1);
}
for (i = 0; i < seeklen; i++)
seekstr[i] = (byte)cmd_params[i + 1].val;
if (dot) {
*dot = 0;
resmax = resnr = atoi(dot + 1);
} else {
resnr = 0;
resmax = 999;
}
if ((restype = get_resource_number(cmd_params[0].str)) == -1) {
sciprintf("Unknown resource type \"%s\"\n", cmd_params[0].str);
free(seekstr);
return 1;
}
for (; resnr <= resmax; resnr++)
if ((script = scir_find_resource(s->resmgr, restype, resnr, 0))) {
unsigned int seeker = 0, seekerold = 0;
int comppos = 0;
int output_script_name = 0;
while (seeker < script->size) {
if (script->data[seeker] == seekstr[comppos]) {
if (comppos == 0)
seekerold = seeker;
comppos++;
if (comppos == seeklen) {
comppos = 0;
seeker = seekerold + 1;
if (!output_script_name) {
sciprintf("\nIn %s.%03d:\n", sci_resource_types[restype], resnr);
output_script_name = 1;
}
sciprintf(" 0x%04x\n", seekerold);
}
} else
comppos = 0;
seeker++;
}
}
free(seekstr);
return 0;
}
static int
c_selectornames(state_t * s) {
int namectr;
char **snames = NULL;
int seeker = 0;
if (NULL == s) {
sciprintf("console.c: c_selectornames(): NULL passed for parameter s\n");
return -1;
}
snames = vocabulary_get_snames(s->resmgr, &namectr, s ? s->version : 0);
if (!snames) {
sciprintf("No selector name table found!\n");
return 1;
}
sciprintf("Selector names in numeric order:\n");
while (snames[seeker]) {
sciprintf("%03x: %s\n", seeker, snames[seeker]);
seeker++;
}
vocabulary_free_snames(snames);
return 0;
}
static int
c_kernelnames(state_t * s) {
int knamectr;
char **knames = vocabulary_get_knames(s->resmgr, &knamectr);
int seeker = 0;
if (NULL == s) {
sciprintf("console.c: c_kernelnames NULL passed for parameter s\n");
return -1;
}
if (!knames) {
sciprintf("No kernel name table found!\n");
return 1;
}
sciprintf("Syscalls in numeric order:\n");
for (seeker = 0; seeker < knamectr; seeker++)
sciprintf("%03x: %s\n", seeker, knames[seeker]);
vocabulary_free_knames(knames);
return 0;
}
static int
c_dissectscript(state_t * s) {
if (NULL == s) {
sciprintf("console.c: c_dissectscript(): NULL passed for parameter s\n");
return -1;
}
script_dissect(s->resmgr, cmd_params[0].val, s->selector_names, s->selector_names_nr);
return 0;
}
#endif /* SCI_CONSOLE */