]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
vshCommandStringParse: Allow retrieving partial result
authorMichal Privoznik <mprivozn@redhat.com>
Mon, 6 Nov 2017 14:46:50 +0000 (15:46 +0100)
committerMichal Privoznik <mprivozn@redhat.com>
Thu, 11 Jan 2018 17:53:04 +0000 (18:53 +0100)
In the future, this function is going to be called from
vshReadlineParse() to provide parsed input for completer
callbacks. The idea is to allow the callbacks to provide more
specific data. For instance, for the following input:

  virsh # domifaddr --domain fedora --interface <TAB><TAB>

the --interface completer callback is going to be called. Now, it
is more user friendly if the completer offers only those
interfaces found in 'fedora' domain. But in order to do that it
needs to be able to retrieve partially parsed result.

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
tools/virsh.c
tools/virt-admin.c
tools/vsh.c
tools/vsh.h

index 89a2bea10cbe318f4591f6bad2b31fdcaa8c515c..933d6b4c98dbedbcf2e82010303146846ea20ff4 100644 (file)
@@ -817,7 +817,7 @@ virshParseArgv(vshControl *ctl, int argc, char **argv)
         ctl->imode = false;
         if (argc - optind == 1) {
             vshDebug(ctl, VSH_ERR_INFO, "commands: \"%s\"\n", argv[optind]);
-            return vshCommandStringParse(ctl, argv[optind]);
+            return vshCommandStringParse(ctl, argv[optind], NULL);
         } else {
             return vshCommandArgvParse(ctl, argc - optind, argv + optind);
         }
@@ -954,7 +954,7 @@ main(int argc, char **argv)
 #if WITH_READLINE
                 add_history(ctl->cmdstr);
 #endif
-                if (vshCommandStringParse(ctl, ctl->cmdstr))
+                if (vshCommandStringParse(ctl, ctl->cmdstr, NULL))
                     vshCommandRun(ctl, ctl->cmd);
             }
             VIR_FREE(ctl->cmdstr);
index e529a28916865b721d1b808b5a210cc66cb2b2ce..b8b33af193c1c43bafc3e483ca3f9e1acea2df81 100644 (file)
@@ -1335,7 +1335,7 @@ vshAdmParseArgv(vshControl *ctl, int argc, char **argv)
         ctl->imode = false;
         if (argc - optind == 1) {
             vshDebug(ctl, VSH_ERR_INFO, "commands: \"%s\"\n", argv[optind]);
-            return vshCommandStringParse(ctl, argv[optind]);
+            return vshCommandStringParse(ctl, argv[optind], NULL);
         } else {
             return vshCommandArgvParse(ctl, argc - optind, argv + optind);
         }
@@ -1555,7 +1555,7 @@ main(int argc, char **argv)
 #if WITH_READLINE
                 add_history(ctl->cmdstr);
 #endif
-                if (vshCommandStringParse(ctl, ctl->cmdstr))
+                if (vshCommandStringParse(ctl, ctl->cmdstr, NULL))
                     vshCommandRun(ctl, ctl->cmd);
             }
             VIR_FREE(ctl->cmdstr);
index 2366b7b7194870de2b1ca74b23226d821893de68..5b78336c59ed75e207ada4b37a724a51266290ec 100644 (file)
@@ -1386,26 +1386,34 @@ struct _vshCommandParser {
 };
 
 static bool
