diff options
author | Jose Antonio Ortega Ruiz <jao@gnu.org> | 2006-03-20 22:46:46 +0000 |
---|---|---|
committer | Jose Antonio Ortega Ruiz <jao@gnu.org> | 2006-03-20 22:46:46 +0000 |
commit | 300160e73da486946ae513f1d039dcd7b85ff17c (patch) | |
tree | f26691ff724b57dac450ab47e4eea91e63cdadc1 /mixlib/mix_vm_command.c | |
parent | 50375f34b611281a3b05a37221e2baa143f5f5ca (diff) | |
download | mdk-300160e73da486946ae513f1d039dcd7b85ff17c.tar.gz mdk-300160e73da486946ae513f1d039dcd7b85ff17c.tar.bz2 |
Version 1.2.1 imported1.2.1
git-archimport-id: mdk@sv.gnu.org/mdk--devel--1--patch-1
Diffstat (limited to 'mixlib/mix_vm_command.c')
-rw-r--r-- | mixlib/mix_vm_command.c | 641 |
1 files changed, 641 insertions, 0 deletions
diff --git a/mixlib/mix_vm_command.c b/mixlib/mix_vm_command.c new file mode 100644 index 0000000..350dae5 --- /dev/null +++ b/mixlib/mix_vm_command.c @@ -0,0 +1,641 @@ +/* -*-c-*- -------------- mix_vm_command.c : + * Implementation of the functions declared in mix_vm_command.h + * ------------------------------------------------------------------ + * $Id: mix_vm_command.c,v 1.30 2005/09/20 19:43:13 jao Exp $ + * ------------------------------------------------------------------ + * Copyright (C) 2001, 2002, 2004 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + + +#include "xmix_vm_command.h" +#include "xmix_vm_handlers.h" + +#ifdef HAVE_LIBHISTORY +# include <readline/history.h> +#endif + +#ifdef HAVE_LIBREADLINE +# include <readline/readline.h> +#endif + +/* hook execution */ +static void +exec_hook_list_ (GSList *list, mix_vm_cmd_dispatcher_t *dis, const gchar *arg) +{ + while (list) + { + hook_ *hook = (hook_ *)list->data; + if (hook) + (hook->func)(dis, arg, hook->data); + list = list->next; + } +} + +static void +exec_global_hook_list_ (GSList *list, + mix_vm_cmd_dispatcher_t *dis, + mix_vm_command_t cmd, const gchar *arg) +{ + while (list) + { + global_hook_ *hook = (global_hook_ *)list->data; + if (hook) + (hook->func)(dis, cmd, arg, hook->data); + list = list->next; + } +} + +/* conversion from/to commands to strings */ +const gchar * +mix_vm_command_to_string (mix_vm_command_t cmd) +{ + if (cmd < MIX_CMD_INVALID) return commands_[cmd].name; + else return NULL; +} + +mix_vm_command_t +mix_vm_command_from_string (const gchar *name) +{ + gint cmd = 0; + while (cmd < MIX_CMD_INVALID && strcmp (name, commands_[cmd].name)) + ++cmd; + return cmd; +} + +/* get help string about a command */ +const gchar * +mix_vm_command_help (mix_vm_command_t cmd) +{ + if (cmd < MIX_CMD_INVALID) return commands_[cmd].doc; + else return NULL; +} + +const gchar * +mix_vm_command_usage (mix_vm_command_t cmd) +{ + if (cmd < MIX_CMD_INVALID) return commands_[cmd].usage; + else return NULL; +} + +/* create a new command dispatcher */ +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 */) +{ + mix_vm_cmd_dispatcher_t *result = NULL; + int k; + + /* g_return_val_if_fail (out_fd && err_fd, NULL); */ + + result = g_new (mix_vm_cmd_dispatcher_t, 1); + result->result = TRUE; + result->out = out_fd; + result->err = err_fd; + result->log_msg = TRUE; + result->uptime = result->laptime = result->progtime = 0; + result->printtime = TRUE; + result->trace = FALSE; + result->program = NULL; + result->editor = NULL; + result->assembler = NULL; + result->eval = mix_eval_new (); + result->dump = mix_dump_context_new (out_fd, + MIX_SHORT_ZERO, MIX_SHORT_ZERO, + MIX_DUMP_ALL); + result->vm = mix_vm_new (); + result->global_pre = result->global_post = NULL; + + for (k =0; k < MIX_CMD_INVALID; ++k) + 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; +} + +mix_vm_cmd_dispatcher_t * +mix_vm_cmd_dispatcher_new_with_config (FILE *out, FILE *err, + mix_config_t *config) +{ + mix_vm_cmd_dispatcher_t *result = mix_vm_cmd_dispatcher_new (out, err); + if (result != NULL && (result->config = config) != NULL) + { + gint hsize = 0; + const gchar *val = mix_config_get (result->config, TRACING_KEY_); + if (val) cmd_strace_ (result, val); + val = mix_config_get (result->config, EDITOR_KEY_); + if (val) mix_vm_cmd_dispatcher_set_editor (result, val); + val = mix_config_get (result->config, ASM_KEY_); + if (val) mix_vm_cmd_dispatcher_set_assembler (result, val); + val = mix_config_get (result->config, TIMING_KEY_); + if (val) cmd_stime_ (result, val); + val = mix_config_get_devices_dir (result->config); + if (!val || !mix_stat_dir (val, "devices")) + { + gchar *dirname = + g_path_get_dirname (mix_config_get_filename (config)); + cmd_sddir_ (result, dirname); + g_free (dirname); + } + else + mix_device_set_dir (val); + val = mix_config_get (result->config, LOGGING_KEY_); + if (val) cmd_slog_ (result, val); +#ifdef HAVE_LIBHISTORY + val = mix_config_get_history_file (result->config); + hsize = mix_config_get_history_size (result->config); + using_history (); + stifle_history (hsize); + if (val) + { + read_history ((char *)val); + history_set_pos (history_base + history_length - 1); + } +#endif + } + return result; +} + + +/* delete (does not close the fds in the constructor) */ +static gboolean +del_pred_ (gpointer key, gpointer val, gpointer data) +{ + if (val) mix_predicate_delete ((mix_predicate_t *)val); + 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) +{ + const gchar *hfile = NULL; + gint k; + + g_return_if_fail (dis != NULL); + mix_eval_delete (dis->eval); + mix_dump_context_delete (dis->dump); + mix_vm_delete (dis->vm); + if (dis->editor) g_free (dis->editor); + if (dis->editor) g_free (dis->assembler); +#ifdef HAVE_LIBHISTORY + if (dis->config && (hfile = mix_config_get_history_file + (dis->config))) + write_history ((char *)hfile); +#endif + 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) +{ + FILE *old = NULL; + g_return_val_if_fail (dis != NULL, old); + old = dis->out; + dis->out = out; + dis->dump->channel = out; + return old; +} + +FILE * /* old error stream */ +mix_vm_cmd_dispatcher_set_error_stream (mix_vm_cmd_dispatcher_t *dis, + FILE *err) +{ + FILE *old = NULL; + g_return_val_if_fail (dis != NULL, old); + old = dis->err; + dis->err = err; + return old; +} + + +/* set editor and compiler templates */ +void +mix_vm_cmd_dispatcher_set_editor (mix_vm_cmd_dispatcher_t *dis, + const gchar *edit_tplt) +{ + g_return_if_fail (dis != NULL); + if (dis->editor) g_free (dis->editor); + dis->editor = (edit_tplt) ? g_strdup (edit_tplt) : NULL; + if (dis->config && dis->editor) + mix_config_update (dis->config, EDITOR_KEY_, dis->editor); +} + +void +mix_vm_cmd_dispatcher_set_assembler (mix_vm_cmd_dispatcher_t *dis, + const gchar *asm_tplt) +{ + g_return_if_fail (dis != NULL); + if (dis->assembler) g_free (dis->assembler); + dis->assembler = (asm_tplt) ? g_strdup (asm_tplt) : NULL; + if (dis->config && dis->assembler) + mix_config_update (dis->config, ASM_KEY_, dis->assembler); +} + +const gchar * +mix_vm_cmd_dispatcher_get_editor (const mix_vm_cmd_dispatcher_t *dis) +{ + g_return_val_if_fail (dis != NULL, NULL); + return dis->editor; +} + +const gchar * +mix_vm_cmd_dispatcher_get_assembler (const mix_vm_cmd_dispatcher_t *dis) +{ + g_return_val_if_fail (dis != NULL, NULL); + return dis->assembler; +} + +const gchar * +mix_vm_cmd_dispatcher_get_src_file_path (const mix_vm_cmd_dispatcher_t *dis) +{ + static gchar *PATH = NULL; + + const mix_vm_t *vm = mix_vm_cmd_dispatcher_get_vm (dis); + const mix_src_file_t *f = mix_vm_get_src_file (vm); + + if (PATH) + { + g_free (PATH); + PATH = NULL; + } + + if (f) + PATH = mix_file_complete_name (mix_src_file_get_path (f), MIX_SRC_DEFEXT); + + return PATH; +} + +const gchar * +mix_vm_cmd_dispatcher_get_program_path (const mix_vm_cmd_dispatcher_t *dis) +{ + g_return_val_if_fail (dis != NULL, NULL); + return dis->program; +} + +/* install hooks */ +void +mix_vm_cmd_dispatcher_pre_hook (mix_vm_cmd_dispatcher_t *dis, + mix_vm_command_t cmd, + mix_vm_cmd_hook_t hook, gpointer data) +{ + hook_ *phook; + + g_return_if_fail (dis != NULL); + g_return_if_fail (cmd < MIX_CMD_INVALID); + + phook = g_new (hook_, 1); + phook->func = hook; + phook->data = data; + + dis->pre_hooks[cmd] = g_slist_append (dis->pre_hooks[cmd], phook); +} + +void +mix_vm_cmd_dispatcher_post_hook (mix_vm_cmd_dispatcher_t *dis, + mix_vm_command_t cmd, + mix_vm_cmd_hook_t hook, gpointer data) +{ + hook_ *phook; + + g_return_if_fail (dis != NULL); + g_return_if_fail (cmd < MIX_CMD_INVALID); + + phook = g_new (hook_, 1); + phook->func = hook; + phook->data = data; + + dis->post_hooks[cmd] = g_slist_append (dis->post_hooks[cmd], phook); +} + +void +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); + + phook = g_new (global_hook_, 1); + phook->func = hook; + phook->data = data; + + dis->global_pre = g_slist_append (dis->global_pre, phook); +} + +void +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); + + 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 */ +gboolean /* TRUE if success, FALSE otherwise */ +mix_vm_cmd_dispatcher_dispatch (mix_vm_cmd_dispatcher_t *dis, + mix_vm_command_t cmd, const gchar *arg) +{ + g_return_val_if_fail (dis != NULL, FALSE); + + if (dis->global_pre) + exec_global_hook_list_ (dis->global_pre, dis, cmd, arg); + + if (cmd < MIX_CMD_INVALID) + { + 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); + + 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) + exec_global_hook_list_ (dis->global_post, dis, cmd, arg); + + fflush (dis->out); + fflush (dis->err); + return dis->result; +} + +/* dispatch a command in text format */ +gboolean +mix_vm_cmd_dispatcher_dispatch_text (mix_vm_cmd_dispatcher_t *dis, + const gchar *text) +{ + gchar *cp, *arg = ""; + int k = 0; + + g_return_val_if_fail (dis != NULL, FALSE); + g_return_val_if_fail (text != NULL, FALSE); + + cp = g_strdup (text); + while (cp[k] && !isspace (cp[k])) ++k; + if (cp[k]) + { + cp[k] = '\0'; ++k; + while (cp[k] && isspace (cp[k])) ++k; + arg = cp + k; + } + + (void) mix_vm_cmd_dispatcher_dispatch_split_text (dis, cp, arg); + + g_free (cp); + + 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) +{ + g_return_val_if_fail (dis != NULL, FALSE); + return dis->result; +} + +/* get total uptime */ +mix_time_t +mix_vm_cmd_dispatcher_get_uptime (const mix_vm_cmd_dispatcher_t *dis) +{ + g_return_val_if_fail (dis != NULL, 0); + return dis->uptime; +} + +/* get program total time */ +mix_time_t +mix_vm_cmd_dispatcher_get_progtime (const mix_vm_cmd_dispatcher_t *dis) +{ + g_return_val_if_fail (dis != NULL, 0); + return dis->progtime; +} + +/* get time lapse */ +mix_time_t +mix_vm_cmd_dispatcher_get_laptime (const mix_vm_cmd_dispatcher_t *dis) +{ + g_return_val_if_fail (dis != NULL, 0); + return dis->laptime; +} + +/* toggle time printing */ +void +mix_vm_cmd_dispatcher_print_time (mix_vm_cmd_dispatcher_t * dis, gboolean print) +{ + g_return_if_fail (dis != NULL); + dis->printtime = print; +} + +/* get the mix vm */ +const mix_vm_t * +mix_vm_cmd_dispatcher_get_vm (const mix_vm_cmd_dispatcher_t *dis) +{ + g_return_val_if_fail (dis != NULL, NULL); + return dis->vm; +} + +/* src file info */ +gulong +mix_vm_cmd_dispatcher_get_src_file_lineno (const mix_vm_cmd_dispatcher_t *dis) +{ + g_return_val_if_fail (dis != NULL, 0); + return mix_vm_get_break_lineno (dis->vm); +} + +const gchar * +mix_vm_cmd_dispatcher_get_src_file_line (const mix_vm_cmd_dispatcher_t *dis, + gulong line, gboolean cr) +{ + const mix_src_file_t *file; + g_return_val_if_fail (dis != NULL, NULL); + + file = mix_vm_get_src_file (dis->vm); + + if (line == 0 || file == NULL) return cr? "" : "\n"; + + if (cr) + return mix_src_file_get_line (file, line); + else + { + enum {BUFF_SIZE = 256}; + static gchar BUFFER[BUFF_SIZE]; + int len = + g_snprintf (BUFFER, BUFF_SIZE, "%s", mix_src_file_get_line (file, line)); + if (len > 0 && BUFFER[len - 1] == '\n') BUFFER[len - 1] = '\0'; + return BUFFER; + } +} + + |