diff options
| author | Jose Antonio Ortega Ruiz <jao@gnu.org> | 2001-08-28 16:38:06 +0000 | 
|---|---|---|
| committer | Jose Antonio Ortega Ruiz <jao@gnu.org> | 2001-08-28 16:38:06 +0000 | 
| commit | fd346daffb1a4ec94a8a7b28d30efc37e2742f24 (patch) | |
| tree | 1013e9930944ffb05d198d0cd4ade1c5573f00ce | |
| parent | 6446df78afb4f3da2aa90e25b18b471fb272a8a9 (diff) | |
| download | mdk-fd346daffb1a4ec94a8a7b28d30efc37e2742f24.tar.gz mdk-fd346daffb1a4ec94a8a7b28d30efc37e2742f24.tar.bz2  | |
guile integration
| -rw-r--r-- | .cvsignore | 1 | ||||
| -rw-r--r-- | NEWS | 7 | ||||
| -rw-r--r-- | configure.in | 3 | ||||
| -rw-r--r-- | mixgtk/Makefile.am | 10 | ||||
| -rw-r--r-- | mixgtk/gmixvm.c | 22 | ||||
| -rw-r--r-- | mixgtk/mixgtk_cmd_dispatcher.c | 63 | ||||
| -rw-r--r-- | mixgtk/mixgtk_mixvm.c | 2 | ||||
| -rw-r--r-- | mixguile/Makefile.am | 3 | ||||
| -rw-r--r-- | mixguile/mixguile.c | 46 | ||||
| -rw-r--r-- | mixguile/mixguile.h | 13 | ||||
| -rw-r--r-- | mixguile/mixguile_cmd_dispatcher.c | 91 | ||||
| -rw-r--r-- | mixguile/mixguile_main.c | 23 | ||||
| -rw-r--r-- | mixguile/xmixguile_cmd_dispatcher.c | 163 | ||||
| -rw-r--r-- | mixlib/Makefile.am | 4 | ||||
| -rw-r--r-- | mixlib/mix_config.c | 6 | ||||
| -rw-r--r-- | mixlib/mix_config.h | 3 | ||||
| -rw-r--r-- | mixlib/mix_vm_command.c | 1586 | ||||
| -rw-r--r-- | mixlib/mix_vm_command.h | 34 | ||||
| -rw-r--r-- | mixlib/xmix_vm_command.c | 31 | ||||
| -rw-r--r-- | mixlib/xmix_vm_command.h | 92 | ||||
| -rw-r--r-- | mixlib/xmix_vm_handlers.c | 1252 | ||||
| -rw-r--r-- | mixlib/xmix_vm_handlers.h | 80 | ||||
| -rw-r--r-- | mixutils/Makefile.am | 7 | ||||
| -rw-r--r-- | mixutils/mixvm.c | 4 | ||||
| -rw-r--r-- | mixutils/mixvm_command.c | 176 | ||||
| -rw-r--r-- | mixutils/mixvm_command.h | 3 | ||||
| -rw-r--r-- | mixutils/mixvm_loop.c | 27 | ||||
| -rw-r--r-- | po/ChangeLog | 20 | 
28 files changed, 2181 insertions, 1591 deletions
@@ -1,4 +1,5 @@  .emacs.desktop +.todo  GPATH  GRTAGS  GSYMS @@ -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.  | 
