On Wed, 21 Oct 2009 19:35:03 +0100 Jamie Lokier <ja...@shareable.org> wrote:
> Mulyadi Santosa wrote: > > On Wed, Oct 21, 2009 at 11:24 PM, Glauber Costa <glom...@gmail.com> wrote: > > > You can provide a monitor command to do that > > > > > > something in the lines of: > > > - add_macro <key> <command_list> > > > - remove_macro <key> > > > - list_macros > > > > Please CMIIW, "command_list" here refers to at least one of monitor > > commands, right? meaning, i.e one could do: > > add_macro ctrl_alt_shift_s "stop" > > > > or extend that so it does: > > add_macro ctrl_alt_shift_s "stop print $pc" > > > > so, it stops the VM followed by printing program counter. > > If the monitor accepted ";" as a command separator, to put multiple > commands on a single line, <command_list> could just be a quoted > string which is processed as a line. Why is ";" needed? > If we're going to have keyboard macros, it would be nice and probably > very easy to have monitor macros too - monitor commands which expand > to a line in the same way. > > The number of times I've typed things like send_key control-alt-del > and would have appreciated a "cad" macro... Yeah, I agree. When testing migration, for example, I have to type 'migrate -d tcp:0:4444' several times... Maybe there's a smarter way to do this, but the monitor macros idea seems interesting to me. > Syntax idea comes to mind is: > > - Add ";" as command separator. Not difficult, but not trivial. > - add_macro <name> <command-string> > - remove_macro <name> > - list_macros Why not macro_add? > > - add_key key <key> <command-string> > - remove_key <key> <command-string> > - list_keys What's key? Anyway, below there's a patch with an initial implementation. I've implemented it using the "old" monitor style because I didn't want to think about the right "object model" for this yet.. If people think this is interesting I will work on a serious implementation for submission. Ah, it doesn't have macro_del and if we use QObjects we can consider saving its json representation in file so that we can have macro_load. commit e7fa305f82f4f99168166bda437e86d3a6343064 Author: Luiz Capitulino <lcapitul...@redhat.com> Date: Thu Oct 22 12:26:06 2009 -0200 monitor: Add macro support This is a buggy, untested, initial implementation, which only supports "macro_add" and "macro_list". Example: (qemu) macro_add mi "migrate -d tcp:localhost:4444" Signed-off-by: Luiz Capitulino <lcapitul...@redhat.com> diff --git a/monitor.c b/monitor.c index 2566f4a..f8e2844 100644 --- a/monitor.c +++ b/monitor.c @@ -107,6 +107,15 @@ struct Monitor { QLIST_ENTRY(Monitor) entry; }; +typedef struct MonitorMacro { + QTAILQ_ENTRY(MonitorMacro) entry; + const char *name; + const char *command_line; +} MonitorMacro; + +static QTAILQ_HEAD(monitor_macros, MonitorMacro) monitor_macros = + QTAILQ_HEAD_INITIALIZER(monitor_macros); + static QLIST_HEAD(mon_list, Monitor) mon_list; static const mon_cmd_t mon_cmds[]; @@ -1909,6 +1918,25 @@ static void do_closefd(Monitor *mon, const QDict *qdict) fdname); } +static void do_macro_add(Monitor *mon, const QDict *qdict) +{ + MonitorMacro *macro; + + macro = qemu_mallocz(sizeof(*macro)); + macro->name = qemu_strdup(qdict_get_str(qdict, "name")); + macro->command_line = qemu_strdup(qdict_get_str(qdict, "command")); + + QTAILQ_INSERT_TAIL(&monitor_macros, macro, entry); +} + +static void do_macro_list(Monitor *mon, const QDict *qdict) +{ + MonitorMacro *macro; + + QTAILQ_FOREACH(macro, &monitor_macros, entry) + monitor_printf(mon, "%s: \"%s\"\n", macro->name, macro->command_line); +} + static void do_loadvm(Monitor *mon, const QDict *qdict) { int saved_vm_running = vm_running; @@ -2902,6 +2930,45 @@ static char *key_get_info(const char *type, char **key) return ++p; } +static const mon_cmd_t *find_command(const char *cmdname) +{ + const mon_cmd_t *cmd; + + /* find the command */ + for (cmd = mon_cmds; cmd->name != NULL; cmd++) { + if (compare_cmd(cmdname, cmd->name)) + return cmd; + } + + return NULL; +} + +static const mon_cmd_t *find_macro(char *cmdname, size_t len, const char **pos) +{ + const char *p; + MonitorMacro *macro; + const mon_cmd_t *cmd; + + QTAILQ_FOREACH(macro, &monitor_macros, entry) { + if (strcmp(macro->name, cmdname) == 0) + break; + } + + if (!macro) + return NULL; + + p = get_command_name(macro->command_line, cmdname, len); + if (!p) + return NULL; + + cmd = find_command(cmdname); + if (!cmd) + return NULL; + + *pos = p; + return cmd; +} + static int default_fmt_format = 'x'; static int default_fmt_size = 4; @@ -2927,15 +2994,13 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon, if (!p) return NULL; - /* find the command */ - for(cmd = mon_cmds; cmd->name != NULL; cmd++) { - if (compare_cmd(cmdname, cmd->name)) - break; - } - - if (cmd->name == NULL) { - monitor_printf(mon, "unknown command: '%s'\n", cmdname); - return NULL; + cmd = find_macro(cmdname, sizeof(cmdname), &p); + if (!cmd) { + cmd = find_command(cmdname); + if (!cmd) { + monitor_printf(mon, "unknown command: '%s'\n", cmdname); + return NULL; + } } /* parse the parameters */ diff --git a/qemu-monitor.hx b/qemu-monitor.hx index 29999c6..37561be 100644 --- a/qemu-monitor.hx +++ b/qemu-monitor.hx @@ -1031,6 +1031,30 @@ Close the file descriptor previously assigned to @var{fdname} using the used by another monitor command. ETEXI + { + .name = "macro_add", + .args_type = "name:s,command:s", + .params = "name command", + .help = "add a new monitor macro", + .mhandler.cmd = do_macro_add, + }, + +STEXI +...@item macro_add @var{name} @var{command} +ETEXI + + { + .name = "macro_list", + .args_type = "", + .params = "", + .help = "list monitor macros", + .mhandler.cmd = do_macro_list, + }, + +STEXI +...@item macro_list +ETEXI + STEXI @end table ETEXI