From ef4616f943c15d40cc2ff189b70e0ef6251af561 Mon Sep 17 00:00:00 2001 From: Jose Antonio Ortega Ruiz Date: Tue, 28 Aug 2001 16:38:06 +0000 Subject: guile integration --- .cvsignore | 1 + NEWS | 7 + configure.in | 3 +- mixgtk/Makefile.am | 10 +- mixgtk/gmixvm.c | 22 +- mixgtk/mixgtk_cmd_dispatcher.c | 63 +- mixgtk/mixgtk_mixvm.c | 2 +- mixguile/Makefile.am | 3 +- mixguile/mixguile.c | 46 +- mixguile/mixguile.h | 13 +- mixguile/mixguile_cmd_dispatcher.c | 91 +- mixguile/mixguile_main.c | 23 +- mixguile/xmixguile_cmd_dispatcher.c | 163 ++++ mixlib/Makefile.am | 4 +- mixlib/mix_config.c | 6 +- mixlib/mix_config.h | 3 + mixlib/mix_vm_command.c | 1586 +++++------------------------------ mixlib/mix_vm_command.h | 34 +- mixlib/xmix_vm_command.c | 31 + mixlib/xmix_vm_command.h | 92 ++ mixlib/xmix_vm_handlers.c | 1252 +++++++++++++++++++++++++++ mixlib/xmix_vm_handlers.h | 80 ++ mixutils/Makefile.am | 7 +- mixutils/mixvm.c | 4 +- mixutils/mixvm_command.c | 176 ++-- mixutils/mixvm_command.h | 3 +- mixutils/mixvm_loop.c | 27 +- po/ChangeLog | 20 + 28 files changed, 2181 insertions(+), 1591 deletions(-) create mode 100644 mixlib/xmix_vm_command.c create mode 100644 mixlib/xmix_vm_command.h create mode 100644 mixlib/xmix_vm_handlers.c create mode 100644 mixlib/xmix_vm_handlers.h diff --git a/.cvsignore b/.cvsignore index 90946fb..7387927 100644 --- a/.cvsignore +++ b/.cvsignore @@ -1,4 +1,5 @@ .emacs.desktop +.todo GPATH GRTAGS GSYMS diff --git a/NEWS b/NEWS index 9a653af..326af04 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,13 @@ See the end for copying conditions. Please send mdk bug reports to bug-mdk@gnu.org. +--------------------------------------------------------------------------- +* Version 0.5 + +** Added guile support. New utility 'mixguile'... + +** Bug fix: help messages are now correctly aligned in (g)mixvm. + --------------------------------------------------------------------------- * Version 0.4.2 (17/08/01) diff --git a/configure.in b/configure.in index 9e143f4..704662e 100644 --- a/configure.in +++ b/configure.in @@ -79,6 +79,7 @@ if test x$wguile = xtrue; then GUILE_LDFLAGS="`guile-config link`" LIBS="$LIBS $GUILE_LDFLAGS" CFLAGS="$CFLAGS $GUILE_CFLAGS" + AC_SUBST(MAKE_GUILE) AC_MSG_RESULT(yes) fi @@ -110,7 +111,7 @@ dnl Check for libglade if test x$gui = xtrue; then AM_PATH_LIBGLADE([LIBS="$LIBS $LIBGLADE_LIBS" CFLAGS="$CFLAGS $LIBGLADE_CFLAGS"], - [(Cannot find libglade: the GUI shall not be built) gui=false]) + gui=false) fi dnl use the provided getopt if gnu getopt is not available diff --git a/mixgtk/Makefile.am b/mixgtk/Makefile.am index 461a4ab..36af4b2 100644 --- a/mixgtk/Makefile.am +++ b/mixgtk/Makefile.am @@ -16,14 +16,20 @@ XPMS = clear.xpm colors.xpm compile.xpm edit.xpm font.xpm fontl.xpm \ EXTRA_DIST = mixgtk.glade $(XPMS) +if MAKE_GUILE +GUILED = -DMAKE_GUILE +else +GUILED = +endif if MAKE_GUI pkgdata_DATA = mixgtk.glade $(XPMS) INCLUDES = -I$(includedir) -DGLADE_FILE=\""$(pkgdatadir)/mixgtk.glade"\"\ - -DLOCAL_GLADE_FILE=\"mixgtk.glade\" -LDADD = $(top_builddir)/mixlib/libmix.a $(top_builddir)/lib/libreplace.a $(INTLLIBS) + -DLOCAL_GLADE_FILE=\"mixgtk.glade\" $(GUILED) +LDADD = $(top_builddir)/mixlib/libmix.a $(top_builddir)/lib/libreplace.a\ + $(top_builddir)/mixguile/libmixguile.a $(INTLLIBS) bin_PROGRAMS = gmixvm gmixvm_SOURCES = gmixvm.c mixgtk.h mixgtk.c \ diff --git a/mixgtk/gmixvm.c b/mixgtk/gmixvm.c index 6326957..59b4b41 100644 --- a/mixgtk/gmixvm.c +++ b/mixgtk/gmixvm.c @@ -24,13 +24,31 @@ #include #include "mixgtk.h" + +#ifdef MAKE_GUILE +# include +# include "mixgtk_cmd_dispatcher.h" +static void +inner_main_ (int argc, char *argv[]) +{ + mixgtk_init (argc, argv); + mixguile_set_cmd_dispatcher (mixgtk_cmd_dispatcher_get_mix_dispatcher ()); + mixguile_load_bootstrap (); + mixgtk_main (); + mixgtk_release (); +} +#endif + int main(int argc, char *argv[]) { +#ifdef MAKE_GUILE + mixguile_enter (argc, argv, inner_main_); +#else if (!mixgtk_init (argc, argv)) return EXIT_FAILURE; - mixgtk_main (); mixgtk_release (); - +#endif + return EXIT_SUCCESS; } diff --git a/mixgtk/mixgtk_cmd_dispatcher.c b/mixgtk/mixgtk_cmd_dispatcher.c index 8d2d0a7..01e549b 100644 --- a/mixgtk/mixgtk_cmd_dispatcher.c +++ b/mixgtk/mixgtk_cmd_dispatcher.c @@ -35,6 +35,10 @@ # include #endif +#ifdef MAKE_GUILE +# include +#endif + #include #include #include "mixgtk_mixvm.h" @@ -53,7 +57,6 @@ typedef struct mixgtk_dispatch_ GtkWidget *log; /* the dispatcher's messages echo area */ GtkWidget *status; /* the status bar widget */ guint context; /* context of the status bar messages */ - GCompletion *completions; /* mixvm command completions */ gchar *last_file; } mixgtk_dispatch_data_t; @@ -99,19 +102,7 @@ flush_log_ (mixgtk_dispatch_data_t *dis) } } -/* completions */ -static void -init_completions_ (void) -{ - GList *cmds = NULL; - gint k; - - dis_data_.completions = g_completion_new (NULL); - for (k = 0; k < MIX_CMD_INVALID; ++k) - cmds = g_list_append (cmds, (gpointer) mix_vm_command_to_string (k)); - g_completion_add_items (dis_data_.completions, cmds); -} - +/* hooks */ static void global_post_hook_ (mix_vm_cmd_dispatcher_t *dis, mix_vm_command_t cmd, const gchar *arg, gpointer data) @@ -323,10 +314,10 @@ mixgtk_cmd_dispatcher_init (mixgtk_dialog_id_t top) int r = pipe (dis_data_.fildes); g_return_val_if_fail (r == 0, FALSE); - /* connect stdout/stderr to the pipe's write end + /* connect stdout/stderr to the pipe's write end */ if (dup2 (dis_data_.fildes[1], STDOUT_FILENO) == -1 || dup2 (dis_data_.fildes[1], STDERR_FILENO) == -1) - return FALSE;*/ + return FALSE; dis_data_.out = fdopen (dis_data_.fildes[1], "w"); g_return_val_if_fail (dis_data_.out != NULL, FALSE); r = fcntl (dis_data_.fildes[0], F_GETFL, 0); @@ -355,19 +346,32 @@ mixgtk_cmd_dispatcher_init (mixgtk_dialog_id_t top) dis_data_.context = gtk_statusbar_get_context_id (GTK_STATUSBAR (dis_data_.status), "cmd_dis_context"); - if (!dis_data_.completions) init_completions_ (); if (!restart) read_config_ (); if (dis_data_.last_file) gtk_window_set_title (GTK_WINDOW (mixgtk_widget_factory_get_dialog (MIXGTK_MAIN)), dis_data_.last_file); - restart = TRUE; return TRUE; } /* dispatch an externally provided command */ +#ifdef MAKE_GUILE +static gboolean +try_guile_ (const gchar *command) +{ + if (command && command[0] == '(' && command[strlen (command) - 1] == ')') + { + mixguile_interpret_command (command); + return TRUE; + } + return FALSE; +} +#else +# define try_guile_(ignored) FALSE +#endif + void mixgtk_cmd_dispatcher_dispatch (const gchar *command) { @@ -376,7 +380,8 @@ mixgtk_cmd_dispatcher_dispatch (const gchar *command) g_assert (entry != NULL); gtk_entry_set_text (GTK_ENTRY (entry), command); log_command_ (&dis_data_, command); - mix_vm_cmd_dispatcher_dispatch_text (dis_data_.dispatcher, command); + if (!try_guile_ (command)) + mix_vm_cmd_dispatcher_dispatch_text (dis_data_.dispatcher, command); gtk_entry_set_text (GTK_ENTRY (entry), ""); } @@ -419,26 +424,26 @@ complete_command_ (void) { GtkEntry *entry = GTK_ENTRY (dis_data_.prompt); gchar *prefix = NULL; - gchar *text = g_strchomp (gtk_entry_get_text (entry)); - GList *cmds = g_completion_complete (dis_data_.completions, text, &prefix); + gchar *text = gtk_entry_get_text (entry); + const GList *cmds = + mix_vm_cmd_dispatcher_complete (dis_data_.dispatcher, text, &prefix); if (prefix != NULL) { gtk_entry_set_text (entry, prefix); g_free (prefix); - if (g_list_length (cmds) > 1) + if (g_list_length ((GList *)cmds) > 1) { + static gchar BUFFER[25]; gint k = 0; gtk_text_insert (GTK_TEXT (dis_data_.log), NULL, NULL, NULL, "Completions:\n", -1); while (cmds) { + snprintf (BUFFER, 25, "%-12s", (const char*)cmds->data); ++k; gtk_text_insert (GTK_TEXT (dis_data_.log), - NULL, NULL, NULL, - (gchar *)(cmds->data), -1); - gtk_text_insert (GTK_TEXT (dis_data_.log), - NULL, NULL, NULL, " ", -1); + NULL, NULL, NULL, BUFFER, -1); if (k%5 == 0) gtk_text_insert (GTK_TEXT (dis_data_.log), NULL, NULL, NULL, "\n", -1); @@ -454,7 +459,6 @@ complete_command_ (void) } } - int on_command_prompt_key_press_event (GtkEntry *w, GdkEventKey *e, gpointer d) { @@ -486,11 +490,12 @@ on_command_prompt_key_press_event (GtkEntry *w, GdkEventKey *e, gpointer d) if (key == GDK_Return) { - gchar *text = gtk_entry_get_text (w); + gchar *text = g_strstrip (gtk_entry_get_text (w)); if (text && *text) { log_command_ (&dis_data_, text); - mix_vm_cmd_dispatcher_dispatch_text (dis_data_.dispatcher, text); + if (!try_guile_ (text)) + mix_vm_cmd_dispatcher_dispatch_text (dis_data_.dispatcher, text); gtk_entry_set_text (w, ""); } return TRUE; diff --git a/mixgtk/mixgtk_mixvm.c b/mixgtk/mixgtk_mixvm.c index f492110..0d776fc 100644 --- a/mixgtk/mixgtk_mixvm.c +++ b/mixgtk/mixgtk_mixvm.c @@ -235,7 +235,7 @@ void mixgtk_mixvm_update_cells_to_address (gint address) { g_assert (memory_); - g_return_if_fail (address < MIX_VM_CELL_NO); + if (address >= MIX_VM_CELL_NO) return; gtk_clist_freeze (memory_); gtk_clist_moveto (memory_, address, 0, 0, 0); diff --git a/mixguile/Makefile.am b/mixguile/Makefile.am index 392b08d..fed3371 100644 --- a/mixguile/Makefile.am +++ b/mixguile/Makefile.am @@ -22,14 +22,13 @@ SCM_PATHS = -DSCM_FILE=\""$(pkgdatadir)/mixguile.scm"\"\ -DLOCAL_SCM_FILE=\"mixguile.scm\" pkgdata_DATA = $(SCM_FILES) - +INCLUDES = -I$(includedir) $(SCM_PATHS) libmixguile_a_INCLUDES = -I$(includedir) -DG_LOG_DOMAIN=\"libmixguile\" libmixguile_a_SOURCES = mixguile.h mixguile.c \ mixguile_cmd_dispatcher.h mixguile_cmd_dispatcher.c \ xmixguile_cmd_dispatcher.h xmixguile_cmd_dispatcher.c bin_PROGRAMS = mixguile -mixguile_INCLUDES = -I$(includedir) $(SCM_PATHS) mixguile_LDADD = $(top_builddir)/mixlib/libmix.a \ $(top_builddir)/lib/libreplace.a \ $(top_builddir)/mixguile/libmixguile.a $(INTLLIBS) diff --git a/mixguile/mixguile.c b/mixguile/mixguile.c index 52321ca..4072869 100644 --- a/mixguile/mixguile.c +++ b/mixguile/mixguile.c @@ -21,31 +21,70 @@ * */ +#include #include "mixguile_cmd_dispatcher.h" #include "mixguile.h" static mixguile_cmd_dispatcher_t *dispatcher_ = NULL; +static mix_vm_cmd_dispatcher_t *vm_dispatcher_ = NULL; static main_func_t main_fun_; /* do local initialisation and enter the user provided main */ + static void real_main_ (int argc, char *argv[]) { + if (vm_dispatcher_) + { + mixguile_set_cmd_dispatcher (vm_dispatcher_); + mixguile_load_bootstrap (); + } (*main_fun_)(argc, argv); } /* initialise the guile command dispatcher and enter the provided - main function. the mixlib is also initialised. + main function. */ void -mixguile_init (int argc, char *argv[], main_func_t main_fun) +mixguile_init (int argc, char *argv[], main_func_t main_fun, + mix_vm_cmd_dispatcher_t *dis) { - mix_init_lib (); main_fun_ = main_fun; + vm_dispatcher_ = dis; gh_enter (argc, argv, real_main_); } +/* load bootstrap file */ +void +mixguile_load_bootstrap (void) +{ + FILE *scm = NULL; + const gchar *scmfile = SCM_FILE; + gchar *lscmfile = + g_strconcat (g_get_home_dir (), G_DIR_SEPARATOR_S, MIX_CONFIG_DIR, + G_DIR_SEPARATOR_S, LOCAL_SCM_FILE, NULL); + + if (!(scm = fopen (scmfile, "r")) + && !(scm = fopen ((scmfile = LOCAL_SCM_FILE), "r"))) + { + g_warning ("mixguile bootstrap file %s not found\n", SCM_FILE); + scmfile = NULL; + } + else + fclose (scm); + + if (scmfile) mixguile_interpret_file (scmfile); + + if ((scm = fopen (lscmfile, "r")) != NULL) + { + fclose (scm); + mixguile_interpret_file (lscmfile); + } + + g_free (lscmfile); +} + /* enter the guile repl */ void mixguile_enter_repl (int argc, char *argv[]) @@ -60,6 +99,7 @@ mixguile_set_cmd_dispatcher (mix_vm_cmd_dispatcher_t *dis) { g_return_if_fail (dis != NULL); if (dispatcher_) mixguile_cmd_dispatcher_delete (dispatcher_); + vm_dispatcher_ = dis; dispatcher_ = mixguile_cmd_dispatcher_new (dis); g_assert (dispatcher_); } diff --git a/mixguile/mixguile.h b/mixguile/mixguile.h index 8897d29..6cc7918 100644 --- a/mixguile/mixguile.h +++ b/mixguile/mixguile.h @@ -32,12 +32,21 @@ /* the main function type */ typedef void (*main_func_t) (int argc, char *argv[]); + +/* enter and do the initialisation manually inside the guile world */ +#define mixguile_enter(argc,argv,main_fun) gh_enter (argc, argv, main_fun) + +/* load mixguile startup file */ +extern void +mixguile_load_bootstrap (); + /* initialise the guile command dispatcher and enter the provided - main function. the mixlib is also initialised. + main function. */ extern void -mixguile_init (int argc, char *argv[], main_func_t main_fun); +mixguile_init (int argc, char *argv[], main_func_t main_fun, + mix_vm_cmd_dispatcher_t *dis); /* set the command dispatcher */ extern void diff --git a/mixguile/mixguile_cmd_dispatcher.c b/mixguile/mixguile_cmd_dispatcher.c index 4676c43..b55d0ed 100644 --- a/mixguile/mixguile_cmd_dispatcher.c +++ b/mixguile/mixguile_cmd_dispatcher.c @@ -30,14 +30,56 @@ #include "mixguile.h" #include "xmixguile_cmd_dispatcher.h" +#define SCM_CMD "scm" +#define SCMF_CMD "scmf" + +/*local commands */ +static gboolean +cmd_scm_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + (void) gh_eval_str_with_catch ((char *)arg, scm_handle_by_message_noexit); + return TRUE; +} + +static gboolean +cmd_scmf_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + (void) gh_eval_file_with_catch ((char *)arg, scm_handle_by_message_noexit); + return TRUE; +} + +static mix_vm_command_info_t commands_[] = { + { SCM_CMD, cmd_scm_, N_("Eval Scheme command using Guile"), "scm COMMAND"}, + { SCMF_CMD, cmd_scmf_, N_("Eval Scheme file using Guile"), "scm PATH"}, + {NULL} +}; + /* create/destroy cmd dispatcher */ +static void +make_pipe_ (mixguile_cmd_dispatcher_t *dis) +{ + int fildes[2], r; + FILE *out; + r = pipe (fildes); + g_return_if_fail (r == 0); + out = fdopen (fildes[1], "w"); + g_return_if_fail (out != NULL); + r = fcntl (fildes[0], F_GETFL, 0); + g_return_if_fail (r != -1); + r = fcntl (fildes[0], F_SETFL, r | O_NONBLOCK); + g_return_if_fail (r != -1); + + dis->guile_out = out; + dis->fildes[0] = fildes[0]; + dis->fildes[1] = fildes[1]; +} + mixguile_cmd_dispatcher_t * mixguile_cmd_dispatcher_new (mix_vm_cmd_dispatcher_t *dis) { static gboolean REGISTERED = FALSE; mixguile_cmd_dispatcher_t *result = NULL; - int fildes[2], r; - FILE *out; + int k = 0; g_return_val_if_fail (dis != NULL, NULL); @@ -46,23 +88,19 @@ mixguile_cmd_dispatcher_new (mix_vm_cmd_dispatcher_t *dis) register_scm_commands_ (DEFAULT_SCM_COMMANDS_); REGISTERED = TRUE; } - - r = pipe (fildes); - g_return_val_if_fail (r == 0, NULL); - out = fdopen (fildes[1], "w"); - g_return_val_if_fail (out != NULL, NULL); - r = fcntl (fildes[0], F_GETFL, 0); - g_return_val_if_fail (r != -1, NULL); - r = fcntl (fildes[0], F_SETFL, r | O_NONBLOCK); - g_return_val_if_fail (r != -1, NULL); result = g_new (mixguile_cmd_dispatcher_t, 1); result->dispatcher = dis; result->err = result->out = NULL; - result->guile_out = out; - result->fildes[0] = fildes[0]; - result->fildes[1] = fildes[1]; result->result = NULL; + result->fildes[0] = result->fildes[1] = -1; + result->guile_out = NULL; + + while (commands_[k].name) + { + mix_vm_cmd_dispatcher_register_new (dis, commands_ + k); + ++k; + } register_cmd_dispatcher_ (result); @@ -74,9 +112,12 @@ void mixguile_cmd_dispatcher_delete (mixguile_cmd_dispatcher_t *dis) { g_return_if_fail (dis != NULL); - fclose (dis->guile_out); - close (dis->fildes[0]); - close (dis->fildes[1]); + if (dis->guile_out) + { + fclose (dis->guile_out); + close (dis->fildes[0]); + close (dis->fildes[1]); + } mix_vm_cmd_dispatcher_delete (dis->dispatcher); } @@ -99,6 +140,7 @@ mixguile_cmd_dispatcher_last_result (mixguile_cmd_dispatcher_t *dis) gchar *tmp = NULL; g_return_val_if_fail (dis != NULL, NULL); + if (!dis->guile_out) return NULL; if (dis->result) g_free (dis->result); dis->result = NULL; fflush (dis->guile_out); @@ -124,6 +166,7 @@ mixguile_cmd_dispatcher_last_result (mixguile_cmd_dispatcher_t *dis) static void prepare_dispatcher_ (mixguile_cmd_dispatcher_t *dis) { + if (!dis->guile_out) make_pipe_ (dis); dis->out = mix_vm_cmd_dispatcher_set_out_stream (dis->dispatcher, dis->guile_out); dis->err = mix_vm_cmd_dispatcher_set_error_stream (dis->dispatcher, @@ -137,14 +180,14 @@ mixguile_cmd_dispatcher_prepare (mixguile_cmd_dispatcher_t *dis) prepare_dispatcher_ (dis); } -/* interpret commands from file or string */ +/* interpret commands from file or string static void reset_dispatcher_ (mixguile_cmd_dispatcher_t *dis) { (void) mix_vm_cmd_dispatcher_set_out_stream (dis->dispatcher, dis->out); (void) mix_vm_cmd_dispatcher_set_error_stream (dis->dispatcher, dis->err); } - +*/ void mixguile_cmd_dispatcher_interpret_file (mixguile_cmd_dispatcher_t *dis, @@ -152,9 +195,8 @@ mixguile_cmd_dispatcher_interpret_file (mixguile_cmd_dispatcher_t *dis, { g_return_if_fail (dis != NULL); g_return_if_fail (path != NULL); - prepare_dispatcher_ (dis); - (void) gh_eval_file ((char *)path); - reset_dispatcher_ (dis); + mix_vm_cmd_dispatcher_dispatch_split_text (dis->dispatcher, + SCMF_CMD, path); } void @@ -163,8 +205,7 @@ mixguile_cmd_dispatcher_interpret_command (mixguile_cmd_dispatcher_t *dis, { g_return_if_fail (dis != NULL); g_return_if_fail (command != NULL); - prepare_dispatcher_ (dis); - (void) gh_eval_str ((char *)command); - reset_dispatcher_ (dis); + mix_vm_cmd_dispatcher_dispatch_split_text (dis->dispatcher, + SCM_CMD, command); } diff --git a/mixguile/mixguile_main.c b/mixguile/mixguile_main.c index de9bfa4..183dfaf 100644 --- a/mixguile/mixguile_main.c +++ b/mixguile/mixguile_main.c @@ -25,20 +25,19 @@ #include #include "mixguile.h" -static void -inner_main_ (int argc, char *argv[]) -{ - mix_vm_cmd_dispatcher_t *dis = mix_vm_cmd_dispatcher_new (stdout, stderr); - mixguile_set_cmd_dispatcher (dis); - mixguile_enter_repl (argc, argv); -} - int main (int argc, char *argv[]) { - mixguile_init (argc, argv, inner_main_); - return EXIT_SUCCESS; /* never reached */ -} - + const gchar *CONFIG_FILE = "mixvm.config"; + mix_config_t *config; + mix_vm_cmd_dispatcher_t *dis; + + + mix_init_lib (); + config = mix_config_new (NULL, CONFIG_FILE); + dis = mix_vm_cmd_dispatcher_new_with_config (stdout, stderr, config); + mixguile_init (argc, argv, mixguile_enter_repl, dis); + return EXIT_SUCCESS; /* never reached */ +} diff --git a/mixguile/xmixguile_cmd_dispatcher.c b/mixguile/xmixguile_cmd_dispatcher.c index 711bc52..744b76b 100644 --- a/mixguile/xmixguile_cmd_dispatcher.c +++ b/mixguile/xmixguile_cmd_dispatcher.c @@ -218,6 +218,12 @@ mix_set_over_ (SCM over) return gh_symbol2scm ("ok"); } +static SCM +mix_loc_ (void) +{ + return gh_long2scm (mix_vm_get_prog_count (vm_)); +} + static SCM mix_cmp_ (void) { @@ -261,6 +267,158 @@ mix_set_cmp_ (SCM value) return gh_symbol2scm ("ok"); } +/* ----- hook functions ---- */ +/* auxiliar arg list maker */ +static SCM +make_arg_list_ (const gchar *arg) +{ + gchar **arglist = g_strsplit (arg, " ", -1); + SCM argument = gh_list (SCM_UNDEFINED); + if (arglist && arglist[0]) + { + int k = 0; + while (arglist[k]) + argument = gh_cons (gh_str02scm (arglist[k++]), argument); + argument = gh_reverse (argument); + } + g_strfreev (arglist); + return argument; +} + +/* command hook auxiliar functions and types */ +/* +static SCM +hook_error_handler_ (void *data, SCM tag, SCM args) +{ + int len; + mix_vm_cmd_dispatcher_t *dis = (mix_vm_cmd_dispatcher_t *)dis; + gchar *argstr = gh_scm2newstr (args, &len); + fprintf (mix_vm_cmd_dispatcher_get_err_stream (dis), "Error in hook: %s\n", + argstr); + g_free (argstr); + return SCM_BOOL_T; +} +*/ + +typedef struct +{ + SCM function; + SCM args; +} hook_data_t; + +static SCM +hook_catch_body_ (void *data) +{ + hook_data_t *h = (hook_data_t *)data; + return gh_call1 (h->function, h->args); +} + +static void +scm_hook_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg, gpointer data) +{ + hook_data_t h; + h.function = (SCM) data; + h.args = make_arg_list_ (arg); + gh_catch (SCM_BOOL_T, hook_catch_body_, &h, + scm_handle_by_message_noexit, dis); +} + +/* global hook auxiliar functions and types */ +typedef struct +{ + SCM function; + SCM cmd; + SCM args; +} global_hook_data_t; + +static SCM +global_hook_catch_body_ (void *data) +{ + global_hook_data_t *h = (global_hook_data_t *)data; + return gh_call2 (h->function, h->cmd, h->args); +} + +static void +scm_global_hook_ (mix_vm_cmd_dispatcher_t *dis, mix_vm_command_t cmd, + const gchar *arg, gpointer data) +{ + global_hook_data_t h; + h.function = (SCM) data; + h.cmd = gh_str02scm ((char *)mix_vm_command_to_string (cmd)); + h.args = make_arg_list_ (arg); + gh_catch (SCM_BOOL_T, global_hook_catch_body_, &h, + scm_handle_by_message_noexit, NULL); +} + +static SCM +mix_add_hook_ (SCM cmd, SCM function, gboolean pre) +{ + gchar *cmdstr = NULL; + mix_vm_command_t command; + int len; + const gchar *fun = pre? "mix-add-pre-hook" : "mix-add-post-hook"; + + SCM_ASSERT (SCM_STRINGP (cmd) || SCM_SYMBOLP (cmd), cmd, SCM_ARG1, fun); + SCM_ASSERT (gh_procedure_p (function), function, SCM_ARG2, fun); + SCM_DEFER_INTS; + cmdstr = gh_scm2newstr (cmd, &len); + command = mix_vm_command_from_string (cmdstr); + g_free (cmdstr); + SCM_ALLOW_INTS; + SCM_ASSERT (command != MIX_CMD_INVALID, cmd, SCM_ARG1, fun); + SCM_DEFER_INTS; + if (pre) + mix_vm_cmd_dispatcher_pre_hook (vm_dispatcher_, command, + scm_hook_, (gpointer) function); + else + mix_vm_cmd_dispatcher_post_hook (vm_dispatcher_, command, + scm_hook_, (gpointer) function); + SCM_ALLOW_INTS; + return gh_symbol2scm ("ok"); +} + +static SCM +mix_add_global_hook_ (SCM function, gboolean pre) +{ + const gchar *fun = + pre? "mix-add-global-pre-hook" : "mix-add-global-post-hook"; + + SCM_ASSERT (gh_procedure_p (function), function, SCM_ARG1, fun); + SCM_DEFER_INTS; + if (pre) + mix_vm_cmd_dispatcher_global_pre_hook (vm_dispatcher_, scm_global_hook_, + (gpointer) function); + else + mix_vm_cmd_dispatcher_global_post_hook (vm_dispatcher_, scm_global_hook_, + (gpointer) function); + SCM_ALLOW_INTS; + return gh_symbol2scm ("ok"); +} + +static SCM +mix_add_pre_hook_ (SCM cmd, SCM function) +{ + return mix_add_hook_ (cmd, function, TRUE); +} + +static SCM +mix_add_post_hook_ (SCM cmd, SCM function) +{ + return mix_add_hook_ (cmd, function, FALSE); +} + +static SCM +mix_add_global_pre_hook_ (SCM function) +{ + return mix_add_global_hook_ (function, TRUE); +} + +static SCM +mix_add_global_post_hook_ (SCM function) +{ + return mix_add_global_hook_ (function, FALSE); +} + /* NULL-terminated list of available scm commands */ const scm_command_t DEFAULT_SCM_COMMANDS_[] = { {"mixvm-cmd", mixvm_cmd_, 2, 0, 0}, @@ -269,8 +427,13 @@ const scm_command_t DEFAULT_SCM_COMMANDS_[] = { {"mix-cell", mix_cell_, 1, 0, 0}, {"mix-set-cell!", mix_set_cell_, 2, 0, 0}, {"mix-over", mix_over_, 0, 0, 0}, + {"mix-loc", mix_loc_, 0, 0, 0}, {"mix-set-over!", mix_set_over_, 1, 0, 0}, {"mix-cmp", mix_cmp_, 0, 0, 0}, {"mix-set-cmp!", mix_set_cmp_, 1, 0, 0}, + {"mix-add-pre-hook", mix_add_pre_hook_, 2, 0, 0}, + {"mix-add-post-hook", mix_add_post_hook_, 2, 0, 0}, + {"mix-add-global-pre-hook", mix_add_global_pre_hook_, 1, 0, 0}, + {"mix-add-global-post-hook", mix_add_global_post_hook_, 1, 0, 0}, {NULL} }; diff --git a/mixlib/Makefile.am b/mixlib/Makefile.am index 475fad3..3b51a0e 100644 --- a/mixlib/Makefile.am +++ b/mixlib/Makefile.am @@ -11,7 +11,7 @@ # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. SUBDIRS = testsuite -INCLUDES = -I$(includedir) -DG_LOG_DOMAIN=\"libmix\" +INCLUDES = -I$(includedir) -DG_LOG_DOMAIN=\"libmix\" noinst_LIBRARIES = libmix.a libmix_a_SOURCES = mix.h mix.c \ @@ -29,6 +29,8 @@ libmix_a_SOURCES = mix.h mix.c \ mix_src_file.c mix_src_file.h \ mix_vm_clock.c mix_vm_clock.h \ mix_vm_command.c mix_vm_command.h \ + xmix_vm_command.c xmix_vm_command.h \ + xmix_vm_handlers.h xmix_vm_handlers.c \ mix_config.c mix_config.h \ mix_predicate.c mix_predicate.h \ mix_predicate_list.c mix_predicate_list.h diff --git a/mixlib/mix_config.c b/mixlib/mix_config.c index fd3505e..f55ee48 100644 --- a/mixlib/mix_config.c +++ b/mixlib/mix_config.c @@ -29,8 +29,9 @@ #include #include "mix_config.h" +const gchar *MIX_CONFIG_DIR = ".mdk"; + static const gchar COMMENT_PREFIX_ = '#'; -static const gchar *DEF_DIR_ = ".mdk"; static const gchar *AUTOSAVE_KEY_ = "Autosave"; static const gchar *AUTOSAVE_YES_ = "True"; static const gchar *AUTOSAVE_NO_ = "False"; @@ -58,7 +59,8 @@ mix_config_new (const gchar *dirname, const gchar *filename) mix_config_t *result = NULL; if (DEF_DIRNAME_ == NULL) - DEF_DIRNAME_ = g_strdup_printf ("%s/%s", g_get_home_dir (), DEF_DIR_); + DEF_DIRNAME_ = g_strconcat (g_get_home_dir (), G_DIR_SEPARATOR_S, + MIX_CONFIG_DIR, NULL); if (dirname == NULL) dirname = DEF_DIRNAME_; if (filename == NULL) filename = DEF_FILENAME_; diff --git a/mixlib/mix_config.h b/mixlib/mix_config.h index 47932e1..2f1b1a0 100644 --- a/mixlib/mix_config.h +++ b/mixlib/mix_config.h @@ -27,6 +27,9 @@ #include "mix.h" +/* default config dir */ +extern const gchar *MIX_CONFIG_DIR; + /* the config type */ typedef struct mix_config_t mix_config_t; diff --git a/mixlib/mix_vm_command.c b/mixlib/mix_vm_command.c index dd0bb2d..56f381d 100644 --- a/mixlib/mix_vm_command.c +++ b/mixlib/mix_vm_command.c @@ -21,18 +21,9 @@ * */ -#include -#include -#include -#include -#include - -#include "mix_device.h" -#include "mix_vm.h" -#include "mix_vm_dump.h" -#include "mix_eval.h" -#include "mix_predicate.h" -#include "mix_vm_command.h" + +#include "xmix_vm_command.h" +#include "xmix_vm_handlers.h" #ifdef HAVE_LIBHISTORY # include @@ -42,180 +33,34 @@ # include #endif -/* hooks */ -typedef struct +/* hook execution */ +static void +exec_hook_list_ (GSList *list, mix_vm_cmd_dispatcher_t *dis, const gchar *arg) { - mix_vm_cmd_hook_t func; - gpointer data; -} hook_; + while (list) + { + hook_ *hook = (hook_ *)list->data; + if (hook) + (hook->func)(dis, arg, hook->data); + list = list->next; + } +} -typedef struct +static void +exec_global_hook_list_ (GSList *list, + mix_vm_cmd_dispatcher_t *dis, + mix_vm_command_t cmd, const gchar *arg) { - mix_vm_cmd_global_hook_t func; - gpointer data; -} global_hook_; - -#define PRNO_ MIX_PRED_MEM + while (list) + { + global_hook_ *hook = (global_hook_ *)list->data; + if (hook) + (hook->func)(dis, cmd, arg, hook->data); + list = list->next; + } +} -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 */ - gchar *editor; /* edit command line template */ - gchar *assembler; /* compile command line template */ - 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 */ - mix_config_t *config; /* externally provided configuration */ - mix_predicate_t *preds[PRNO_]; /* predicates for conditional breakpoints */ - GHashTable *mem_preds; /* predicates for memory conditional bps */ -}; - -/* 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 (tracing_); -DEC_FUN (timing_); -DEC_FUN (edit_); -DEC_FUN (compile_); -DEC_FUN (pedit_); -DEC_FUN (sedit_); -DEC_FUN (pasm_); -DEC_FUN (sasm_); -DEC_FUN (devdir_); -DEC_FUN (sbpr_); -DEC_FUN (sbpm_); -DEC_FUN (sbpc_); -DEC_FUN (sbpo_); -DEC_FUN (cbpr_); -DEC_FUN (cbpm_); -DEC_FUN (cbpc_); -DEC_FUN (cbpo_); -DEC_FUN (pbt_); - - -/* 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"}, - { "edit", cmd_edit_, N_("Edit a MIXAL source file"), "edit [FILENAME]"}, - { "pedit", cmd_pedit_, N_("Print the external editor command"), "pedit"}, - { "sedit", cmd_sedit_, N_("Set the external editor command"), - "sedit COMMAND (e.g. emacs %s)"}, - { "compile", cmd_compile_, N_("Compile a MIXAL source file"), - "compile [FILENAME]"}, - { "pasm", cmd_pasm_, N_("Print the compile command"), "pasm"}, - { "sasm", cmd_sasm_, N_("Set the compile command"), - "sasm COMMAND (e.g. mixasm -g -l %s)"}, - { "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"}, - { "sbpr", cmd_sbpr_, N_("Set conditional breakpoint on register change"), - "sbpr A | X | J | I[1-6]"}, - { "cbpr", cmd_cbpr_, N_("Clear conditional breakpoint on register change"), - "sbpr A | X | J | I[1-6]"}, - { "sbpm", cmd_sbpm_, N_("Set conditional breakpoint on mem cell change"), - "sbpm ADDRESS"}, - { "cbpm", cmd_cbpm_, N_("Clear conditional breakpoint on mem cell change"), - "cbpm ADDRESS"}, - { "sbpc", cmd_sbpc_, - N_("Set conditional breakpoint on comparison flag change"), "sbpc"}, - { "cbpc", cmd_cbpc_, - N_("Clear conditional breakpoint on comparison flag change"), "cbpc"}, - { "sbpo", cmd_sbpo_, - N_("Set conditional breakpoint on overflow toggled"), "sbpo"}, - { "cbpo", cmd_cbpo_, - N_("Set conditional breakpoint on overflow toggled"), "cbpo"}, - { "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"}, - { "tracing", cmd_tracing_, N_("Turn on/off instruction tracing"), - "tracing [on|off]"}, - { "pbt", cmd_pbt_, N_("Print backtrace of executed instructions"), - "pbt [INS_NO] (e.g pbt 5)"}, - { "timing", cmd_timing_, N_("Turn on/off timing statistics"), - "timing [on|off]"}, - { "devdir", cmd_devdir_, N_("Print/set devices directory"), - "devdir [NEWDIR]"}, - { NULL, NULL, NULL, NULL}, -}; - -/* configuration keys */ -static const gchar *TRACING_KEY_ = "Tracing"; -static const gchar *TIMING_KEY_ = "Timing"; -static const gchar *EDITOR_KEY_ = "Editor"; -static const gchar *ASM_KEY_ = "Assembler"; - - -/* external interface */ + /* conversion from/to commands to strings */ const gchar * @@ -228,7 +73,6 @@ mix_vm_command_to_string (mix_vm_command_t cmd) 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; @@ -251,6 +95,19 @@ mix_vm_command_usage (mix_vm_command_t cmd) } /* create a new command dispatcher */ +static GCompletion * +make_completions_ (void) +{ + GList *cmds = NULL; + gint k; + + GCompletion *completions = g_completion_new (NULL); + for (k = 0; k < MIX_CMD_INVALID; ++k) + cmds = g_list_append (cmds, (gpointer) mix_vm_command_to_string (k)); + g_completion_add_items (completions, cmds); + return completions; +} + mix_vm_cmd_dispatcher_t * mix_vm_cmd_dispatcher_new (FILE *out_fd, /* output messages file */ FILE *err_fd /* error messages file */) @@ -275,19 +132,18 @@ mix_vm_cmd_dispatcher_new (FILE *out_fd, /* output messages file */ 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; + result->global_pre = result->global_post = 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; - } + result->pre_hooks[k] = result->post_hooks[k] = NULL; + result->config = NULL; for (k = 0; k < PRNO_; ++k) result->preds[k] = mix_predicate_new (k); result->mem_preds = g_hash_table_new (NULL, NULL); + result->commands = g_hash_table_new (g_str_hash, g_str_equal); + result->completions = make_completions_ (); return result; } @@ -341,6 +197,22 @@ del_pred_ (gpointer key, gpointer val, gpointer data) return TRUE; } +static void +del_hook_ (gpointer data, gpointer ignored) +{ + if (data) g_free (data); +} + +static void +del_hook_list_ (GSList *s) +{ + if (s) + { + g_slist_foreach (s, del_hook_, NULL); + g_slist_free (s); + } +} + void mix_vm_cmd_dispatcher_delete (mix_vm_cmd_dispatcher_t *dis) { @@ -361,10 +233,62 @@ mix_vm_cmd_dispatcher_delete (mix_vm_cmd_dispatcher_t *dis) for (k = 0; k < PRNO_; ++k) mix_predicate_delete (dis->preds[k]); g_hash_table_foreach_remove (dis->mem_preds, del_pred_, NULL); g_hash_table_destroy (dis->mem_preds); + g_hash_table_destroy (dis->commands); + g_completion_free (dis->completions); + for (k = 0; k < MIX_CMD_INVALID; ++k) + { + del_hook_list_ (dis->pre_hooks[k]); + del_hook_list_ (dis->post_hooks[k]); + } + del_hook_list_ (dis->global_pre); + del_hook_list_ (dis->global_post); g_free (dis); } +/* register new commands for a dispatcher */ +void +mix_vm_cmd_dispatcher_register_new (mix_vm_cmd_dispatcher_t *dis, + mix_vm_command_info_t *cmd) +{ + GList *list = NULL; + g_return_if_fail (dis != NULL); + g_return_if_fail (cmd != NULL); + g_hash_table_insert (dis->commands, (gpointer)cmd->name, (gpointer)cmd); + list = g_list_append (list, (gpointer)cmd->name); + g_completion_add_items (dis->completions, list); +} + +const GList * +mix_vm_cmd_dispatcher_complete (const mix_vm_cmd_dispatcher_t *dis, + const gchar *cmd, gchar **prefix) +{ + char *cp; + GList *result; + + g_return_val_if_fail (dis != NULL, NULL); + g_return_val_if_fail (cmd != NULL, NULL); + + cp = g_strdup (cmd); + result = g_completion_complete (dis->completions, cp, prefix); + g_free (cp); + return result; +} + /* set/get out/error streams */ +FILE * +mix_vm_cmd_dispatcher_get_out_stream (const mix_vm_cmd_dispatcher_t *dis) +{ + g_return_val_if_fail (dis, NULL); + return dis->out; +} + +FILE * +mix_vm_cmd_dispatcher_get_err_stream (const mix_vm_cmd_dispatcher_t *dis) +{ + g_return_val_if_fail (dis, NULL); + return dis->err; +} + FILE * /* old output stream */ mix_vm_cmd_dispatcher_set_out_stream (mix_vm_cmd_dispatcher_t *dis, FILE *out) { @@ -451,10 +375,16 @@ 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) { + hook_ *phook; + 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; + + phook = g_new (hook_, 1); + phook->func = hook; + phook->data = data; + + dis->pre_hooks[cmd] = g_slist_append (dis->pre_hooks[cmd], phook); } void @@ -462,10 +392,16 @@ 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) { + hook_ *phook; + 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; + + phook = g_new (hook_, 1); + phook->func = hook; + phook->data = data; + + dis->post_hooks[cmd] = g_slist_append (dis->post_hooks[cmd], phook); } void @@ -473,9 +409,15 @@ mix_vm_cmd_dispatcher_global_pre_hook (mix_vm_cmd_dispatcher_t *dis, mix_vm_cmd_global_hook_t hook, gpointer data) { + global_hook_ *phook; + g_return_if_fail (dis != NULL); - dis->global_pre.func = hook; - dis->global_pre.data = data; + + phook = g_new (global_hook_, 1); + phook->func = hook; + phook->data = data; + + dis->global_pre = g_slist_append (dis->global_pre, phook); } void @@ -483,9 +425,15 @@ mix_vm_cmd_dispatcher_global_post_hook (mix_vm_cmd_dispatcher_t *dis, mix_vm_cmd_global_hook_t hook, gpointer data) { + global_hook_ *phook; + g_return_if_fail (dis != NULL); - dis->global_post.func = hook; - dis->global_post.data = data; + + phook = g_new (global_hook_, 1); + phook->func = hook; + phook->data = data; + + dis->global_post = g_slist_append (dis->global_post, phook); } /* dispatch a command */ @@ -495,24 +443,35 @@ mix_vm_cmd_dispatcher_dispatch (mix_vm_cmd_dispatcher_t *dis, { 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 (dis->global_pre) + exec_global_hook_list_ (dis->global_pre, dis, cmd, arg); if (cmd < MIX_CMD_INVALID) { - if (dis->pre_hooks[cmd].func) - (dis->pre_hooks[cmd].func)(dis, arg, dis->pre_hooks[cmd].data); + if (dis->pre_hooks[cmd]) + exec_hook_list_ (dis->pre_hooks[cmd], dis, arg); + + fflush (dis->out); + fflush (dis->err); + 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); + + fflush (dis->out); + fflush (dis->err); + + if (dis->post_hooks[cmd]) + exec_hook_list_ (dis->post_hooks[cmd], dis, arg); + + fflush (dis->out); + fflush (dis->err); } else { fprintf (dis->err, "Unknown command. Try: help\n"); } - if (dis->global_post.func) - (dis->global_post.func)(dis, cmd, arg, dis->global_post.data); + if (dis->global_post) + exec_global_hook_list_ (dis->global_post, dis, cmd, arg); fflush (dis->out); fflush (dis->err); @@ -526,7 +485,6 @@ mix_vm_cmd_dispatcher_dispatch_text (mix_vm_cmd_dispatcher_t *dis, { gchar *cp, *arg = ""; int k = 0; - gboolean result; g_return_val_if_fail (dis != NULL, FALSE); g_return_val_if_fail (text != NULL, FALSE); @@ -540,13 +498,56 @@ mix_vm_cmd_dispatcher_dispatch_text (mix_vm_cmd_dispatcher_t *dis, arg = cp + k; } - result = mix_vm_cmd_dispatcher_dispatch (dis, - mix_vm_command_from_string (cp), - arg); + (void) mix_vm_cmd_dispatcher_dispatch_split_text (dis, cp, arg); + g_free (cp); - return result; + + return dis->result; +} + +/* dispatch a command in text format, with command and arg split */ +gboolean +mix_vm_cmd_dispatcher_dispatch_split_text (mix_vm_cmd_dispatcher_t *dis, + const gchar *command, + const gchar *arg) +{ + mix_vm_command_info_t *info; + + g_return_val_if_fail (dis, FALSE); + + if (!command) return FALSE; + if (!arg) arg = ""; + + info = (mix_vm_command_info_t *)g_hash_table_lookup (dis->commands, command); + + if (info) + { + if (dis->global_pre) + exec_global_hook_list_ (dis->global_pre, dis, MIX_CMD_LOCAL, arg); + + fflush (dis->out); + fflush (dis->err); + + dis->result = info->func (dis, arg); + + fflush (dis->out); + fflush (dis->err); + + if (dis->global_post) + exec_global_hook_list_ (dis->global_post, dis, MIX_CMD_LOCAL, arg); + + fflush (dis->out); + fflush (dis->err); + } + else + dis->result = + mix_vm_cmd_dispatcher_dispatch (dis, + mix_vm_command_from_string (command), + arg); + return dis->result; } + /* get the last dispatch's result */ gboolean mix_vm_cmd_dispatcher_get_last_result (const mix_vm_cmd_dispatcher_t *dis) @@ -595,1168 +596,3 @@ mix_vm_cmd_dispatcher_get_vm (const mix_vm_cmd_dispatcher_t *dis) 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 || !*arg) - { - fprintf (dis->out ,_("%s\t\t%s\n"), commands_[i].name, - _(commands_[i].doc)); - printed++; - } - else if ((strcmp (arg, commands_[i].name) == 0)) - { - fprintf (dis->out ,_("%s\t\t%s.\n\t\tUsage: %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_edit_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) -{ - if (dis->editor == NULL) - { - fputs (_("Editor not specified (set MDK_EDITOR)\n"), dis->err); - return FALSE; - } - if (!arg || *arg == '\0') arg = mix_vm_cmd_dispatcher_get_src_file_path (dis); - if (!arg) - { - fputs (_("MIXAL source file path not found\n"), dis->err); - return FALSE; - } - else - { - gchar *cmd = g_strdup_printf (dis->editor, arg); - fputs (cmd, dis->out); - system (cmd); - fputs (_(" ...done\n"), dis->out); - g_free (cmd); - return TRUE; - } -} - -static gboolean -cmd_compile_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) -{ - if (dis->assembler == NULL) - { - fputs (_("MIX assembler not specified\n"), dis->err); - return FALSE; - } - if (!arg || *arg == '\0') arg = mix_vm_cmd_dispatcher_get_src_file_path (dis); - if (!arg) - { - fputs (_("MIXAL source file path not found\n"), dis->err); - return FALSE; - } - else - { - gchar *cmd = g_strdup_printf (dis->assembler, arg); - fputs (cmd, dis->out); - fputs ("\n", dis->out); - if (system (cmd) == EXIT_SUCCESS) - fputs (_("Successful compilation\n"), dis->out); - g_free (cmd); - 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_COND_BREAK: - { - gulong line = mix_vm_get_break_lineno (dis->vm); - if (line != 0) - fprintf (dis->out, _("... stopped: %s (line %ld, address %d)\n"), - mix_vm_get_last_breakpoint_message (dis->vm), - line, mix_vm_get_prog_count (dis->vm)); - else - fprintf (dis->out, _("... stopped: %s (address %d)\n"), - mix_vm_get_last_breakpoint_message (dis->vm), - 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_to_file (mix_symbol_table_value (table, arg), - NULL, dis->out); - 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, dis->out, 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\n"), 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] == '-') - { - gchar *narg; - arg[i++] = '\0'; - begin = atol (arg); - narg = arg + i; - i = 0; - while (isdigit (narg[i])) - i++; - while (isspace (narg[i])) - i++; - if (narg[i] != '\0') - error = TRUE; - else - end = atol (narg); - } - 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])); - glong addr = -1; - glong value = 0; - 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"); - } - if (arg) 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_tracing_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) -{ - static const gchar *ON = "on"; - static const gchar *OFF = "off"; - if (arg && !strcmp (arg, ON)) - { - dis->trace = TRUE; - if (dis->config) mix_config_update (dis->config, TRACING_KEY_, ON); - } - else if (arg && !strcmp (arg, OFF)) - { - dis->trace = FALSE; - if (dis->config) mix_config_update (dis->config, TRACING_KEY_, OFF); - } - else if (arg && !strlen (arg)) - { - fprintf (dis->out, "Instruction tracing is currently set %s\n", - dis->trace ? "ON" : "OFF"); - } - else - cmd_help_ (dis, "tracing"); - return TRUE; -} - -static gboolean -cmd_timing_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) -{ - static const gchar *ON = "on"; - static const gchar *OFF = "off"; - if (arg && !strcmp (arg, ON)) - { - dis->printtime = TRUE; - if (dis->config) mix_config_update (dis->config, TIMING_KEY_, ON); - } - else if (arg && !strcmp (arg, OFF)) - { - dis->printtime = FALSE; - if (dis->config) mix_config_update (dis->config, TIMING_KEY_, OFF); - } - else if (arg && !strlen (arg)) - { - print_time_ (dis); - } - else - cmd_help_ (dis, "timing"); - return TRUE; -} - - -static gboolean -cmd_pedit_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) -{ - const gchar *ed = mix_vm_cmd_dispatcher_get_editor (dis); - if (dis) - fprintf (dis->out, "Edit command: %s\n", ed); - else - fprintf (dis->out, "Edit command not set (use sedit)\n"); - return TRUE; -} - -static gboolean -cmd_sedit_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) -{ - if (!arg || !strlen (arg)) return cmd_help_ (dis, "sedit"); - mix_vm_cmd_dispatcher_set_editor (dis, arg); - return TRUE; -} - -static gboolean -cmd_pasm_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) -{ - const gchar *ed = mix_vm_cmd_dispatcher_get_assembler (dis); - if (dis) - fprintf (dis->out, "Compile command: %s\n", ed); - else - fprintf (dis->out, "Compile command not set (use sasm)\n"); - return TRUE; -} - -static gboolean -cmd_sasm_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) -{ - if (!arg || !strlen (arg)) return cmd_help_ (dis, "sasm"); - mix_vm_cmd_dispatcher_set_assembler (dis, arg); - return TRUE; -} - -static gboolean -cmd_devdir_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) -{ - if (!arg || !strlen (arg)) - fprintf (dis->out, "Device directory: %s\n", mix_device_get_dir ()); - else if (mix_device_set_dir (arg) && dis->config) - mix_config_set_devices_dir (dis->config, arg); - return TRUE; -} - - -static const gint INVALID_REG_ = -2; - -static mix_predicate_type_t -get_reg_pred_ (const gchar *arg) -{ - mix_predicate_type_t pred = INVALID_REG_; - - switch (*arg) - { - case 'A': - pred = MIX_PRED_REG_A; - break; - case 'X': - pred = MIX_PRED_REG_X; - break; - case 'J': - pred = MIX_PRED_REG_J; - break; - case 'I': - { - if ( strlen (arg) == 2 ) - { - int i = arg[1] - '1'; - if (i >= 0 && i < 6) - pred = MIX_PRED_REG_I1 - 1 + i; - } - } - break; - default: - break; - } - return pred; -} - -static gboolean -cmd_sbpr_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) -{ - mix_predicate_type_t pred = get_reg_pred_ (arg); - if (pred != INVALID_REG_) - { - mix_vm_set_conditional_breakpoint (dis->vm, dis->preds[pred]); - fprintf (dis->out, _("Conditional breakpoint on r%s change set\n"), arg); - return TRUE; - } - else - { - fprintf (dis->err, "Invalid argument %s\n", arg); - return FALSE; - } -} - -static gboolean -cmd_cbpr_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) -{ - mix_predicate_type_t pred = get_reg_pred_ (arg); - if (pred != INVALID_REG_) - { - if (mix_vm_clear_conditional_breakpoint (dis->vm, dis->preds[pred])) - fprintf (dis->out, - _("Conditional breakpoint on r%s change removed\n"), - arg); - else - fprintf (dis->err, _("No breakpoint set on r%s change\n"), arg); - return TRUE; - } - else - { - fprintf (dis->err, _("Invalid argument %s\n"), arg); - return FALSE; - } -} - -static gboolean -cmd_sbpm_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) -{ - gint add = atoi (arg); - gpointer key, value; - if (add < 0 || add > MIX_VM_CELL_NO) - { - fprintf (dis->out, _("Invalid memory address: %s\n"), arg); - return FALSE; - } - if (!g_hash_table_lookup_extended (dis->mem_preds, GINT_TO_POINTER (add), - &key, &value)) - { - mix_predicate_t *new_pred = mix_predicate_new (MIX_PRED_MEM); - mix_predicate_set_mem_address (new_pred, add); - g_hash_table_insert (dis->mem_preds, - GINT_TO_POINTER (add), (gpointer)new_pred); - mix_vm_set_conditional_breakpoint (dis->vm, new_pred); - } - fprintf (dis->out, _("Conditional breakpoint on mem cell no. %d set\n"), add); - return TRUE; -} - -static gboolean -cmd_cbpm_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) -{ - gint add = atoi (arg); - gpointer key, value; - if (add < 0 || add > MIX_VM_CELL_NO) - { - fprintf (dis->out, _("Invalid memory address: %s\n"), arg); - return FALSE; - } - if (g_hash_table_lookup_extended (dis->mem_preds, GINT_TO_POINTER (add), - &key, &value)) - { - g_hash_table_remove (dis->mem_preds, key); - mix_vm_clear_conditional_breakpoint (dis->vm, (mix_predicate_t *)value); - mix_predicate_delete ((mix_predicate_t *)value); - fprintf (dis->out, - _("Conditional breakpoint on mem cell no. %d removed\n"), add); - } - else - { - fprintf (dis->out, _("No conditional breakpoint set at address %d\n"), - add); - } - return TRUE; -} - -static gboolean -cmd_sbpo_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) -{ - if (arg && strlen (arg)) - fprintf (dis->err, _("Unexpected argument: %s\n"), arg); - else - { - mix_vm_set_conditional_breakpoint (dis->vm, dis->preds[MIX_PRED_OVER]); - fprintf (dis->out, - _("Conditional breakpoint on overflow toggled set\n")); - } - return TRUE; -} - -static gboolean -cmd_cbpo_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) -{ - if (arg && strlen (arg)) - fprintf (dis->err, _("Unexpected argument: %s\n"), arg); - else - { - if (mix_vm_clear_conditional_breakpoint - (dis->vm, dis->preds[MIX_PRED_OVER])) - fprintf (dis->out, - _("Conditional breakpoint on overflow toggled removed.\n")); - else - fprintf (dis->err, _("No breakpoint set on overflow toggle\n")); - } - return TRUE; -} - -static gboolean -cmd_sbpc_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) -{ - if (arg && strlen (arg)) - fprintf (dis->err, _("Unexpected argument: %s\n"), arg); - else - { - mix_vm_set_conditional_breakpoint (dis->vm, dis->preds[MIX_PRED_CMP]); - fprintf (dis->out, - _("Conditional breakpoint on comparison flag changed set.\n")); - } - return TRUE; -} - -static gboolean -cmd_cbpc_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) -{ - if (arg && strlen (arg)) - fprintf (dis->err, _("Unexpected argument: %s\n"), arg); - else - { - if (mix_vm_clear_conditional_breakpoint - (dis->vm, dis->preds[MIX_PRED_CMP])) - fprintf - (dis->out, - _("Conditional breakpoint on comparison flag changed removed.\n")); - else - fprintf (dis->err, _("No breakpoint set on comparison flag change\n")); - } - return TRUE; -} - -static gboolean -cmd_pbt_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) -{ - enum {SIZE = 256}; - static gchar BUFFER[SIZE]; - gint no = atoi (arg); - gint k = 0, address; - guint line; - const mix_src_file_t *file = mix_vm_get_src_file (dis->vm); - char *name = file ? g_basename (mix_src_file_get_path (file)) : NULL; - - const GSList *add = mix_vm_get_backtrace (dis->vm); - while (add && (no == 0 || k < no)) - { - BUFFER[0] = '\0'; - address = GPOINTER_TO_INT (add->data); - line = mix_vm_get_address_lineno (dis->vm, address); - if (line && file) - { - int j = 0; - snprintf (BUFFER, SIZE, "%s", mix_src_file_get_line (file, line)); - while (!isspace (BUFFER[j])) j++; - BUFFER[j] = '\0'; - } - if (strlen (BUFFER) == 0) snprintf (BUFFER, SIZE, "%d", address); - fprintf (dis->out, "#%d\t%s\tin %s%s:%d\n", k, BUFFER, name, - MIX_SRC_DEFEXT, line); - ++k; - add = add->next; - } - /* if (name) g_free (name); */ - return TRUE; -} diff --git a/mixlib/mix_vm_command.h b/mixlib/mix_vm_command.h index 4603f78..465ed3e 100644 --- a/mixlib/mix_vm_command.h +++ b/mixlib/mix_vm_command.h @@ -79,8 +79,19 @@ typedef enum { MIX_CMD_TIMING, /* enable/disable timing statistics */ MIX_CMD_DEVDIR, /* print/set device directory */ MIX_CMD_INVALID, /* invalid command identifier */ + MIX_CMD_LOCAL /* locally defined command */ } mix_vm_command_t; +/* new commands definition */ +typedef gboolean (*mix_vm_cmd_function_t) (mix_vm_cmd_dispatcher_t *, + const gchar *); +typedef struct { + const gchar *name; /* User printable name of the function. */ + mix_vm_cmd_function_t func; /* Function to call to do the job. */ + const char *doc; /* Documentation for this function. */ + const char *usage; /* Usage */ +} mix_vm_command_info_t; + /* hook functions, to be invoked before and/or after command execution */ typedef void (*mix_vm_cmd_hook_t)(mix_vm_cmd_dispatcher_t *dis, const gchar *arg, gpointer data); @@ -104,7 +115,6 @@ mix_vm_command_help (mix_vm_command_t cmd); extern const gchar * mix_vm_command_usage (mix_vm_command_t cmd); - /* create a new command dispatcher */ extern mix_vm_cmd_dispatcher_t * mix_vm_cmd_dispatcher_new (FILE *out, /* output messages file */ @@ -118,7 +128,23 @@ mix_vm_cmd_dispatcher_new_with_config (FILE *out, FILE *err, extern void mix_vm_cmd_dispatcher_delete (mix_vm_cmd_dispatcher_t *dis); +/* register new commands for a dispatcher */ +extern void +mix_vm_cmd_dispatcher_register_new (mix_vm_cmd_dispatcher_t *dis, + mix_vm_command_info_t *cmd); + +/* get command completion list */ +const GList * +mix_vm_cmd_dispatcher_complete (const mix_vm_cmd_dispatcher_t *dis, + const gchar *cmd, gchar **prefix); + /* set/get out/error streams */ +extern FILE * +mix_vm_cmd_dispatcher_get_out_stream (const mix_vm_cmd_dispatcher_t *dis); + +extern FILE * +mix_vm_cmd_dispatcher_get_err_stream (const mix_vm_cmd_dispatcher_t *dis); + extern FILE * /* old output stream */ mix_vm_cmd_dispatcher_set_out_stream (mix_vm_cmd_dispatcher_t *dis, FILE *out); @@ -155,6 +181,12 @@ extern gboolean mix_vm_cmd_dispatcher_dispatch_text (mix_vm_cmd_dispatcher_t *dis, const gchar *text); +/* dispatch a command in text format, with command and arg split */ +extern gboolean +mix_vm_cmd_dispatcher_dispatch_split_text (mix_vm_cmd_dispatcher_t *dis, + const gchar *command, + const gchar *arg); + /* get the last dispatch's result */ extern gboolean mix_vm_cmd_dispatcher_get_last_result (const mix_vm_cmd_dispatcher_t *dis); diff --git a/mixlib/xmix_vm_command.c b/mixlib/xmix_vm_command.c new file mode 100644 index 0000000..0c0ec8a --- /dev/null +++ b/mixlib/xmix_vm_command.c @@ -0,0 +1,31 @@ +/* -*-c-*- -------------- xmix_vm_command.c : + * Implementation of the functions declared in xmix_vm_command.h + * ------------------------------------------------------------------ + * Last change: Time-stamp: "01/08/26 15:27:53 jao" + * ------------------------------------------------------------------ + * 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 "xmix_vm_command.h" + +/* configuration keys */ +const gchar *TRACING_KEY_ = "Tracing"; +const gchar *TIMING_KEY_ = "Timing"; +const gchar *EDITOR_KEY_ = "Editor"; +const gchar *ASM_KEY_ = "Assembler"; diff --git a/mixlib/xmix_vm_command.h b/mixlib/xmix_vm_command.h new file mode 100644 index 0000000..f83bf72 --- /dev/null +++ b/mixlib/xmix_vm_command.h @@ -0,0 +1,92 @@ +/* -*-c-*- ---------------- xmix_vm_command.h : + * Private type declarations form mix_vm_command + * ------------------------------------------------------------------ + * Last change: Time-stamp: <01/08/26 21:52:31 jao> + * ------------------------------------------------------------------ + * 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. + * + */ + + +#ifndef XMIX_VM_COMMAND_H +#define XMIX_VM_COMMAND_H + +#include +#include +#include +#include +#include + +#include "mix_device.h" +#include "mix_vm.h" +#include "mix_vm_dump.h" +#include "mix_eval.h" +#include "mix_predicate.h" +#include "mix_vm_command.h" + + +/* configuration keys */ +extern const gchar *TRACING_KEY_; +extern const gchar *TIMING_KEY_; +extern const gchar *EDITOR_KEY_; +extern const gchar *ASM_KEY_; + +/* 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_; + + +#define PRNO_ MIX_PRED_MEM + +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 */ + gchar *editor; /* edit command line template */ + gchar *assembler; /* compile command line template */ + 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 */ + GHashTable *commands; /* local commands */ + GCompletion *completions; /* command completion list */ + GSList *pre_hooks[MIX_CMD_INVALID]; /* Pre-command hooks */ + GSList *post_hooks[MIX_CMD_INVALID]; /* Post-command hooks */ + GSList *global_pre; /* global pre-command hook */ + GSList *global_post; /* global post-command hook */ + mix_config_t *config; /* externally provided configuration */ + mix_predicate_t *preds[PRNO_]; /* predicates for conditional breakpoints */ + GHashTable *mem_preds; /* predicates for memory conditional bps */ +}; + +#endif /* XMIX_VM_COMMAND_H */ + diff --git a/mixlib/xmix_vm_handlers.c b/mixlib/xmix_vm_handlers.c new file mode 100644 index 0000000..8bbbad4 --- /dev/null +++ b/mixlib/xmix_vm_handlers.c @@ -0,0 +1,1252 @@ +/* -*-c-*- -------------- xmix_vm_handlers.c : + * Implementation of the functions declared in xmix_vm_handlers.h + * ------------------------------------------------------------------ + * Last change: Time-stamp: "01/08/26 04:01:54 jao" + * ------------------------------------------------------------------ + * 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 "xmix_vm_handlers.h" + +/* available commands (in the same order as the type enum) */ +mix_vm_command_info_t commands_[] = { + { "help", cmd_help_, N_("Display this text"), "help [COMMAND]"}, + { "load", cmd_load_, N_("Load a MIX code file"), "load FILENAME"}, + { "edit", cmd_edit_, N_("Edit a MIXAL source file"), "edit [FILENAME]"}, + { "pedit", cmd_pedit_, N_("Print the external editor command"), "pedit"}, + { "sedit", cmd_sedit_, N_("Set the external editor command"), + "sedit COMMAND (e.g. emacs %s)"}, + { "compile", cmd_compile_, N_("Compile a MIXAL source file"), + "compile [FILENAME]"}, + { "pasm", cmd_pasm_, N_("Print the compile command"), "pasm"}, + { "sasm", cmd_sasm_, N_("Set the compile command"), + "sasm COMMAND (e.g. mixasm -g -l %s)"}, + { "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"}, + { "sbpr", cmd_sbpr_, N_("Set conditional breakpoint on register change"), + "sbpr A | X | J | I[1-6]"}, + { "cbpr", cmd_cbpr_, N_("Clear conditional breakpoint on register change"), + "sbpr A | X | J | I[1-6]"}, + { "sbpm", cmd_sbpm_, N_("Set conditional breakpoint on mem cell change"), + "sbpm ADDRESS"}, + { "cbpm", cmd_cbpm_, N_("Clear conditional breakpoint on mem cell change"), + "cbpm ADDRESS"}, + { "sbpc", cmd_sbpc_, + N_("Set conditional breakpoint on comparison flag change"), "sbpc"}, + { "cbpc", cmd_cbpc_, + N_("Clear conditional breakpoint on comparison flag change"), "cbpc"}, + { "sbpo", cmd_sbpo_, + N_("Set conditional breakpoint on overflow toggled"), "sbpo"}, + { "cbpo", cmd_cbpo_, + N_("Set conditional breakpoint on overflow toggled"), "cbpo"}, + { "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"}, + { "tracing", cmd_tracing_, N_("Turn on/off instruction tracing"), + "tracing [on|off]"}, + { "pbt", cmd_pbt_, N_("Print backtrace of executed instructions"), + "pbt [INS_NO] (e.g pbt 5)"}, + { "timing", cmd_timing_, N_("Turn on/off timing statistics"), + "timing [on|off]"}, + { "devdir", cmd_devdir_, N_("Print/set devices directory"), + "devdir [NEWDIR]"}, + { NULL, NULL, NULL, NULL}, +}; + +/* 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 void +print_help_ (gpointer key, gpointer val, gpointer data) +{ + mix_vm_command_info_t *info = (mix_vm_command_info_t *)val; + if (info) + fprintf ((FILE *)data, "%-15s%s\n", info->name, info->doc); +} + +gboolean +cmd_help_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + if (arg && strlen (arg) > 0) + { + int i; + mix_vm_command_info_t *info = + (mix_vm_command_info_t *)g_hash_table_lookup + (dis->commands, (gpointer)arg); + for (i = 0; info == NULL && commands_[i].name; i++) + if (!strcmp (commands_[i].name, arg)) info = commands_ + i; + if (info) + { + fprintf (dis->out , _("%-15s%s.\n%-15sUsage: %s\n"), + info->name, info->doc, "", info->usage); + return TRUE; + } + fprintf (dis->out, _("No commands match `%s'\n"), arg); + return FALSE; + } + else + { + int i = 0; + fprintf (dis->out, _("Possible commands are:\n")); + for (i = 0; commands_[i].name; ++i) + fprintf (dis->out, "%-15s%s\n", commands_[i].name, commands_[i].doc); + g_hash_table_foreach (dis->commands, print_help_, (gpointer)dis->out); + return TRUE; + } +} + +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; +} + +gboolean +cmd_edit_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + if (dis->editor == NULL) + { + fputs (_("Editor not specified (set MDK_EDITOR)\n"), dis->err); + return FALSE; + } + if (!arg || *arg == '\0') arg = mix_vm_cmd_dispatcher_get_src_file_path (dis); + if (!arg) + { + fputs (_("MIXAL source file path not found\n"), dis->err); + return FALSE; + } + else + { + gchar *cmd = g_strdup_printf (dis->editor, arg); + fputs (cmd, dis->out); + system (cmd); + fputs (_(" ...done\n"), dis->out); + g_free (cmd); + return TRUE; + } +} + +gboolean +cmd_compile_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + if (dis->assembler == NULL) + { + fputs (_("MIX assembler not specified\n"), dis->err); + return FALSE; + } + if (!arg || *arg == '\0') arg = mix_vm_cmd_dispatcher_get_src_file_path (dis); + if (!arg) + { + fputs (_("MIXAL source file path not found\n"), dis->err); + return FALSE; + } + else + { + gchar *cmd = g_strdup_printf (dis->assembler, arg); + fputs (cmd, dis->out); + fputs ("\n", dis->out); + if (system (cmd) == EXIT_SUCCESS) + fputs (_("Successful compilation\n"), dis->out); + g_free (cmd); + return TRUE; + } +} + +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_COND_BREAK: + { + gulong line = mix_vm_get_break_lineno (dis->vm); + if (line != 0) + fprintf (dis->out, _("... stopped: %s (line %ld, address %d)\n"), + mix_vm_get_last_breakpoint_message (dis->vm), + line, mix_vm_get_prog_count (dis->vm)); + else + fprintf (dis->out, _("... stopped: %s (address %d)\n"), + mix_vm_get_last_breakpoint_message (dis->vm), + 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; +} + +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; +} + +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; +} + +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_to_file (mix_symbol_table_value (table, arg), + NULL, dis->out); + 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, dis->out, TRUE); + result = TRUE; + } + + return result; +} + +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\n"), 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; +} + +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; +} + +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; +} + +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] == '-') + { + gchar *narg; + arg[i++] = '\0'; + begin = atol (arg); + narg = arg + i; + i = 0; + while (isdigit (narg[i])) + i++; + while (isspace (narg[i])) + i++; + if (narg[i] != '\0') + error = TRUE; + else + end = atol (narg); + } + 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; +} + +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; +} + +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; +} + +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; +} + +gboolean +cmd_smem_ (mix_vm_cmd_dispatcher_t *dis, const gchar *carg) +{ + gboolean ok = (strlen (carg) > 2 && isdigit (carg[0])); + glong addr = -1; + glong value = 0; + 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"); + } + if (arg) g_free (arg); + + return ok; +} + +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; +} + +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; +} + +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; +} + +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; +} + +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; +} + + +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; +} + +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; + } +} + +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; + } +} + +gboolean +cmd_tracing_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + static const gchar *ON = "on"; + static const gchar *OFF = "off"; + if (arg && !strcmp (arg, ON)) + { + dis->trace = TRUE; + if (dis->config) mix_config_update (dis->config, TRACING_KEY_, ON); + } + else if (arg && !strcmp (arg, OFF)) + { + dis->trace = FALSE; + if (dis->config) mix_config_update (dis->config, TRACING_KEY_, OFF); + } + else if (arg && !strlen (arg)) + { + fprintf (dis->out, "Instruction tracing is currently set %s\n", + dis->trace ? "ON" : "OFF"); + } + else + cmd_help_ (dis, "tracing"); + return TRUE; +} + +gboolean +cmd_timing_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + static const gchar *ON = "on"; + static const gchar *OFF = "off"; + if (arg && !strcmp (arg, ON)) + { + dis->printtime = TRUE; + if (dis->config) mix_config_update (dis->config, TIMING_KEY_, ON); + } + else if (arg && !strcmp (arg, OFF)) + { + dis->printtime = FALSE; + if (dis->config) mix_config_update (dis->config, TIMING_KEY_, OFF); + } + else if (arg && !strlen (arg)) + { + print_time_ (dis); + } + else + cmd_help_ (dis, "timing"); + return TRUE; +} + + +gboolean +cmd_pedit_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + const gchar *ed = mix_vm_cmd_dispatcher_get_editor (dis); + if (dis) + fprintf (dis->out, "Edit command: %s\n", ed); + else + fprintf (dis->out, "Edit command not set (use sedit)\n"); + return TRUE; +} + +gboolean +cmd_sedit_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + if (!arg || !strlen (arg)) return cmd_help_ (dis, "sedit"); + mix_vm_cmd_dispatcher_set_editor (dis, arg); + return TRUE; +} + +gboolean +cmd_pasm_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + const gchar *ed = mix_vm_cmd_dispatcher_get_assembler (dis); + if (dis) + fprintf (dis->out, "Compile command: %s\n", ed); + else + fprintf (dis->out, "Compile command not set (use sasm)\n"); + return TRUE; +} + +gboolean +cmd_sasm_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + if (!arg || !strlen (arg)) return cmd_help_ (dis, "sasm"); + mix_vm_cmd_dispatcher_set_assembler (dis, arg); + return TRUE; +} + +gboolean +cmd_devdir_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + if (!arg || !strlen (arg)) + fprintf (dis->out, "Device directory: %s\n", mix_device_get_dir ()); + else if (mix_device_set_dir (arg) && dis->config) + mix_config_set_devices_dir (dis->config, arg); + return TRUE; +} + + +static const gint INVALID_REG_ = -2; + +static mix_predicate_type_t +get_reg_pred_ (const gchar *arg) +{ + mix_predicate_type_t pred = INVALID_REG_; + + switch (*arg) + { + case 'A': + pred = MIX_PRED_REG_A; + break; + case 'X': + pred = MIX_PRED_REG_X; + break; + case 'J': + pred = MIX_PRED_REG_J; + break; + case 'I': + { + if ( strlen (arg) == 2 ) + { + int i = arg[1] - '1'; + if (i >= 0 && i < 6) + pred = MIX_PRED_REG_I1 - 1 + i; + } + } + break; + default: + break; + } + return pred; +} + +gboolean +cmd_sbpr_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + mix_predicate_type_t pred = get_reg_pred_ (arg); + if (pred != INVALID_REG_) + { + mix_vm_set_conditional_breakpoint (dis->vm, dis->preds[pred]); + fprintf (dis->out, _("Conditional breakpoint on r%s change set\n"), arg); + return TRUE; + } + else + { + fprintf (dis->err, "Invalid argument %s\n", arg); + return FALSE; + } +} + +gboolean +cmd_cbpr_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + mix_predicate_type_t pred = get_reg_pred_ (arg); + if (pred != INVALID_REG_) + { + if (mix_vm_clear_conditional_breakpoint (dis->vm, dis->preds[pred])) + fprintf (dis->out, + _("Conditional breakpoint on r%s change removed\n"), + arg); + else + fprintf (dis->err, _("No breakpoint set on r%s change\n"), arg); + return TRUE; + } + else + { + fprintf (dis->err, _("Invalid argument %s\n"), arg); + return FALSE; + } +} + +gboolean +cmd_sbpm_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + gint add = atoi (arg); + gpointer key, value; + if (add < 0 || add > MIX_VM_CELL_NO) + { + fprintf (dis->out, _("Invalid memory address: %s\n"), arg); + return FALSE; + } + if (!g_hash_table_lookup_extended (dis->mem_preds, GINT_TO_POINTER (add), + &key, &value)) + { + mix_predicate_t *new_pred = mix_predicate_new (MIX_PRED_MEM); + mix_predicate_set_mem_address (new_pred, add); + g_hash_table_insert (dis->mem_preds, + GINT_TO_POINTER (add), (gpointer)new_pred); + mix_vm_set_conditional_breakpoint (dis->vm, new_pred); + } + fprintf (dis->out, _("Conditional breakpoint on mem cell no. %d set\n"), add); + return TRUE; +} + +gboolean +cmd_cbpm_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + gint add = atoi (arg); + gpointer key, value; + if (add < 0 || add > MIX_VM_CELL_NO) + { + fprintf (dis->out, _("Invalid memory address: %s\n"), arg); + return FALSE; + } + if (g_hash_table_lookup_extended (dis->mem_preds, GINT_TO_POINTER (add), + &key, &value)) + { + g_hash_table_remove (dis->mem_preds, key); + mix_vm_clear_conditional_breakpoint (dis->vm, (mix_predicate_t *)value); + mix_predicate_delete ((mix_predicate_t *)value); + fprintf (dis->out, + _("Conditional breakpoint on mem cell no. %d removed\n"), add); + } + else + { + fprintf (dis->out, _("No conditional breakpoint set at address %d\n"), + add); + } + return TRUE; +} + +gboolean +cmd_sbpo_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + if (arg && strlen (arg)) + fprintf (dis->err, _("Unexpected argument: %s\n"), arg); + else + { + mix_vm_set_conditional_breakpoint (dis->vm, dis->preds[MIX_PRED_OVER]); + fprintf (dis->out, + _("Conditional breakpoint on overflow toggled set\n")); + } + return TRUE; +} + +gboolean +cmd_cbpo_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + if (arg && strlen (arg)) + fprintf (dis->err, _("Unexpected argument: %s\n"), arg); + else + { + if (mix_vm_clear_conditional_breakpoint + (dis->vm, dis->preds[MIX_PRED_OVER])) + fprintf (dis->out, + _("Conditional breakpoint on overflow toggled removed.\n")); + else + fprintf (dis->err, _("No breakpoint set on overflow toggle\n")); + } + return TRUE; +} + +gboolean +cmd_sbpc_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + if (arg && strlen (arg)) + fprintf (dis->err, _("Unexpected argument: %s\n"), arg); + else + { + mix_vm_set_conditional_breakpoint (dis->vm, dis->preds[MIX_PRED_CMP]); + fprintf (dis->out, + _("Conditional breakpoint on comparison flag changed set.\n")); + } + return TRUE; +} + +gboolean +cmd_cbpc_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + if (arg && strlen (arg)) + fprintf (dis->err, _("Unexpected argument: %s\n"), arg); + else + { + if (mix_vm_clear_conditional_breakpoint + (dis->vm, dis->preds[MIX_PRED_CMP])) + fprintf + (dis->out, + _("Conditional breakpoint on comparison flag changed removed.\n")); + else + fprintf (dis->err, _("No breakpoint set on comparison flag change\n")); + } + return TRUE; +} + +gboolean +cmd_pbt_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + enum {SIZE = 256}; + static gchar BUFFER[SIZE]; + gint no = atoi (arg); + gint k = 0, address; + guint line; + const mix_src_file_t *file = mix_vm_get_src_file (dis->vm); + char *name = file ? g_basename (mix_src_file_get_path (file)) : NULL; + + const GSList *add = mix_vm_get_backtrace (dis->vm); + while (add && (no == 0 || k < no)) + { + BUFFER[0] = '\0'; + address = GPOINTER_TO_INT (add->data); + line = mix_vm_get_address_lineno (dis->vm, address); + if (line && file) + { + int j = 0; + snprintf (BUFFER, SIZE, "%s", mix_src_file_get_line (file, line)); + while (!isspace (BUFFER[j])) j++; + BUFFER[j] = '\0'; + } + if (strlen (BUFFER) == 0) snprintf (BUFFER, SIZE, "%d", address); + fprintf (dis->out, "#%d\t%s\tin %s%s:%d\n", k, BUFFER, name, + MIX_SRC_DEFEXT, line); + ++k; + add = add->next; + } + /* if (name) g_free (name); */ + return TRUE; +} + diff --git a/mixlib/xmix_vm_handlers.h b/mixlib/xmix_vm_handlers.h new file mode 100644 index 0000000..3b80898 --- /dev/null +++ b/mixlib/xmix_vm_handlers.h @@ -0,0 +1,80 @@ +/* -*-c-*- ---------------- xmix_vm_handlers.h : + * mix_vm_cmd_dispatcher command handlers + * ------------------------------------------------------------------ + * Last change: Time-stamp: <01/08/26 04:07:47 jao> + * ------------------------------------------------------------------ + * 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. + * + */ + + +#ifndef XMIX_VM_HANDLERS_H +#define XMIX_VM_HANDLERS_H + +#include "xmix_vm_command.h" + +/* command handlers */ +#define DEC_FUN(name) \ + extern gboolean 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 (tracing_); +DEC_FUN (timing_); +DEC_FUN (edit_); +DEC_FUN (compile_); +DEC_FUN (pedit_); +DEC_FUN (sedit_); +DEC_FUN (pasm_); +DEC_FUN (sasm_); +DEC_FUN (devdir_); +DEC_FUN (sbpr_); +DEC_FUN (sbpm_); +DEC_FUN (sbpc_); +DEC_FUN (sbpo_); +DEC_FUN (cbpr_); +DEC_FUN (cbpm_); +DEC_FUN (cbpc_); +DEC_FUN (cbpo_); +DEC_FUN (pbt_); + +/* default command structure */ +extern mix_vm_command_info_t commands_[]; + + +#endif /* XMIX_VM_HANDLERS_H */ + diff --git a/mixutils/Makefile.am b/mixutils/Makefile.am index 1c8cdd5..314c3ed 100644 --- a/mixutils/Makefile.am +++ b/mixutils/Makefile.am @@ -10,7 +10,12 @@ # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -INCLUDES = -I$(includedir) +if MAKE_GUILE +INCLUDES = -I$(includedir) -DMAKE_GUILE +else +INCLUDES = -I$(includedir) +endif + LDADD = $(top_builddir)/mixlib/libmix.a $(top_builddir)/lib/libreplace.a \ $(top_builddir)/mixguile/libmixguile.a $(INTLLIBS) diff --git a/mixutils/mixvm.c b/mixutils/mixvm.c index 81b1fa2..aef9493 100644 --- a/mixutils/mixvm.c +++ b/mixutils/mixvm.c @@ -35,7 +35,7 @@ #endif /* HAVE_GETOPT_LONG */ extern void -mix_vmloop (const gchar *code_file, gboolean use_emacs); +mix_vmloop (int argc, char *argv[], const gchar *code_file, gboolean use_emacs); extern void mix_vmrun (const gchar *code_file, gboolean dump); @@ -128,7 +128,7 @@ main (int argc, char **argv) mix_init_lib (); if (run) mix_vmrun(in, dump); - else mix_vmloop (in, emacs); + else mix_vmloop (argc, argv, in, emacs); mix_release_lib (); diff --git a/mixutils/mixvm_command.c b/mixutils/mixvm_command.c index 610f79a..4e9d9f8 100644 --- a/mixutils/mixvm_command.c +++ b/mixutils/mixvm_command.c @@ -42,39 +42,42 @@ #include #include #include + +#ifdef MAKE_GUILE +# include +static gboolean +try_guile_ (char *line) +{ + if (line[0] == '(') + { + if (line[strlen (line) -1] != ')') return FALSE; + mixguile_interpret_command (line); + return TRUE; + } + return FALSE; +} +#else /* !MAKE_GUILE */ +# define try_guile_(ignored) FALSE +#endif /* MAKE_GUILE */ + #include "mixvm_command.h" +/* mixvm dispatcher */ +static mix_vm_cmd_dispatcher_t *dis_ = NULL; + /* The names of functions that actually do the manipulation. */ #define DEC_FUN(name) \ -static int cmd_##name (char *arg) +static gboolean cmd_##name (mix_vm_cmd_dispatcher_t *dis, const char *arg) -DEC_FUN (help_); DEC_FUN (shell_); DEC_FUN (quit_); -/* A structure which contains information on the commands this program - can understand. */ -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; - -COMMAND commands[] = { - { "help", cmd_help_, N_("Display this text"), "help [COMMAND]" }, +mix_vm_command_info_t commands[] = { { "shell", cmd_shell_, N_("Execute shell command"), "shell COMMAND" }, { "quit", cmd_quit_, N_("Quit the program"), "quit" }, { (char *)NULL, (Function *)NULL, (char *)NULL } }; -#define LOCAL_COMANDS_NO_ ((sizeof (commands) / sizeof (commands[0])) - 1) -#define MIX_COMMANDS_NO_ MIX_CMD_INVALID+1 -#define ALL_COMMANDS_NO_ LOCAL_COMANDS_NO_+MIX_COMMANDS_NO_ - -static const char *mix_commands_[ALL_COMMANDS_NO_] = {NULL}; - - #ifdef HAVE_LIBREADLINE /* readline functions */ @@ -109,48 +112,29 @@ mixvm_cmd_completion_ (char *text, int start, int end) static char * mixvm_cmd_generator_ (const char *text, int state) { - static int list_index, len; - const char *name; + static const GList *comp = NULL; + char *prefix = NULL; + char *name = NULL; - /* If this is a new word to complete, initialize now. This includes - saving the length of TEXT for efficiency, and initializing the index - variable to 0. */ + /* If this is a new word to complete, initialize now. */ if (!state) { - list_index = 0; - len = strlen (text); + if (prefix) g_free (prefix); + comp = mix_vm_cmd_dispatcher_complete (dis_, text, &prefix); } /* Return the next name which partially matches from the command list. */ - while ((name = mix_commands_[list_index]) != NULL) + if (comp) { - list_index++; - if (strncmp (name, text, len) == 0) - return (g_strdup (name)); + name = g_strdup ((const gchar *)comp->data); + comp = comp->next; } - /* If no names matched, then return NULL. */ - return ((char *)NULL); + return name; } #endif /* HAVE_LIBREADLINE */ -/* command functions */ -static COMMAND * -find_command_ (const char *name) -{ - int i; - - for (i = 0; commands[i].name; i++) - if (strcmp (name, commands[i].name) == 0) - return (&commands[i]); - - return ((COMMAND *)NULL); -} - -/* mixvm dispatcher */ -static mix_vm_cmd_dispatcher_t *dis_ = NULL; - /* emacs interface */ static void emacs_output_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg, gpointer data) @@ -171,48 +155,26 @@ emacs_output_ (mix_vm_cmd_dispatcher_t *dis, const gchar *arg, gpointer data) } static int -cmd_help_ (char *arg) -{ - int i; - int printed = 0; - - for (i = 1; commands[i].name; i++) - { - if (!arg || !*arg) - { - printf (_("%s\t\t%s.\n"), commands[i].name, _(commands[i].doc)); - printed++; - } - else if (strcmp (arg, commands[i].name) == 0) - { - printf (_("%s\t\t%s.\nUsage:\t\t%s\n"), commands[i].name, - _(commands[i].doc), commands[i].usage); - printed++; - } - } - if (!printed ||!arg || !*arg) - mix_vm_cmd_dispatcher_dispatch (dis_, MIX_CMD_HELP, arg); - return TRUE; -} - -static int -cmd_quit_ (char *arg) +cmd_quit_ (mix_vm_cmd_dispatcher_t *dis, const char *arg) { puts ("Quitting ..."); if ( dis_ ) mix_vm_cmd_dispatcher_delete (dis_); + exit (0); + /* pek: anything needed here to make the marker disappear??? */ return FALSE; } static int -cmd_shell_ (char *arg) +cmd_shell_ (mix_vm_cmd_dispatcher_t *dis, const char *arg) { system (arg); return TRUE; } + /* external interface */ static void @@ -238,17 +200,10 @@ init_dis_ (mix_vm_cmd_dispatcher_t *dis) mix_vm_cmd_dispatcher_set_assembler (dis, "mixasm -g %s"); } -void +mix_vm_cmd_dispatcher_t * mixvm_cmd_init (mix_config_t *config, char *arg, gboolean use_emacs) { int k; - /* get local command names */ - for (k = 0; k < LOCAL_COMANDS_NO_; ++k) - mix_commands_[k] = commands[k].name; - /* get external command names */ - for (k = 0; k < MIX_CMD_INVALID; ++k) - mix_commands_[k + LOCAL_COMANDS_NO_] = mix_vm_command_to_string (k); - mix_commands_[ALL_COMMANDS_NO_ - 1] = NULL; #ifdef HAVE_LIBREADLINE /* Tell the completer that we want a crack first. */ @@ -263,6 +218,14 @@ mixvm_cmd_init (mix_config_t *config, char *arg, gboolean use_emacs) init_dis_ (dis_); + /* add local commands */ + k = 0; + while (commands[k].name) + { + mix_vm_cmd_dispatcher_register_new (dis_, commands + k); + ++k; + } + /* install post hook for emacs interaction */ if (use_emacs) { @@ -273,56 +236,21 @@ mixvm_cmd_init (mix_config_t *config, char *arg, gboolean use_emacs) if (arg) mix_vm_cmd_dispatcher_dispatch (dis_, MIX_CMD_LOAD, arg); + + return dis_; } gboolean mixvm_cmd_exec (char *line) { - int i; - COMMAND *command; - char *cmd, *arg; - mix_vm_command_t mix_cmd; - - if (!line) return cmd_quit_(NULL); + if (!line) return cmd_quit_(dis_, NULL); /* strip white space */ line = g_strstrip(line); - /* Isolate the command word. */ - i = 0; - while (line[i] && isspace (line[i])) - i++; - cmd = line + i; - - while (line[i] && !isspace (line[i])) - i++; - - if (line[i]) - line[i++] = '\0'; - - if (cmd == NULL || strlen (cmd) == 0) - return TRUE; + if (try_guile_ (line)) return TRUE; - /* Get argument to command, if any. */ - while (isspace (line[i])) - i++; - - arg = line + i; - - /* try to find local command */ - command = find_command_ (cmd); - if (command) - return ((*(command->func)) (arg)); + (void)mix_vm_cmd_dispatcher_dispatch_text (dis_, line); - /* try to find mix command */ - mix_cmd = mix_vm_command_from_string (cmd); - - if (mix_cmd == MIX_CMD_INVALID) - fprintf (stderr, _("%s: No such command. Try \'help\'\n"), cmd); - else - mix_vm_cmd_dispatcher_dispatch (dis_, mix_cmd, arg); - return TRUE; } - - diff --git a/mixutils/mixvm_command.h b/mixutils/mixvm_command.h index f4fdea8..e748710 100644 --- a/mixutils/mixvm_command.h +++ b/mixutils/mixvm_command.h @@ -24,8 +24,9 @@ #define MIXVM_COMMAND_H #include +#include -extern void +extern mix_vm_cmd_dispatcher_t * mixvm_cmd_init (mix_config_t *config, char *arg, gboolean use_emacs); extern gboolean diff --git a/mixutils/mixvm_loop.c b/mixutils/mixvm_loop.c index 023d82d..f88acfb 100644 --- a/mixutils/mixvm_loop.c +++ b/mixutils/mixvm_loop.c @@ -27,6 +27,11 @@ #include #include #include + +#ifdef MAKE_GUILE +#include +#endif + #include "mixvm_command.h" #ifdef HAVE_LIBHISTORY @@ -80,7 +85,7 @@ rl_gets () /* The main command loop of the virtual machine */ static mix_config_t *config_ = NULL; -static void +static mix_vm_cmd_dispatcher_t * init_mixvm_ (const gchar *file, gboolean use_emacs) { static const gchar *HISTORY_FILE = "mixvm.history"; @@ -93,18 +98,30 @@ init_mixvm_ (const gchar *file, gboolean use_emacs) if (mix_config_get_history_size (config_) == 0) mix_config_set_history_size (config_, HISTORY_SIZE); - mixvm_cmd_init (config_, (char *)file, use_emacs); + return mixvm_cmd_init (config_, (char *)file, use_emacs); } -void -mix_vmloop (const gchar *file, gboolean use_emacs) + +static void +loop_ (int argc, char *argv[]) { - init_mixvm_ (file, use_emacs); while ( mixvm_cmd_exec (rl_gets ()) ) ; mix_config_delete (config_); } +void +mix_vmloop (int argc, char *argv[], const gchar *file, gboolean use_emacs) +{ +#ifdef MAKE_GUILE + mix_vm_cmd_dispatcher_t *dis = init_mixvm_ (file, use_emacs); + mixguile_init (argc, argv, loop_, dis); +#else + (void) init_mixvm_ (file, use_emacs); + loop_ (argc, argv); +#endif +} + /* run a program and exit */ void mix_vmrun (const gchar *code_file, gboolean dump) diff --git a/po/ChangeLog b/po/ChangeLog index da3c46e..86776a6 100644 --- a/po/ChangeLog +++ b/po/ChangeLog @@ -1,3 +1,23 @@ +2001-08-27 gettextize + + * Makefile.in.in: Upgrade to gettext-0.10.39. + +2001-08-26 gettextize + + * Makefile.in.in: Upgrade to gettext-0.10.39. + +2001-08-25 gettextize + + * Makefile.in.in: Upgrade to gettext-0.10.39. + +2001-08-25 gettextize + + * Makefile.in.in: Upgrade to gettext-0.10.39. + +2001-08-25 gettextize + + * Makefile.in.in: Upgrade to gettext-0.10.39. + 2001-08-23 gettextize * Makefile.in.in: Upgrade to gettext-0.10.39. -- cgit v1.2.3