-vshCommandParse(vshControl *ctl, vshCommandParser *parser)
+vshCommandParse(vshControl *ctl, vshCommandParser *parser, vshCmd **partial)
 {
     char *tkdata = NULL;
     vshCmd *clast = NULL;
     vshCmdOpt *first = NULL;
+    const vshCmdDef *cmd = NULL;
 
-    vshCommandFree(ctl->cmd);
-    ctl->cmd = NULL;
+    if (!partial) {
+        vshCommandFree(ctl->cmd);
+        ctl->cmd = NULL;
+    }
 
     while (1) {
         vshCmdOpt *last = NULL;
-        const vshCmdDef *cmd = NULL;
         vshCommandToken tk;
         bool data_only = false;
         uint64_t opts_need_arg = 0;
         uint64_t opts_required = 0;
         uint64_t opts_seen = 0;
 
+        cmd = NULL;
         first = NULL;
 
+        if (partial) {
+            vshCommandFree(*partial);
+            *partial = NULL;
+        }
+
         while (1) {
             const vshCmdOptDef *opt = NULL;
 
@@ -1422,7 +1430,8 @@ vshCommandParse(vshControl *ctl, vshCommandParser *parser)
             if (cmd == NULL) {
                 /* first token must be command name */
                 if (!(cmd = vshCmddefSearch(tkdata))) {
-                    vshError(ctl, _("unknown command: '%s'"), tkdata);
+                    if (!partial)
+                        vshError(ctl, _("unknown command: '%s'"), tkdata);
                     goto syntaxError;   /* ... or ignore this command only? */
                 }
 
@@ -1434,9 +1443,10 @@ vshCommandParse(vshControl *ctl, vshCommandParser *parser)
                 }
                 if (vshCmddefOptParse(cmd, &opts_need_arg,
                                       &opts_required) < 0) {
-                    vshError(ctl,
-                             _("internal error: bad options in command: '%s'"),
-                             tkdata);
+                    if (!partial)
+                        vshError(ctl,
+                                 _("internal error: bad options in command: '%s'"),
+                                 tkdata);
                     goto syntaxError;
                 }
                 VIR_FREE(tkdata);
@@ -1454,7 +1464,7 @@ vshCommandParse(vshControl *ctl, vshCommandParser *parser)
                 /* Special case 'help' to ignore all spurious options */
                 if (!(opt = vshCmddefGetOption(ctl, cmd, tkdata + 2,
                                                &opts_seen, &opt_index,
-                                               &optstr, true))) {
+                                               &optstr, partial == NULL))) {
                     VIR_FREE(optstr);
                     if (STREQ(cmd->name, "help"))
                         continue;
@@ -1471,11 +1481,24 @@ vshCommandParse(vshControl *ctl, vshCommandParser *parser)
                     if (tk == VSH_TK_ERROR)
                         goto syntaxError;
                     if (tk != VSH_TK_ARG) {
-                        vshError(ctl,
-                                 _("expected syntax: --%s <%s>"),
-                                 opt->name,
-                                 opt->type ==
-                                 VSH_OT_INT ? _("number") : _("string"));
+                        if (partial) {
+                            vshCmdOpt *arg = vshMalloc(ctl, sizeof(vshCmdOpt));
+                            arg->def = opt;
+                            arg->data = tkdata;
+                            tkdata = NULL;
+                            arg->next = NULL;
+                            if (!first)
+                                first = arg;
+                            if (last)
+                                last->next = arg;
+                            last = arg;
+                        } else {
+                            vshError(ctl,
+                                     _("expected syntax: --%s <%s>"),
+                                     opt->name,
+                                     opt->type ==
+                                     VSH_OT_INT ? _("number") : _("string"));
+                        }
                         goto syntaxError;
                     }
                     if (opt->type != VSH_OT_ARGV)
@@ -1483,8 +1506,9 @@ vshCommandParse(vshControl *ctl, vshCommandParser *parser)
                 } else {
                     tkdata = NULL;
                     if (optstr) {
-                        vshError(ctl, _("invalid '=' after option --%s"),
-                                 opt->name);
+                        if (!partial)
+                            vshError(ctl, _("invalid '=' after option --%s"),
+                                     opt->name);
                         VIR_FREE(optstr);
                         goto syntaxError;
                     }
@@ -1500,7 +1524,8 @@ vshCommandParse(vshControl *ctl, vshCommandParser *parser)
                 if (!(opt = vshCmddefGetData(cmd, &opts_need_arg,
                                              &opts_seen)) &&
                      STRNEQ(cmd->name, "help")) {
-                    vshError(ctl, _("unexpected data '%s'"), tkdata);
+                    if (!partial)
+                        vshError(ctl, _("unexpected data '%s'"), tkdata);
                     goto syntaxError;
                 }
             }
@@ -1519,11 +1544,12 @@ vshCommandParse(vshControl *ctl, vshCommandParser *parser)
                     last->next = arg;
                 last = arg;
 
-                vshDebug(ctl, VSH_ERR_INFO, "%s: %s(%s): %s\n",
-                         cmd->name,
-                         opt->name,
-                         opt->type != VSH_OT_BOOL ? _("optdata") : _("bool"),
-                         opt->type != VSH_OT_BOOL ? arg->data : _("(none)"));
+                if (!partial)
+                    vshDebug(ctl, VSH_ERR_INFO, "%s: %s(%s): %s\n",
+                             cmd->name,
+                             opt->name,
+                             opt->type != VSH_OT_BOOL ? _("optdata") : _("bool"),
+                             opt->type != VSH_OT_BOOL ? arg->data : _("(none)"));
             }
         }
 
