};
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;
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? */
}
}
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);
/* 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;
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)
} 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;
}
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;
}
}
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)"));
}
}
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)
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;
}
parser.arg_pos = argv;
parser.arg_end = argv + nargs;
parser.getNextArg = vshCommandArgvGetArg;
- return vshCommandParse(ctl, &parser);
+ return vshCommandParse(ctl, &parser, NULL);
}
/* ----------------------
}
bool
-vshCommandStringParse(vshControl *ctl, char *cmdstr)
+vshCommandStringParse(vshControl *ctl, char *cmdstr, vshCmd **partial)
{
vshCommandParser parser;
parser.pos = cmdstr;
parser.getNextArg = vshCommandStringGetArg;
- return vshCommandParse(ctl, &parser);
+ return vshCommandParse(ctl, &parser, partial);
}
/**