/* -*-c-*- -------------- mix_vm_command.c : * Implementation of the functions declared in mix_vm_command.h * ------------------------------------------------------------------ * Last change: Time-stamp: "01/03/15 15:57:52 jose" * ------------------------------------------------------------------ * Copyright (C) 2001 Free Software Foundation, Inc. * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include #include #include #include #include #include "mix_vm_command.h" #include "mix_vm.h" #include "mix_vm_dump.h" #include "mix_eval.h" /* hooks */ typedef struct { mix_vm_cmd_hook_t func; gpointer data; } hook_; typedef struct { mix_vm_cmd_global_hook_t func; gpointer data; } global_hook_; struct mix_vm_cmd_dispatcher_t { mix_vm_t *vm; /* the virtual machine */ gboolean result; /* last command's outcome */ gchar *program; /* the name of the last loaded program */ FILE *out; /* message output file */ FILE *err; /* error output file */ mix_dump_context_t *dump; /* dump context for output */ mix_eval_t *eval; /* evaluator for w-expressions */ gboolean trace; /* tracing flag */ gboolean printtime; /* printing times flag */ mix_time_t uptime; /* total running time */ mix_time_t laptime; /* last run time */ mix_time_t progtime; /* current program running time */ hook_ pre_hooks[MIX_CMD_INVALID]; /* Pre-command hooks */ hook_ post_hooks[MIX_CMD_INVALID]; /* Post-command hooks */ global_hook_ global_pre; /* global pre-command hook */ global_hook_ global_post; /* global post-command hook */ }; /* command handlers */ typedef gboolean (*Function_)(mix_vm_cmd_dispatcher_t *, const gchar *); #define DEC_FUN(name) \ static int cmd_##name (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) DEC_FUN (help_); DEC_FUN (load_); DEC_FUN (run_); DEC_FUN (next_); DEC_FUN (pc_); DEC_FUN (psym_); DEC_FUN (preg_); DEC_FUN (pflags_); DEC_FUN (pall_); DEC_FUN (pmem_); DEC_FUN (sreg_); DEC_FUN (scmp_); DEC_FUN (sover_); DEC_FUN (smem_); DEC_FUN (ssym_); DEC_FUN (sbp_); DEC_FUN (sbpa_); DEC_FUN (cbp_); DEC_FUN (cbpa_); DEC_FUN (cabp_); DEC_FUN (weval_); DEC_FUN (w2d_); DEC_FUN (tron_); DEC_FUN (troff_); /* internal command info struct */ typedef struct { const char *name; /* User printable name of the function. */ Function_ func; /* Function to call to do the job. */ const char *doc; /* Documentation for this function. */ const char *usage; /* Usage */ } command_; /* available commands (in the same order as the type enum) */ command_ commands_[] = { { "help", cmd_help_, N_("Display this text"), "help [COMMAND]"}, { "load", cmd_load_, N_("Load a MIX code file"), "load FILENAME"}, { "run", cmd_run_, N_("Run loaded or given MIX code file"), "run [FILENAME]"}, { "next", cmd_next_, N_("Execute next instruction(s)"), "next [NO_OF_INS]"}, { "pc", cmd_pc_, N_("Print program counter value"), "pc" }, { "psym", cmd_psym_, N_("Print symbol value"), "psym [SYMBOLNAME]"}, { "preg", cmd_preg_, N_("Print register value"), "preg [A | X | J | I[1-6]]"}, { "pflags", cmd_pflags_, N_("Print comparison and overflow flags"), "pflags"}, { "pall", cmd_pall_, N_("Print all registers and flags"), "pall"}, { "pmem", cmd_pmem_, N_("Print memory contents in address range"), "pmem FROM[-TO]"}, { "sreg", cmd_sreg_, N_("Set register value"), "preg A | X | J | I[1-6] VALUE"}, { "scmp", cmd_scmp_, N_("Set comparison flag value"), "scmp L | E | G"}, { "sover", cmd_sover_, N_("Set overflow flag value"), "sover T | F" }, { "smem", cmd_smem_, N_("Set memory contents in given address"), "smem ADDRESS VALUE"}, { "ssym", cmd_ssym_, N_("Set a symbol\'s value"), "ssym SYMBOL WEXPR"}, { "sbp", cmd_sbp_, N_("Set break point at given line"), "sbp LINENO"}, { "cbp", cmd_cbp_, N_("Clear break point at given line"), "cbp LINENO"}, { "sbpa", cmd_sbpa_, N_("Set break point at given address"), "sbpa ADDRESS"}, { "cbpa", cmd_cbpa_, N_("Clear break point at given address"), "cbpa ADDRESS"}, { "cabp", cmd_cabp_, N_("Clear all breakpoints"), "cabp"}, { "weval", cmd_weval_, N_("Evaluate a given W-expression"), "weval WEXPR"}, { "w2d", cmd_w2d_, N_("Convert a MIX word to its decimal value"), "w2d WORD"}, { "tron", cmd_tron_, N_("Turn on instruction tracing."), "tron"}, { "troff", cmd_troff_, N_("Turn off instruction tracing."), "troff"}, { NULL, NULL, NULL, NULL}, }; /* external interface */ /* conversion from/to commands to strings */ const gchar * mix_vm_command_to_string (mix_vm_command_t cmd) { if (cmd < MIX_CMD_INVALID) return commands_[cmd].name; else return NULL; } mix_vm_command_t mix_vm_command_from_string (const gchar *name) { /* inefficient linear search, i know */ gint cmd = 0; while (cmd < MIX_CMD_INVALID && strcmp (name, commands_[cmd].name)) ++cmd; return cmd; } /* get help string about a command */ const gchar * mix_vm_command_help (mix_vm_command_t cmd) { if (cmd < MIX_CMD_INVALID) return commands_[cmd].doc; else return NULL; } const gchar * mix_vm_command_usage (mix_vm_command_t cmd) { if (cmd < MIX_CMD_INVALID) return commands_[cmd].usage; else return NULL; } /* create a new command dispatcher */ mix_vm_cmd_dispatcher_t * mix_vm_cmd_dispatcher_new (FILE *out_fd, /* output messages file */ FILE *err_fd /* error messages file */) { mix_vm_cmd_dispatcher_t *result = NULL; int k; g_return_val_if_fail (out_fd && err_fd, NULL); result = g_new (mix_vm_cmd_dispatcher_t, 1); result->result = TRUE; result->out = out_fd; result->err = err_fd; result->uptime = result->laptime = result->progtime = 0; result->printtime = TRUE; result->trace = FALSE; result->program = NULL; result->eval = mix_eval_new (); result->dump = mix_dump_context_new (out_fd, MIX_SHORT_ZERO, MIX_SHORT_ZERO, MIX_DUMP_ALL); result->vm = mix_vm_new (); result->global_pre.func = result->global_post.func = NULL; result->global_pre.data = result->global_post.data = NULL; for (k =0; k < MIX_CMD_INVALID; ++k) { result->pre_hooks[k].func = result->post_hooks[k].func = NULL; result->pre_hooks[k].data = result->post_hooks[k].data = NULL; } return result; } /* delete (does not close the fds in the constructor) */ extern void mix_vm_cmd_dispatcher_delete (mix_vm_cmd_dispatcher_t *dis) { g_return_if_fail (dis != NULL); mix_eval_delete (dis->eval); mix_dump_context_delete (dis->dump); mix_vm_delete (dis->vm); g_free (dis); } /* install hooks */ void mix_vm_cmd_dispatcher_pre_hook (mix_vm_cmd_dispatcher_t *dis, mix_vm_command_t cmd, mix_vm_cmd_hook_t hook, gpointer data) { g_return_if_fail (dis != NULL); g_return_if_fail (cmd < MIX_CMD_INVALID); dis->pre_hooks[cmd].func = hook; dis->pre_hooks[cmd].data = data; } void mix_vm_cmd_dispatcher_post_hook (mix_vm_cmd_dispatcher_t *dis, mix_vm_command_t cmd, mix_vm_cmd_hook_t hook, gpointer data) { g_return_if_fail (dis != NULL); g_return_if_fail (cmd < MIX_CMD_INVALID); dis->post_hooks[cmd].func = hook; dis->post_hooks[cmd].data = data; } void mix_vm_cmd_dispatcher_global_pre_hook (mix_vm_cmd_dispatcher_t *dis, mix_vm_cmd_global_hook_t hook, gpointer data) { g_return_if_fail (dis != NULL); dis->global_pre.func = hook; dis->global_pre.data = data; } void mix_vm_cmd_dispatcher_global_post_hook (mix_vm_cmd_dispatcher_t *dis, mix_vm_cmd_global_hook_t hook, gpointer data) { g_return_if_fail (dis != NULL); dis->global_post.func = hook; dis->global_post.data = data; } /* dispatch a command */ gboolean /* TRUE if success, FALSE otherwise */ mix_vm_cmd_dispatcher_dispatch (mix_vm_cmd_dispatcher_t *dis, mix_vm_command_t cmd, const gchar *arg) { g_return_val_if_fail (dis != NULL, FALSE); if (dis->global_pre.func) (dis->global_pre.func)(dis, cmd, arg, dis->global_pre.data); if (cmd < MIX_CMD_INVALID) { if (dis->pre_hooks[cmd].func) (dis->pre_hooks[cmd].func)(dis, arg, dis->pre_hooks[cmd].data); dis->result = (commands_[cmd].func)(dis, arg); if (dis->post_hooks[cmd].func) (dis->post_hooks[cmd].func)(dis, arg, dis->post_hooks[cmd].data); } else { fprintf (dis->err, "Unknown command. Try: help"); } if (dis->global_post.func) (dis->global_post.func)(dis, cmd, arg, dis->global_post.data); fflush (dis->out); fflush (dis->err); return dis->result; } /* dispatch a command in text format */ gboolean mix_vm_cmd_dispatcher_dispatch_text (mix_vm_cmd_dispatcher_t *dis, const gchar *text) { gchar *cp, *arg = ""; int k = 0; gboolean result; g_return_val_if_fail (dis != NULL, FALSE); g_return_val_if_fail (text != NULL, FALSE); cp = g_strdup (text); while (cp[k] && !isspace (cp[k])) ++k; if (cp[k]) { cp[k] = '\0'; ++k; while (cp[k] && isspace (cp[k])) ++k; arg = cp + k; } result = mix_vm_cmd_dispatcher_dispatch (dis, mix_vm_command_from_string (cp), arg); g_free (cp); return result; } /* get the last dispatch's result */ gboolean mix_vm_cmd_dispatcher_get_last_result (const mix_vm_cmd_dispatcher_t *dis) { g_return_val_if_fail (dis != NULL, FALSE); return dis->result; } /* get total uptime */ mix_time_t mix_vm_cmd_dispatcher_get_uptime (const mix_vm_cmd_dispatcher_t *dis) { g_return_val_if_fail (dis != NULL, 0); return dis->uptime; } /* get program total time */ mix_time_t mix_vm_cmd_dispatcher_get_progtime (const mix_vm_cmd_dispatcher_t *dis) { g_return_val_if_fail (dis != NULL, 0); return dis->progtime; } /* get time lapse */ mix_time_t mix_vm_cmd_dispatcher_get_laptime (const mix_vm_cmd_dispatcher_t *dis) { g_return_val_if_fail (dis != NULL, 0); return dis->laptime; } /* toggle time printing */ void mix_vm_cmd_dispatcher_print_time (mix_vm_cmd_dispatcher_t * dis, gboolean print) { g_return_if_fail (dis != NULL); dis->printtime = print; } /* get the mix vm */ const mix_vm_t * mix_vm_cmd_dispatcher_get_vm (const mix_vm_cmd_dispatcher_t *dis) { g_return_val_if_fail (dis != NULL, NULL); return dis->vm; } /* trace current instruction */ static void trace_ (mix_vm_cmd_dispatcher_t *dis) { enum {BUFFER_LEN = 128}; static gchar STRINS[BUFFER_LEN]; const mix_src_file_t *file = mix_vm_get_src_file (dis->vm); const gchar *line = "\n"; mix_address_t loc = mix_vm_get_prog_count (dis->vm); mix_word_t ins = mix_vm_get_addr_contents (dis->vm, loc); mix_ins_t fins; mix_word_to_ins_uncheck (ins, fins); mix_ins_to_string_in_buffer (&fins, STRINS, BUFFER_LEN); if (file != NULL) { gulong b = mix_vm_get_break_lineno (dis->vm); if (b > 0) line = mix_src_file_get_line (file, b); } fprintf (dis->out, "%d: [%-15s]\t%s", (gint)loc, STRINS, line); } /* run a program tracing executed instructions */ static int run_and_trace_ (mix_vm_cmd_dispatcher_t *dis) { int k = MIX_VM_OK; if (!dis->trace) return mix_vm_run (dis->vm); else while (k == MIX_VM_OK) { trace_ (dis); k = mix_vm_exec_next (dis->vm); } return k; } /* print time statistics */ static void print_time_ (mix_vm_cmd_dispatcher_t *dis) { dis->laptime = mix_vm_get_uptime(dis->vm) - dis->uptime; dis->uptime += dis->laptime; dis->progtime += dis->laptime; if (dis->printtime) fprintf( dis->out, _("Elapsed time: %ld /Total program time: %ld (Total uptime: %ld)\n"), dis->laptime, dis->progtime, dis->uptime); } /* commands */ static gboolean cmd_help_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) { static const int NO_OF_COLS = 6; int i; int printed = 0; for (i = 0; commands_[i].name; i++) { if (!*arg || (strcmp (arg, commands_[i].name) == 0)) { fprintf (dis->out ,_("%s\t\t%s. Usage: %s\n"), commands_[i].name, _(commands_[i].doc), commands_[i].usage); printed++; } } if (!printed) { fprintf (dis->out, _("No commands match `%s'. Possibilities are:\n"), arg); for (i = 0; commands_[i].name; i++) { if (printed == NO_OF_COLS) { printed = 0; fprintf (dis->out, "\n"); } fprintf (dis->out, "%s\t", commands_[i].name); printed++; } if (printed) fprintf (dis->out, "\n"); } return TRUE; } static gboolean cmd_load_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) { errno = 0; if (arg == NULL || *arg == '\0') { fputs (_("Missing file name\n"), dis->err); return FALSE; } mix_eval_remove_symbols_from_table (dis->eval, mix_vm_get_symbol_table (dis->vm)); if (!mix_vm_load_file (dis->vm, arg) ) { fprintf (dis->err, _("Cannot load %s: "), arg); if ( errno == 0 ) fputs (_("Wrong file format\n"), dis->err); else fprintf (dis->err, "%s\n", strerror (errno)); return FALSE; } if (dis->program != arg) { if (dis->program) g_free (dis->program); dis->program = g_strdup (arg); } mix_eval_set_symbols_from_table (dis->eval, mix_vm_get_symbol_table (dis->vm)); fprintf (dis->out, _("Program loaded. Start address: %d\n"), mix_vm_get_prog_count (dis->vm)); dis->laptime = dis->progtime = 0; return TRUE; } static gboolean cmd_run_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) { if (arg != NULL && *arg != '\0' && cmd_load_ (dis, arg) != TRUE) return FALSE; if (mix_vm_is_halted (dis->vm)) cmd_load_ (dis, dis->program); fputs (_("Running ...\n"), dis->out); switch (run_and_trace_ (dis)) { case MIX_VM_HALT: fputs (_("... done\n"), dis->out); break; case MIX_VM_BREAK: { gulong line = mix_vm_get_break_lineno (dis->vm); if (line != 0) fprintf (dis->out, _("... stopped: breakpoint at line %ld (address %d)\n"), line, mix_vm_get_prog_count (dis->vm)); else fprintf (dis->out, _("... stopped: breakpoint at address %d\n"), mix_vm_get_prog_count (dis->vm)); } break; case MIX_VM_ERROR: fputs (_("... error executing loaded file"), dis->err); break; default: g_assert_not_reached (); break; } print_time_ (dis); return TRUE; } static gboolean cmd_next_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) { int ins_no = 1; int k; if ( strlen (arg) != 0 ) { int k = 0; while (isdigit (arg[k])) k++; if (arg[k] != '\0') { fprintf (dis->err, _("Invalid argument: %s\n"), arg); cmd_help_ (dis, "next"); return FALSE; } ins_no = atoi (arg); } if (mix_vm_is_halted (dis->vm)) cmd_load_ (dis, dis->program); while ( ins_no-- > 0 ) { if (dis->trace) trace_ (dis); k = mix_vm_exec_next (dis->vm); if (k == MIX_VM_HALT) { fprintf (dis->err, _("End of program reached at address %d\n"), mix_vm_get_prog_count (dis->vm)); break; } else if (k == MIX_VM_ERROR) { fprintf (dis->err, _("Error at address %d\n"), mix_vm_get_prog_count (dis->vm)); break; } } print_time_ (dis); return TRUE; } static gboolean cmd_pc_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) { fprintf (dis->out, "Current address: %d\n", mix_vm_get_prog_count (dis->vm)); return TRUE; } static gboolean cmd_psym_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) { gboolean result = FALSE; const mix_symbol_table_t *table = mix_eval_symbol_table (dis->eval); if ( table == NULL ) fputs (_("Symbol table not available\n"), dis->err); else if (arg != NULL && *arg != '\0') { if ( mix_symbol_table_is_defined (table, arg) ) { mix_word_print (mix_symbol_table_value (table, arg), NULL); putc ('\n', dis->out); result = TRUE; } else fprintf (dis->out, _("%s: symbol not defined\n"), arg); } else { mix_symbol_table_print (table, MIX_SYM_ROWS, stdout, TRUE); result = TRUE; } return result; } static gboolean cmd_preg_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) { mix_dump_context_set_opt (dis->dump, MIX_DUMP_NONE); if ( strlen (arg) == 0 ) mix_dump_context_add_opt (dis->dump, MIX_DUMP_rALL); else switch (*arg) { case 'A': mix_dump_context_add_opt (dis->dump, MIX_DUMP_rA); break; case 'X': mix_dump_context_add_opt (dis->dump, MIX_DUMP_rX); break; case 'J': mix_dump_context_add_opt (dis->dump, MIX_DUMP_rJ); break; case 'I': { if ( strlen (arg) == 1 ) mix_dump_context_add_opt (dis->dump, MIX_DUMP_rIa); else { static gint32 opt[] = { MIX_DUMP_rI1, MIX_DUMP_rI2, MIX_DUMP_rI3, MIX_DUMP_rI4, MIX_DUMP_rI5, MIX_DUMP_rI6 }; int i = arg[1] - '1'; if ( i < 0 || i > 5 ) { fprintf (dis->err, _("Invalid I index: %d"), i); return FALSE; } mix_dump_context_add_opt (dis->dump, opt[i]); } } break; default: fprintf (dis->err, _("Invalid argument: %s\n"), arg); return FALSE; } mix_vm_dump (dis->vm, dis->dump); return TRUE; } static gboolean cmd_pflags_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) { mix_dump_context_set_opt (dis->dump, MIX_DUMP_CMP | MIX_DUMP_OVER); mix_vm_dump (dis->vm, dis->dump); return TRUE; } static gboolean cmd_pall_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) { mix_dump_context_set_opt (dis->dump, MIX_DUMP_ALL_NOMEM); mix_vm_dump (dis->vm, dis->dump); return TRUE; } static gboolean cmd_pmem_ (mix_vm_cmd_dispatcher_t *dis, const gchar *carg) { glong begin = MIX_SHORT_ZERO, end = MIX_SHORT_ZERO; int i = 0; gboolean error = FALSE; gchar *arg = NULL; if ( strlen (carg) == 0 ) { fputs (_("Missing memory address\n"), dis->err); return FALSE; } arg = g_strdup (carg); while (isdigit (arg[i])) i++; while (isspace (arg[i])) i++; if (arg[i] == '\0') begin = end = atol (arg); else if (arg[i] == '-') { arg[i++] = '\0'; begin = atol (arg); arg = arg + i; i = 0; while (isdigit (arg[i])) i++; while (isspace (arg[i])) i++; if (arg[i] != '\0') error = TRUE; else end = atol (arg); } else error = TRUE; if (error) { fprintf (dis->err, _("Invalid argument: %s\n"), arg); cmd_help_ (dis, "pmem"); } else if ( end < begin || end > MIX_VM_CELL_NO - 1 ) { fprintf (dis->err, _("Invalid range: %ld-%ld\n"), begin, end); error = TRUE; } else { mix_dump_context_set_opt (dis->dump, MIX_DUMP_CELLS); mix_dump_context_range (dis->dump, mix_short_new (begin), mix_short_new (end + 1)); mix_vm_dump (dis->vm, dis->dump); } g_free (arg); return !error; } static gboolean cmd_sreg_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) { int i = 0; char reg = arg[0]; gboolean ok = TRUE; long value; i = (reg == 'I') ? 2 : 1; ok = strlen (arg) > 2 && isspace (arg[i]); if (ok) { while (isspace (arg[i])) i++; ok = isdigit (arg[i]) || arg[i] == '+' || arg[i] == '-'; if (ok) { value = atol (arg + i); if (arg[i] == '+' || arg[i] == '-') i++; while (isdigit (arg[i])) i++; ok = (arg[i] == '\0'); if (ok) switch (reg) { case 'A': mix_vm_set_rA (dis->vm, mix_word_new (value)); break; case 'X': mix_vm_set_rX (dis->vm, mix_word_new (value)); break; case 'J': if ( value >= 0 ) mix_vm_set_rJ (dis->vm, mix_short_new (value)); else ok = FALSE; break; case 'I': { guint k = arg[1] - '0'; if ( k < 7 ) mix_vm_set_rI (dis->vm, k, mix_short_new (value)); else ok = FALSE; } break; default: ok = FALSE; } } } if (!ok) { fprintf (dis->err, _("Invalid argument: %s\n"), arg); cmd_help_ (dis, "sreg"); } return ok; } static gboolean cmd_scmp_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) { gboolean ok = (strlen (arg) == 1); if (ok) switch (arg[0]) { case 'L': mix_vm_set_cmpflag (dis->vm, mix_LESS); break; case 'E': mix_vm_set_cmpflag (dis->vm, mix_EQ); break; case 'G': mix_vm_set_cmpflag (dis->vm, mix_GREAT); break; default: ok = FALSE; } if (!ok) { fprintf (dis->err, _("Invalid argument: %s\n"), arg); cmd_help_ (dis, "scmp"); } return ok; } static gboolean cmd_sover_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) { gboolean ok = (strlen (arg) == 1); if (ok) switch (arg[0]) { case 'T': mix_vm_set_overflow (dis->vm, TRUE); break; case 'F': mix_vm_set_overflow (dis->vm, FALSE); break; default: ok = FALSE; } if (!ok) { fprintf (dis->err, _("Invalid argument: %s\n"), arg); cmd_help_ (dis, "sover"); } return ok; } static gboolean cmd_smem_ (mix_vm_cmd_dispatcher_t *dis, const gchar *carg) { gboolean ok = (strlen (carg) > 2 && isdigit (carg[0])); gulong addr; glong value; int k = 0; gchar *arg = NULL; if (ok) { arg = g_strdup (carg); while (isdigit (arg[k])) k++; ok = isspace (arg[k]); if (ok) { arg[k++] = '\0'; addr = atol (arg); ok = addr < MIX_VM_CELL_NO; } if (ok) { while (isspace (arg[k])) k++; value = atol (arg + k); if ( arg[k] == '+' || arg[k] == '-' ) k++; while (isdigit (arg[k])) k++; ok = arg[k] == '\0'; } } if (ok) mix_vm_set_addr_contents (dis->vm, mix_short_new (addr), mix_word_new (value)); else { fprintf (dis->err, _("Invalid argument: %s\n"), arg); cmd_help_ (dis, "smem"); } g_free (arg); return ok; } static gboolean cmd_ssym_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) { gboolean result = FALSE; if (arg == NULL || strlen(arg) == 0) { fprintf (dis->err, _("Missing arguments\n")); cmd_help_ (dis, "ssym"); } else { gchar *a = g_strdup (arg); gchar *s = strtok (a, " \t"); gchar *w = strtok (NULL, " \t"); if (w != NULL && strtok (NULL, " \t") == NULL) { cmd_weval_ (dis, w); if (mix_eval_last_error (dis->eval) == MIX_EVAL_OK) { mix_eval_set_symbol (dis->eval, s, mix_eval_value (dis->eval)); result = TRUE; } } else { fprintf (dis->err, _("Wrong argument number\n")); cmd_help_ (dis, "ssym"); } g_free (a); } return result; } static gboolean cmd_sbp_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) { glong lineno; glong k = 0; while (isdigit (arg[k])) k++; if (arg[k] != '\0') { fprintf (dis->err, _("Invalid argument: %s\n"), arg); cmd_help_ (dis, "sbp"); return FALSE; } lineno = atol (arg); switch (k = mix_vm_set_breakpoint (dis->vm, lineno)) { case MIX_VM_BP_INV_LINE: fprintf (dis->err, _("Line number %ld too high\n"), lineno); break; case MIX_VM_BP_ERROR: fputs (_("Could not set breakpoint. Internal error\n"), dis->err); break; case MIX_VM_BP_NDEBUG: fputs (_("Could not set breakpoint. No debug info available\n"), dis->err); break; default: fprintf (dis->err, _("Breakpoint set at line %ld\n"), k); return TRUE; } return FALSE; } static gboolean cmd_sbpa_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) { glong address; glong k = 0; while (isdigit (arg[k])) k++; if (arg[k] != '\0') { fprintf (dis->err, _("Invalid argument: %s\n"), arg); cmd_help_ (dis, "sbpa"); return FALSE; } address = atol (arg); switch (mix_vm_set_breakpoint_address (dis->vm, address)) { case MIX_VM_BP_INV_ADDRESS: fprintf (dis->err, _("Invalid address %ld\n"), address); break; case MIX_VM_BP_ERROR: fputs (_("Could not set breakpoint. Internal error\n"), dis->err); break; default: fprintf (dis->err, _("Breakpoint set at address %ld\n"), address); return TRUE; } return FALSE; } static gboolean cmd_cbp_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) { glong lineno; int k = 0; while (isdigit (arg[k])) k++; if (arg[k] != '\0') { fprintf (dis->err, _("Invalid argument: %s\n"), arg); cmd_help_ (dis, "cbp"); return FALSE; } lineno = atol (arg); switch (mix_vm_clear_breakpoint (dis->vm, lineno)) { case MIX_VM_BP_INV_LINE: fprintf (dis->err, _("No breakpoint set at line %ld\n"), lineno); break; case MIX_VM_BP_ERROR: fputs (_("Could not set breakpoint. Internal error\n"), dis->err); break; case MIX_VM_BP_NDEBUG: fputs (_("No debug info available\n"), dis->err); break; case MIX_VM_BP_OK: fprintf (dis->err, _("Breakpoint cleared at line %ld\n"), lineno); return TRUE; default: g_assert_not_reached (); break; } return FALSE; } static gboolean cmd_cbpa_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) { glong address; glong k = 0; while (isdigit (arg[k])) k++; if (arg[k] != '\0') { fprintf (dis->err, _("Invalid argument: %s\n"), arg); cmd_help_ (dis, "cbpa"); return FALSE; } address = atol (arg); switch (mix_vm_clear_breakpoint_address (dis->vm, address)) { case MIX_VM_BP_INV_ADDRESS: fprintf (dis->err, _("Invalid address %ld\n"), address); break; case MIX_VM_BP_ERROR: fputs (_("Could not clear breakpoint. Internal error\n"), dis->err); break; default: fprintf (dis->err, _("Breakpoint cleared at address %ld\n"), address); return TRUE; } return FALSE; } static gboolean cmd_cabp_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) { if (strlen (arg) != 0) { fprintf (dis->err, _("Invalid argument: %s\n"), arg); cmd_help_ (dis, "cabp"); return FALSE; } mix_vm_clear_all_breakpoints (dis->vm); return TRUE; } static gboolean cmd_weval_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) { if ( strlen (arg) == 0 ) { cmd_help_ (dis, "weval"); return FALSE; } if (mix_eval_expression_with_loc (dis->eval, arg, mix_vm_get_prog_count (dis->vm)) == MIX_EVAL_OK) { mix_word_print_to_file (mix_eval_value (dis->eval), NULL, dis->out); putc ('\n', dis->out); return TRUE; } else { gint pos = mix_eval_last_error_pos (dis->eval); gint k, len = strlen (arg); g_assert(pos > -1 && pos <= len); for (k = 0; kerr); fputc ('\n', dis->err); for (k = 0; kerr); for (k = pos; k < len; ++k) fputc (arg[k], dis->err); fprintf (dis->err, _("\nEvaluation error: %s\n"), mix_eval_last_error_string (dis->eval)); return FALSE; } } static gboolean cmd_w2d_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) { if ( strlen (arg) == 0 ) { cmd_help_ (dis, "w2d"); return FALSE; } else { gchar *cp = g_strdup (arg), *a = cp; mix_byte_t bytes[5] = {0, 0, 0, 0, 0}; gchar *b; guint k = 0; gboolean is_n = (a[0] == '-'), success = TRUE; if (a[0] == '+' || a[0] == '-') ++a; b = strtok (a, " \t"); while (b != NULL && k < 5) { if (strlen (b) != 2 || !isdigit(b[0]) || !isdigit(b[1])) { fprintf (dis->err, _("Incorrect byte specification: %s\n"), b); success = FALSE; b = NULL; } else { bytes[k++] = mix_byte_new (atoi (b)); b = strtok (NULL, " \t"); } } if (success) { if (strtok (NULL, "\t") != NULL) { fprintf (dis->err, _("The expression %s does not fit in a word\n"), arg); success = FALSE; } else { mix_word_t w = mix_bytes_to_word (bytes, k); fprintf (dis->out, "%s%ld\n", is_n? "-":"+", mix_word_magnitude (w)); } } g_free (cp); return success; } } static gboolean cmd_tron_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) { dis->trace = TRUE; fprintf (dis->out, _("Instruction tracing has been turned ON.\n")); return TRUE; } static gboolean cmd_troff_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) { dis->trace = FALSE; fprintf (dis->out, _("Instruction tracing has been turned OFF.\n")); return TRUE; }