@@ -1555,17 +1581,24 @@ vshCommandParse(vshControl *ctl, vshCommandParser *parser)
             c->opts = first;
             c->def = cmd;
             c->next = NULL;
+            first = NULL;
 
-            if (vshCommandCheckOpts(ctl, c, opts_required, opts_seen) < 0) {
+            if (!partial &&
+                vshCommandCheckOpts(ctl, c, opts_required, opts_seen) < 0) {
                 VIR_FREE(c);
                 goto syntaxError;
             }
 
-            if (!ctl->cmd)
-                ctl->cmd = c;
-            if (clast)
-                clast->next = c;
-            clast = c;
+            if (partial) {
+                vshCommandFree(*partial);
+                *partial = c;
+            } else {
+                if (!ctl->cmd)
+                    ctl->cmd = c;
+                if (clast)
+                    clast->next = c;
+                clast = c;
+            }
         }
 
         if (tk == VSH_TK_END)
@@ -1575,9 +1608,19 @@ vshCommandParse(vshControl *ctl, vshCommandParser *parser)
     return true;
 
  syntaxError:
-    vshCommandFree(ctl->cmd);
-    ctl->cmd = NULL;
-    vshCommandOptFree(first);
+    if (partial) {
+        vshCmd *tmp;
+
+        tmp = vshMalloc(ctl, sizeof(*tmp));
+        tmp->opts = first;
+        tmp->def = cmd;
+
+        *partial = tmp;
+    } else {
+        vshCommandFree(ctl->cmd);
+        ctl->cmd = NULL;
+        vshCommandOptFree(first);
+    }
     VIR_FREE(tkdata);
     return false;
 }
@@ -1612,7 +1655,7 @@ vshCommandArgvParse(vshControl *ctl, int nargs, char **argv)
     parser.arg_pos = argv;
     parser.arg_end = argv + nargs;
     parser.getNextArg = vshCommandArgvGetArg;
-    return vshCommandParse(ctl, &parser);
+    return vshCommandParse(ctl, &parser, NULL);
 }
 
 /* ----------------------
@@ -1684,7 +1727,7 @@ vshCommandStringGetArg(vshControl *ctl, vshCommandParser *parser, char **res,
 }
 
 bool
-vshCommandStringParse(vshControl *ctl, char *cmdstr)
+vshCommandStringParse(vshControl *ctl, char *cmdstr, vshCmd **partial)
 {
     vshCommandParser parser;
 
@@ -1693,7 +1736,7 @@ vshCommandStringParse(vshControl *ctl, char *cmdstr)
 
     parser.pos = cmdstr;
     parser.getNextArg = vshCommandStringGetArg;
-    return vshCommandParse(ctl, &parser);
+    return vshCommandParse(ctl, &parser, partial);
 }
 
 /**
index ab755bccfffe73b7ea174e29abd1c7e60f9a0d65..8f7df9ff83a8e090a6e1f70250dd413411c2e1d3 100644 (file)
@@ -299,7 +299,7 @@ int vshBlockJobOptionBandwidth(vshControl *ctl,
                                unsigned long *bandwidth);
 bool vshCommandOptBool(const vshCmd *cmd, const char *name);
 bool vshCommandRun(vshControl *ctl, const vshCmd *cmd);
-bool vshCommandStringParse(vshControl *ctl, char *cmdstr);
+bool vshCommandStringParse(vshControl *ctl, char *cmdstr, vshCmd **partial);
 
 const vshCmdOpt *vshCommandOptArgv(vshControl *ctl, const vshCmd *cmd,
                                    const vshCmdOpt *opt);