mirror of https://gitee.com/openkylin/libvirt.git
vshCommandStringParse: Allow retrieving partial result
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>
This commit is contained in:
parent
06e1d36f95
commit
2e688d96a4
|
@ -817,7 +817,7 @@ virshParseArgv(vshControl *ctl, int argc, char **argv)
|
||||||
ctl->imode = false;
|
ctl->imode = false;
|
||||||
if (argc - optind == 1) {
|
if (argc - optind == 1) {
|
||||||
vshDebug(ctl, VSH_ERR_INFO, "commands: \"%s\"\n", argv[optind]);
|
vshDebug(ctl, VSH_ERR_INFO, "commands: \"%s\"\n", argv[optind]);
|
||||||
return vshCommandStringParse(ctl, argv[optind]);
|
return vshCommandStringParse(ctl, argv[optind], NULL);
|
||||||
} else {
|
} else {
|
||||||
return vshCommandArgvParse(ctl, argc - optind, argv + optind);
|
return vshCommandArgvParse(ctl, argc - optind, argv + optind);
|
||||||
}
|
}
|
||||||
|
@ -954,7 +954,7 @@ main(int argc, char **argv)
|
||||||
#if WITH_READLINE
|
#if WITH_READLINE
|
||||||
add_history(ctl->cmdstr);
|
add_history(ctl->cmdstr);
|
||||||
#endif
|
#endif
|
||||||
if (vshCommandStringParse(ctl, ctl->cmdstr))
|
if (vshCommandStringParse(ctl, ctl->cmdstr, NULL))
|
||||||
vshCommandRun(ctl, ctl->cmd);
|
vshCommandRun(ctl, ctl->cmd);
|
||||||
}
|
}
|
||||||
VIR_FREE(ctl->cmdstr);
|
VIR_FREE(ctl->cmdstr);
|
||||||
|
|
|
@ -1335,7 +1335,7 @@ vshAdmParseArgv(vshControl *ctl, int argc, char **argv)
|
||||||
ctl->imode = false;
|
ctl->imode = false;
|
||||||
if (argc - optind == 1) {
|
if (argc - optind == 1) {
|
||||||
vshDebug(ctl, VSH_ERR_INFO, "commands: \"%s\"\n", argv[optind]);
|
vshDebug(ctl, VSH_ERR_INFO, "commands: \"%s\"\n", argv[optind]);
|
||||||
return vshCommandStringParse(ctl, argv[optind]);
|
return vshCommandStringParse(ctl, argv[optind], NULL);
|
||||||
} else {
|
} else {
|
||||||
return vshCommandArgvParse(ctl, argc - optind, argv + optind);
|
return vshCommandArgvParse(ctl, argc - optind, argv + optind);
|
||||||
}
|
}
|
||||||
|
@ -1555,7 +1555,7 @@ main(int argc, char **argv)
|
||||||
#if WITH_READLINE
|
#if WITH_READLINE
|
||||||
add_history(ctl->cmdstr);
|
add_history(ctl->cmdstr);
|
||||||
#endif
|
#endif
|
||||||
if (vshCommandStringParse(ctl, ctl->cmdstr))
|
if (vshCommandStringParse(ctl, ctl->cmdstr, NULL))
|
||||||
vshCommandRun(ctl, ctl->cmd);
|
vshCommandRun(ctl, ctl->cmd);
|
||||||
}
|
}
|
||||||
VIR_FREE(ctl->cmdstr);
|
VIR_FREE(ctl->cmdstr);
|
||||||
|
|
111
tools/vsh.c
111
tools/vsh.c
|
@ -1386,26 +1386,34 @@ struct _vshCommandParser {
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
vshCommandParse(vshControl *ctl, vshCommandParser *parser)
|
vshCommandParse(vshControl *ctl, vshCommandParser *parser, vshCmd **partial)
|
||||||
{
|
{
|
||||||
char *tkdata = NULL;
|
char *tkdata = NULL;
|
||||||
vshCmd *clast = NULL;
|
vshCmd *clast = NULL;
|
||||||
vshCmdOpt *first = NULL;
|
vshCmdOpt *first = NULL;
|
||||||
|
const vshCmdDef *cmd = NULL;
|
||||||
|
|
||||||
vshCommandFree(ctl->cmd);
|
if (!partial) {
|
||||||
ctl->cmd = NULL;
|
vshCommandFree(ctl->cmd);
|
||||||
|
ctl->cmd = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
vshCmdOpt *last = NULL;
|
vshCmdOpt *last = NULL;
|
||||||
const vshCmdDef *cmd = NULL;
|
|
||||||
vshCommandToken tk;
|
vshCommandToken tk;
|
||||||
bool data_only = false;
|
bool data_only = false;
|
||||||
uint64_t opts_need_arg = 0;
|
uint64_t opts_need_arg = 0;
|
||||||
uint64_t opts_required = 0;
|
uint64_t opts_required = 0;
|
||||||
uint64_t opts_seen = 0;
|
uint64_t opts_seen = 0;
|
||||||
|
|
||||||
|
cmd = NULL;
|
||||||
first = NULL;
|
first = NULL;
|
||||||
|
|
||||||
|
if (partial) {
|
||||||
|
vshCommandFree(*partial);
|
||||||
|
*partial = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
const vshCmdOptDef *opt = NULL;
|
const vshCmdOptDef *opt = NULL;
|
||||||
|
|
||||||
|
@ -1422,7 +1430,8 @@ vshCommandParse(vshControl *ctl, vshCommandParser *parser)
|
||||||
if (cmd == NULL) {
|
if (cmd == NULL) {
|
||||||
/* first token must be command name */
|
/* first token must be command name */
|
||||||
if (!(cmd = vshCmddefSearch(tkdata))) {
|
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? */
|
goto syntaxError; /* ... or ignore this command only? */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1434,9 +1443,10 @@ vshCommandParse(vshControl *ctl, vshCommandParser *parser)
|
||||||
}
|
}
|
||||||
if (vshCmddefOptParse(cmd, &opts_need_arg,
|
if (vshCmddefOptParse(cmd, &opts_need_arg,
|
||||||
&opts_required) < 0) {
|
&opts_required) < 0) {
|
||||||
vshError(ctl,
|
if (!partial)
|
||||||
_("internal error: bad options in command: '%s'"),
|
vshError(ctl,
|
||||||
tkdata);
|
_("internal error: bad options in command: '%s'"),
|
||||||
|
tkdata);
|
||||||
goto syntaxError;
|
goto syntaxError;
|
||||||
}
|
}
|
||||||
VIR_FREE(tkdata);
|
VIR_FREE(tkdata);
|
||||||
|
@ -1454,7 +1464,7 @@ vshCommandParse(vshControl *ctl, vshCommandParser *parser)
|
||||||
/* Special case 'help' to ignore all spurious options */
|
/* Special case 'help' to ignore all spurious options */
|
||||||
if (!(opt = vshCmddefGetOption(ctl, cmd, tkdata + 2,
|
if (!(opt = vshCmddefGetOption(ctl, cmd, tkdata + 2,
|
||||||
&opts_seen, &opt_index,
|
&opts_seen, &opt_index,
|
||||||
&optstr, true))) {
|
&optstr, partial == NULL))) {
|
||||||
VIR_FREE(optstr);
|
VIR_FREE(optstr);
|
||||||
if (STREQ(cmd->name, "help"))
|
if (STREQ(cmd->name, "help"))
|
||||||
continue;
|
continue;
|
||||||
|
@ -1471,11 +1481,24 @@ vshCommandParse(vshControl *ctl, vshCommandParser *parser)
|
||||||
if (tk == VSH_TK_ERROR)
|
if (tk == VSH_TK_ERROR)
|
||||||
goto syntaxError;
|
goto syntaxError;
|
||||||
if (tk != VSH_TK_ARG) {
|
if (tk != VSH_TK_ARG) {
|
||||||
vshError(ctl,
|
if (partial) {
|
||||||
_("expected syntax: --%s <%s>"),
|
vshCmdOpt *arg = vshMalloc(ctl, sizeof(vshCmdOpt));
|
||||||
opt->name,
|
arg->def = opt;
|
||||||
opt->type ==
|
arg->data = tkdata;
|
||||||
VSH_OT_INT ? _("number") : _("string"));
|
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;
|
goto syntaxError;
|
||||||
}
|
}
|
||||||
if (opt->type != VSH_OT_ARGV)
|
if (opt->type != VSH_OT_ARGV)
|
||||||
|
@ -1483,8 +1506,9 @@ vshCommandParse(vshControl *ctl, vshCommandParser *parser)
|
||||||
} else {
|
} else {
|
||||||
tkdata = NULL;
|
tkdata = NULL;
|
||||||
if (optstr) {
|
if (optstr) {
|
||||||
vshError(ctl, _("invalid '=' after option --%s"),
|
if (!partial)
|
||||||
opt->name);
|
vshError(ctl, _("invalid '=' after option --%s"),
|
||||||
|
opt->name);
|
||||||
VIR_FREE(optstr);
|
VIR_FREE(optstr);
|
||||||
goto syntaxError;
|
goto syntaxError;
|
||||||
}
|
}
|
||||||
|
@ -1500,7 +1524,8 @@ vshCommandParse(vshControl *ctl, vshCommandParser *parser)
|
||||||
if (!(opt = vshCmddefGetData(cmd, &opts_need_arg,
|
if (!(opt = vshCmddefGetData(cmd, &opts_need_arg,
|
||||||
&opts_seen)) &&
|
&opts_seen)) &&
|
||||||
STRNEQ(cmd->name, "help")) {
|
STRNEQ(cmd->name, "help")) {
|
||||||
vshError(ctl, _("unexpected data '%s'"), tkdata);
|
if (!partial)
|
||||||
|
vshError(ctl, _("unexpected data '%s'"), tkdata);
|
||||||
goto syntaxError;
|
goto syntaxError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1519,11 +1544,12 @@ vshCommandParse(vshControl *ctl, vshCommandParser *parser)
|
||||||
last->next = arg;
|
last->next = arg;
|
||||||
last = arg;
|
last = arg;
|
||||||
|
|
||||||
vshDebug(ctl, VSH_ERR_INFO, "%s: %s(%s): %s\n",
|
if (!partial)
|
||||||
cmd->name,
|
vshDebug(ctl, VSH_ERR_INFO, "%s: %s(%s): %s\n",
|
||||||
opt->name,
|
cmd->name,
|
||||||
opt->type != VSH_OT_BOOL ? _("optdata") : _("bool"),
|
opt->name,
|
||||||
opt->type != VSH_OT_BOOL ? arg->data : _("(none)"));
|
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->opts = first;
|
||||||
c->def = cmd;
|
c->def = cmd;
|
||||||
c->next = NULL;
|
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);
|
VIR_FREE(c);
|
||||||
goto syntaxError;
|
goto syntaxError;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ctl->cmd)
|
if (partial) {
|
||||||
ctl->cmd = c;
|
vshCommandFree(*partial);
|
||||||
if (clast)
|
*partial = c;
|
||||||
clast->next = c;
|
} else {
|
||||||
clast = c;
|
if (!ctl->cmd)
|
||||||
|
ctl->cmd = c;
|
||||||
|
if (clast)
|
||||||
|
clast->next = c;
|
||||||
|
clast = c;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tk == VSH_TK_END)
|
if (tk == VSH_TK_END)
|
||||||
|
@ -1575,9 +1608,19 @@ vshCommandParse(vshControl *ctl, vshCommandParser *parser)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
syntaxError:
|
syntaxError:
|
||||||
vshCommandFree(ctl->cmd);
|
if (partial) {
|
||||||
ctl->cmd = NULL;
|
vshCmd *tmp;
|
||||||
vshCommandOptFree(first);
|
|
||||||
|
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);
|
VIR_FREE(tkdata);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1612,7 +1655,7 @@ vshCommandArgvParse(vshControl *ctl, int nargs, char **argv)
|
||||||
parser.arg_pos = argv;
|
parser.arg_pos = argv;
|
||||||
parser.arg_end = argv + nargs;
|
parser.arg_end = argv + nargs;
|
||||||
parser.getNextArg = vshCommandArgvGetArg;
|
parser.getNextArg = vshCommandArgvGetArg;
|
||||||
return vshCommandParse(ctl, &parser);
|
return vshCommandParse(ctl, &parser, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------
|
/* ----------------------
|
||||||
|
@ -1684,7 +1727,7 @@ vshCommandStringGetArg(vshControl *ctl, vshCommandParser *parser, char **res,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
vshCommandStringParse(vshControl *ctl, char *cmdstr)
|
vshCommandStringParse(vshControl *ctl, char *cmdstr, vshCmd **partial)
|
||||||
{
|
{
|
||||||
vshCommandParser parser;
|
vshCommandParser parser;
|
||||||
|
|
||||||
|
@ -1693,7 +1736,7 @@ vshCommandStringParse(vshControl *ctl, char *cmdstr)
|
||||||
|
|
||||||
parser.pos = cmdstr;
|
parser.pos = cmdstr;
|
||||||
parser.getNextArg = vshCommandStringGetArg;
|
parser.getNextArg = vshCommandStringGetArg;
|
||||||
return vshCommandParse(ctl, &parser);
|
return vshCommandParse(ctl, &parser, partial);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -299,7 +299,7 @@ int vshBlockJobOptionBandwidth(vshControl *ctl,
|
||||||
unsigned long *bandwidth);
|
unsigned long *bandwidth);
|
||||||
bool vshCommandOptBool(const vshCmd *cmd, const char *name);
|
bool vshCommandOptBool(const vshCmd *cmd, const char *name);
|
||||||
bool vshCommandRun(vshControl *ctl, const vshCmd *cmd);
|
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 *vshCommandOptArgv(vshControl *ctl, const vshCmd *cmd,
|
||||||
const vshCmdOpt *opt);
|
const vshCmdOpt *opt);
|
||||||
|
|
Loading…
Reference in New Issue