/* 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. * * $URL$ * $Id$ * */ /* 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" namespace Sci { #ifdef SCI_CONSOLE EngineState *con_gamestate = NULL; // console commands static int c_list(EngineState *s); // lists various types of things static int c_man(EngineState *s); // 'manual page' static int c_set(EngineState *s); // sets an int variable static int c_print(EngineState *s); // prints a variable static int c_size(EngineState *s); // displays the size of a resource static int c_dump(EngineState *s); // gives a hex dump of a resource //static int c_objinfo(EngineState *s); // shows some info about one class //static int c_objmethods(EngineState *s); // Disassembles all methods of a class static int c_hexgrep(EngineState *s); // Searches a string in one resource or resource class static int c_selectornames(EngineState *s); // Displays all selector names static int c_kernelnames(EngineState *s); // Displays all kernel function names static int c_dissectscript(EngineState *s); // Splits a script into objects and explains them struct cmd_mm_entry_t { const char *name; const char *description; }; // All later structures must "extend" this typedef cmd_mm_entry_t cmd_page_t; // Simple info page struct cmd_command_t { const char *name; const char *description; int (*command)(EngineState *); const char *param; }; struct cmd_var_t { const char *name; const char *description; union { int *intp; char **charpp; reg_t *reg; } var; }; typedef void printfunc_t(cmd_mm_entry_t *data, int full); struct cmd_mm_struct_t { 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 }; #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; void _cmd_exit() { 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() { 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() { 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_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_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(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 (!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 (!scumm_strnicmp(str + 1, "PC", 2)) { *dest = s->execution_stack[s->execution_stack_pos].addr.pc; offsetting = str + 3; } else if (!scumm_strnicmp(str + 1, "P", 1)) { *dest = s->execution_stack[s->execution_stack_pos].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->execution_stack[s->execution_stack_pos].objp; offsetting = str + 4; } else if (!scumm_strnicmp(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 = 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; 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; 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(EngineState *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(EngineState *), 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_list_words(EngineState *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(EngineState *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 (%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(EngineState *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(EngineState *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(EngineState *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(EngineState *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(EngineState *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(EngineState *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(EngineState *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(EngineState * s) { Common::StringList selectorNames; if (NULL == s) { sciprintf("console.c: c_selectornames(): NULL passed for parameter s\n"); return -1; } if (!vocabulary_get_snames(s->resmgr, s ? s->version : 0, selectorNames)) { sciprintf("No selector name table found!\n"); return 1; } sciprintf("Selector names in numeric order:\n"); for (uint seeker = 0; seeker < selectorNames.size(); seeker++) { sciprintf("%03x: %s\n", seeker, selectorNames[seeker].c_str()); } return 0; } static int c_kernelnames(EngineState * 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(EngineState * 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->_selectorNames); return 0; } #endif // SCI_CONSOLE } // End of namespace Sci