mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-11 22:21:31 +00:00
vshReadlineParse: Drop code duplication
Now that we have a way of retrieving partly parsed command we don't need duplicate code that parses the user's input. Yes, this code removes call of opt's completer, but: a) current implementation is broken anyway, and b) it will be added back shortly Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
parent
2e688d96a4
commit
255be07d35
212
tools/vsh.c
212
tools/vsh.c
@ -2697,216 +2697,50 @@ vshReadlineOptionsGenerator(const char *text, int state, const vshCmdDef *cmd_pa
|
|||||||
static char *
|
static char *
|
||||||
vshReadlineParse(const char *text, int state)
|
vshReadlineParse(const char *text, int state)
|
||||||
{
|
{
|
||||||
static vshCommandParser parser, sanitizer;
|
static vshCmd *partial;
|
||||||
vshCommandToken tk;
|
|
||||||
static const vshCmdDef *cmd;
|
static const vshCmdDef *cmd;
|
||||||
const vshCmdOptDef *opt = NULL;
|
|
||||||
char *tkdata, *optstr, *const_tkdata, *completed_name;
|
|
||||||
char *res = NULL;
|
char *res = NULL;
|
||||||
static char *ctext, *sanitized_text;
|
|
||||||
static char **completed_list;
|
|
||||||
static unsigned int completed_list_index;
|
|
||||||
static uint64_t const_opts_need_arg, const_opts_required, const_opts_seen;
|
|
||||||
uint64_t opts_seen;
|
|
||||||
size_t opt_index;
|
|
||||||
static bool cmd_exists, opts_filled, opt_exists;
|
|
||||||
static bool non_bool_opt_exists, data_complete;
|
|
||||||
|
|
||||||
if (!state) {
|
if (!state) {
|
||||||
parser.pos = rl_line_buffer;
|
char *buf = vshStrdup(NULL, rl_line_buffer);
|
||||||
parser.getNextArg = vshCommandStringGetArg;
|
|
||||||
|
|
||||||
ctext = vshStrdup(NULL, text);
|
|
||||||
sanitizer.pos = ctext;
|
|
||||||
sanitizer.getNextArg = vshCommandStringGetArg;
|
|
||||||
|
|
||||||
const_tkdata = NULL;
|
|
||||||
tkdata = NULL;
|
|
||||||
sanitized_text = NULL;
|
|
||||||
optstr = NULL;
|
|
||||||
|
|
||||||
completed_list = NULL;
|
|
||||||
completed_list_index = 0;
|
|
||||||
|
|
||||||
/* Sanitize/de-quote the autocomplete text */
|
|
||||||
tk = sanitizer.getNextArg(NULL, &sanitizer, &sanitized_text, false);
|
|
||||||
|
|
||||||
/* No autocomplete if sanitized text is a token error or token end */
|
|
||||||
if (tk == VSH_TK_ERROR)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
tk = parser.getNextArg(NULL, &parser, &const_tkdata, false);
|
|
||||||
|
|
||||||
if (tk == VSH_TK_ERROR)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
/* Free-ing purposes */
|
|
||||||
tkdata = const_tkdata;
|
|
||||||
/* Skip leading space */
|
|
||||||
virSkipSpaces((const char**)&tkdata);
|
|
||||||
|
|
||||||
/* Handle ';'s */
|
|
||||||
while (tk == VSH_TK_SUBCMD_END) {
|
|
||||||
tk = parser.getNextArg(NULL, &parser, &const_tkdata, false);
|
|
||||||
tkdata = const_tkdata;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Skip trailing space after ;*/
|
|
||||||
virSkipSpaces((const char**)&tkdata);
|
|
||||||
|
|
||||||
cmd_exists = false;
|
|
||||||
opts_filled = false;
|
|
||||||
non_bool_opt_exists = false;
|
|
||||||
data_complete = false;
|
|
||||||
|
|
||||||
const_opts_need_arg = 0;
|
|
||||||
const_opts_required = 0;
|
|
||||||
const_opts_seen = 0;
|
|
||||||
|
|
||||||
opt_index = 0;
|
|
||||||
|
|
||||||
|
vshCommandFree(partial);
|
||||||
|
partial = NULL;
|
||||||
cmd = NULL;
|
cmd = NULL;
|
||||||
opt = NULL;
|
|
||||||
|
|
||||||
/* Parse till text to be auto-completed is reached */
|
*(buf + rl_point) = '\0';
|
||||||
while (STRNEQ(tkdata, sanitized_text)) {
|
|
||||||
if (!cmd) {
|
|
||||||
if (!(cmd = vshCmddefSearch(tkdata)))
|
|
||||||
goto error;
|
|
||||||
if (cmd->flags & VSH_CMD_FLAG_ALIAS)
|
|
||||||
cmd = vshCmddefSearch(cmd->alias);
|
|
||||||
|
|
||||||
cmd_exists = true;
|
vshCommandStringParse(NULL, buf, &partial);
|
||||||
if (vshCmddefOptParse(cmd, &const_opts_need_arg,
|
|
||||||
&const_opts_required) < 0)
|
|
||||||
goto error;
|
|
||||||
opts_seen = const_opts_seen;
|
|
||||||
opts_filled = true;
|
|
||||||
} else if (tkdata[0] == '-' && tkdata[1] == '-' &&
|
|
||||||
c_isalnum(tkdata[2])) {
|
|
||||||
/* Command retrieved successfully, move to options */
|
|
||||||
optstr = strchr(tkdata + 2, '=');
|
|
||||||
opt_index = 0;
|
|
||||||
|
|
||||||
if (optstr) {
|
VIR_FREE(buf);
|
||||||
*optstr = '\0';
|
|
||||||
optstr = vshStrdup(NULL, optstr + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(opt = vshCmddefGetOption(NULL, cmd, tkdata + 2,
|
if (partial)
|
||||||
&opts_seen, &opt_index,
|
cmd = partial->def;
|
||||||
&optstr, false))) {
|
|
||||||
/* Parsing failed wrt autocomplete */
|
|
||||||
VIR_FREE(optstr);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
opts_seen = const_opts_seen;
|
if (cmd && STREQ(cmd->name, text)) {
|
||||||
opt_exists = true;
|
/* Corner case - some commands share prefix (e.g.
|
||||||
VIR_FREE(const_tkdata);
|
* dump and dumpxml). If user typed 'dump<TAB><TAB>',
|
||||||
if (opt->type != VSH_OT_BOOL) {
|
* then @text = "dump" and we want to offer command
|
||||||
non_bool_opt_exists = true;
|
* completion. If they typed 'dump <TAB><TAB>' then
|
||||||
/* Opt exists and check for option data */
|
* @text = "" (the space after the command) and we
|
||||||
if (optstr) {
|
* want to offer options completion for dump command.
|
||||||
const_tkdata = optstr;
|
|
||||||
tkdata = const_tkdata;
|
|
||||||
} else {
|
|
||||||
VIR_FREE(const_tkdata);
|
|
||||||
tk = parser.getNextArg(NULL, &parser, &const_tkdata,
|
|
||||||
false);
|
|
||||||
|
|
||||||
if (tk == VSH_TK_ERROR)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
tkdata = const_tkdata;
|
|
||||||
virSkipSpaces((const char **)&tkdata);
|
|
||||||
}
|
|
||||||
if (STREQ(tkdata, sanitized_text)) {
|
|
||||||
/* auto-complete non-bool option arg */
|
|
||||||
data_complete = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
non_bool_opt_exists = false;
|
|
||||||
} else {
|
|
||||||
tkdata = NULL;
|
|
||||||
/* opt type is BOOL */
|
|
||||||
if (optstr) {
|
|
||||||
VIR_FREE(optstr);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (!opt_exists) {
|
|
||||||
/* No -- option provided and some other token given
|
|
||||||
* Try to find the default option.
|
|
||||||
*/
|
*/
|
||||||
if (!(opt = vshCmddefGetData(cmd, &const_opts_need_arg,
|
|
||||||
&const_opts_seen))
|
|
||||||
|| opt->type == VSH_OT_BOOL)
|
|
||||||
goto error;
|
|
||||||
opt_exists = true;
|
|
||||||
opts_seen = const_opts_seen;
|
|
||||||
} else {
|
|
||||||
/* In every other case, return NULL */
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
VIR_FREE(const_tkdata);
|
|
||||||
tk = parser.getNextArg(NULL, &parser, &const_tkdata, false);
|
|
||||||
|
|
||||||
if (tk == VSH_TK_ERROR)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
while (tk == VSH_TK_SUBCMD_END) {
|
|
||||||
cmd = NULL;
|
cmd = NULL;
|
||||||
cmd_exists = false;
|
}
|
||||||
opts_filled = false;
|
|
||||||
opt = NULL;
|
|
||||||
non_bool_opt_exists = false;
|
|
||||||
tk = parser.getNextArg(NULL, &parser, &const_tkdata, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tkdata = const_tkdata;
|
if (!cmd) {
|
||||||
|
res = vshReadlineCommandGenerator(text, state);
|
||||||
virSkipSpaces((const char**)&tkdata);
|
} else {
|
||||||
}
|
res = vshReadlineOptionsGenerator(text, state, cmd);
|
||||||
VIR_FREE(const_tkdata);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!cmd_exists) {
|
|
||||||
res = vshReadlineCommandGenerator(sanitized_text, state);
|
|
||||||
} else if (opts_filled && !non_bool_opt_exists) {
|
|
||||||
res = vshReadlineOptionsGenerator(sanitized_text, state, cmd);
|
|
||||||
} else if (non_bool_opt_exists && data_complete && opt && opt->completer) {
|
|
||||||
if (!completed_list)
|
|
||||||
completed_list = opt->completer(autoCompleteOpaque,
|
|
||||||
opt->completer_flags);
|
|
||||||
if (completed_list) {
|
|
||||||
while ((completed_name = completed_list[completed_list_index])) {
|
|
||||||
completed_list_index++;
|
|
||||||
if (!STRPREFIX(completed_name, sanitized_text))
|
|
||||||
continue;
|
|
||||||
res = vshStrdup(NULL, completed_name);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
res = NULL;
|
|
||||||
virStringListFree(completed_list);
|
|
||||||
completed_list_index = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!res) {
|
if (!res) {
|
||||||
VIR_FREE(sanitized_text);
|
vshCommandFree(partial);
|
||||||
VIR_FREE(ctext);
|
partial = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
error:
|
|
||||||
VIR_FREE(const_tkdata);
|
|
||||||
VIR_FREE(sanitized_text);
|
|
||||||
VIR_FREE(ctext);
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static char **
|
static char **
|
||||||
|
Loading…
x
Reference in New Issue
Block a user