summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJose Antonio Ortega Ruiz <jao@gnu.org>2001-08-28 16:38:06 +0000
committerJose Antonio Ortega Ruiz <jao@gnu.org>2001-08-28 16:38:06 +0000
commitef4616f943c15d40cc2ff189b70e0ef6251af561 (patch)
tree784a7f78b03dee48c2c5ee387c9abe40b01a3907
parent7ca7d093df5ed4f4408f4617036116a84df2bd7f (diff)
downloadmdk-ef4616f943c15d40cc2ff189b70e0ef6251af561.tar.gz
mdk-ef4616f943c15d40cc2ff189b70e0ef6251af561.tar.bz2
guile integration
-rw-r--r--.cvsignore1
-rw-r--r--NEWS7
-rw-r--r--configure.in3
-rw-r--r--mixgtk/Makefile.am10
-rw-r--r--mixgtk/gmixvm.c22
-rw-r--r--mixgtk/mixgtk_cmd_dispatcher.c63
-rw-r--r--mixgtk/mixgtk_mixvm.c2
-rw-r--r--mixguile/Makefile.am3
-rw-r--r--mixguile/mixguile.c46
-rw-r--r--mixguile/mixguile.h13
-rw-r--r--mixguile/mixguile_cmd_dispatcher.c91
-rw-r--r--mixguile/mixguile_main.c23
-rw-r--r--mixguile/xmixguile_cmd_dispatcher.c163
-rw-r--r--mixlib/Makefile.am4
-rw-r--r--mixlib/mix_config.c6
-rw-r--r--mixlib/mix_config.h3
-rw-r--r--mixlib/mix_vm_command.c1586
-rw-r--r--mixlib/mix_vm_command.h34
-rw-r--r--mixlib/xmix_vm_command.c31
-rw-r--r--mixlib/xmix_vm_command.h92
-rw-r--r--mixlib/xmix_vm_handlers.c1252
-rw-r--r--mixlib/xmix_vm_handlers.h80
-rw-r--r--mixutils/Makefile.am7
-rw-r--r--mixutils/mixvm.c4
-rw-r--r--mixutils/mixvm_command.c176
-rw-r--r--mixutils/mixvm_command.h3
-rw-r--r--mixutils/mixvm_loop.c27
-rw-r--r--po/ChangeLog20
28 files changed, 2181 insertions, 1591 deletions
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
@@ -6,6 +6,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)
** New toolbars for gmixvm windows.
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 <stdlib.h>
#include "mixgtk.h"
+
+#ifdef MAKE_GUILE
+# include <mixguile/mixguile.h>
+# 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 <readline/history.h>
#endif
+#ifdef MAKE_GUILE
+# include <mixguile/mixguile.h>
+#endif
+
#include <gdk/gdkkeysyms.h>
#include <mixlib/mix_vm_command.h>
#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 <mixlib/mix_config.h>
#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 <stdio.h>
#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
@@ -219,6 +219,12 @@ mix_set_over_ (SCM over)
}
static SCM
+mix_loc_ (void)
+{
+ return gh_long2scm (mix_vm_get_prog_count (vm_));
+}
+
+static SCM
mix_cmp_ (void)
{
gchar *result = NULL;
@@ -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 <errno.h>
#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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <errno.h>
-
-#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 <readline/history.h>
@@ -42,180 +33,34 @@
# include <readline/readline.h>
#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; k<pos; ++k) fputc (arg[k], dis->err);
- fputc ('\n', dis->err);
- for (k = 0; k<pos; ++k) fputc (' ', dis->err);
- 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#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; k<pos; ++k) fputc (arg[k], dis->err);
+ fputc ('\n', dis->err);
+ for (k = 0; k<pos; ++k) fputc (' ', dis->err);
+ 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 <mixlib/mix_eval.h>
#include <mixlib/mix_src_file.h>
#include <mixlib/mix_vm_command.h>
+
+#ifdef MAKE_GUILE
+# include <mixguile/mixguile.h>
+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 <mixlib/mix_config.h>
+#include <mixlib/mix_vm_command.h>
-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 <mixlib/mix_vm.h>
#include <mixlib/mix_device.h>
#include <mixlib/mix_vm_dump.h>
+
+#ifdef MAKE_GUILE
+#include <mixguile/mixguile.h>
+#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 <bug-gnu-utils@gnu.org>
+
+ * Makefile.in.in: Upgrade to gettext-0.10.39.
+
+2001-08-26 gettextize <bug-gnu-utils@gnu.org>
+
+ * Makefile.in.in: Upgrade to gettext-0.10.39.
+
+2001-08-25 gettextize <bug-gnu-utils@gnu.org>
+
+ * Makefile.in.in: Upgrade to gettext-0.10.39.
+
+2001-08-25 gettextize <bug-gnu-utils@gnu.org>
+
+ * Makefile.in.in: Upgrade to gettext-0.10.39.
+
+2001-08-25 gettextize <bug-gnu-utils@gnu.org>
+
+ * Makefile.in.in: Upgrade to gettext-0.10.39.
+
2001-08-23 gettextize <bug-gnu-utils@gnu.org>
* Makefile.in.in: Upgrade to gettext-0.10.39.