qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH v4 11/23] monitor: Add completion support for option


From: Jan Kiszka
Subject: [Qemu-devel] [PATCH v4 11/23] monitor: Add completion support for option lists
Date: Wed, 16 Jun 2010 00:38:35 +0200

From: Jan Kiszka <address@hidden>

This enables command line completion inside option strings. A list of
expected key names and their completion type can be appended to the 'O'
inside parentheses ('O(key:type,...)'). The first use case is block
device completion for the 'drive' option of 'device_add'.

Signed-off-by: Jan Kiszka <address@hidden>
---
 monitor.c       |   68 ++++++++++++++++++++++++++++++++++++++++++++++---------
 qemu-monitor.hx |    2 +-
 2 files changed, 58 insertions(+), 12 deletions(-)

diff --git a/monitor.c b/monitor.c
index c1006b4..3e0d862 100644
--- a/monitor.c
+++ b/monitor.c
@@ -68,6 +68,9 @@
  * 'O'          option string of the form NAME=VALUE,...
  *              parsed according to QemuOptsList given by its name
  *              Example: 'device:O' uses qemu_device_opts.
+ *              Command completion for specific keys can be requested via
+ *              appending '(NAME:TYPE,...)' with 'F', 'B' as type.
+ *              Example: 'device:O(bus:Q)' to expand 'bus=...' as qtree path.
  *              Restriction: only lists with empty desc are supported
  *              TODO lift the restriction
  * 'i'          32 bit integer
@@ -3353,6 +3356,11 @@ static const mon_cmd_t *monitor_parse_command(Monitor 
*mon,
                 QemuOptsList *opts_list;
                 QemuOpts *opts;
 
+                if (*typestr == '(') {
+                    while (*typestr++ != ')') {
+                        assert(*typestr != '\0');
+                    }
+                }
                 opts_list = qemu_find_opts(key);
                 if (!opts_list || opts_list->desc->name) {
                     goto bad_type;
@@ -3857,12 +3865,30 @@ static const char *next_arg_type(const char *typestr)
     return (p != NULL ? ++p : typestr);
 }
 
+static bool process_completion_type(char type, const char *str)
+{
+    switch(type) {
+    case 'F':
+        /* file completion */
+        readline_set_completion_index(cur_mon->rs, strlen(str));
+        file_completion(str);
+        return true;
+    case 'B':
+        /* block device name completion */
+        readline_set_completion_index(cur_mon->rs, strlen(str));
+        bdrv_iterate(block_completion_it, (void *)str);
+        return true;
+    default:
+        return false;
+    }
+}
+
 static void monitor_find_completion(const char *cmdline)
 {
     const char *cmdname;
     char *args[MAX_ARGS];
     int nb_args, i, len;
-    const char *ptype, *str;
+    const char *ptype, *str, *opt, *sep;
     const mon_cmd_t *cmd;
     const KeyDef *key;
 
@@ -3915,16 +3941,31 @@ static void monitor_find_completion(const char *cmdline)
         if (*ptype == '-' && ptype[1] != '\0') {
             ptype = next_arg_type(ptype);
         }
+        if (process_completion_type(*ptype, str)) {
+            goto cleanup;
+        }
         switch(*ptype) {
-        case 'F':
-            /* file completion */
-            readline_set_completion_index(cur_mon->rs, strlen(str));
-            file_completion(str);
-            break;
-        case 'B':
-            /* block device name completion */
-            readline_set_completion_index(cur_mon->rs, strlen(str));
-            bdrv_iterate(block_completion_it, (void *)str);
+        case 'O':
+            sep = strrchr(str, ',');
+            opt = sep ? sep + 1 : str;
+            sep = strchr(opt, '=');
+            if (!sep) {
+                break;
+            }
+            len = sep - opt;
+            str = sep + 1;
+            ptype += 2;
+            while (*ptype != ')') {
+                if (strlen(ptype) > len+1 && ptype[len] == ':' &&
+                    strncmp(ptype, opt, len) == 0) {
+                    process_completion_type(ptype[len+1], str);
+                }
+                while (*ptype++ != ',') {
+                    if (*ptype == ')') {
+                        break;
+                    }
+                }
+            }
             break;
         case 's':
             /* XXX: more generic ? */
@@ -3934,7 +3975,7 @@ static void monitor_find_completion(const char *cmdline)
                     cmd_completion(str, cmd->name);
                 }
             } else if (!strcmp(cmd->name, "sendkey")) {
-                char *sep = strrchr(str, '-');
+                sep = strrchr(str, '-');
                 if (sep)
                     str = sep + 1;
                 readline_set_completion_index(cur_mon->rs, strlen(str));
@@ -4114,6 +4155,11 @@ static int monitor_check_qmp_args(const mon_cmd_t *cmd, 
QDict *args)
                 cmd_args.flag = *p++;
                 cmd_args.optional = 1;
             } else if (cmd_args.type == 'O') {
+                if (*p == '(') {
+                    while (*p++ != ')') {
+                        assert(*p != '\0');
+                    }
+                }
                 opts_list = qemu_find_opts(qstring_get_str(cmd_args.name));
                 assert(opts_list);
             } else if (*p == '?') {
diff --git a/qemu-monitor.hx b/qemu-monitor.hx
index 0ea0555..b5d0f6d 100644
--- a/qemu-monitor.hx
+++ b/qemu-monitor.hx
@@ -660,7 +660,7 @@ ETEXI
 
     {
         .name       = "device_add",
-        .args_type  = "device:O",
+        .args_type  = "device:O(drive:B)",
         .params     = "driver[,prop=value][,...]",
         .help       = "add device, like -device on the command line",
         .user_print = monitor_user_noop,
-- 
1.6.0.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]