diff options
Diffstat (limited to 'engines/sci/engine/scriptconsole.cpp')
-rw-r--r-- | engines/sci/engine/scriptconsole.cpp | 1342 |
1 files changed, 1342 insertions, 0 deletions
diff --git a/engines/sci/engine/scriptconsole.cpp b/engines/sci/engine/scriptconsole.cpp new file mode 100644 index 0000000000..48f1f1695b --- /dev/null +++ b/engines/sci/engine/scriptconsole.cpp @@ -0,0 +1,1342 @@ +/*************************************************************************** + 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 retreived\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 retreive 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, char *str, reg_t *dest) +{ /* Returns 0 on success */ + int rel_offsetting = 0; + 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 = 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 *str_objname; + char *str_suffix; + char suffchar = 0; /* Supress spurious -Wall warning */ + int i; + /* Parse obj by name */ + + str_objname = strchr(str, '+'); + str_suffix = strchr(str, '-'); + if (str_objname < str_suffix) + str_suffix = str_objname; + if (str_suffix) { + suffchar = (*str_suffix); + *str_suffix = 0; + } + + str_objname = strchr(str, '.'); + + if (str_objname) { + *str_objname = 0; + index = strtol(str_objname+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.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 = 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) { + int i; + 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 { + int i; + 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; + + 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 */ + + |