mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-03-07 17:28:15 +00:00
virsh: add vshCommandParser abstraction
add vshCommandParser and make vshCommandParse() accept different parsers. the current code for parse command string is integrated as vshCommandStringParse(). Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com>
This commit is contained in:
parent
4417f08de4
commit
a93f514f5f
101
tools/virsh.c
101
tools/virsh.c
@ -10325,30 +10325,40 @@ vshCommandRun(vshControl *ctl, const vshCmd *cmd)
|
|||||||
* Command string parsing
|
* Command string parsing
|
||||||
* ---------------
|
* ---------------
|
||||||
*/
|
*/
|
||||||
#define VSH_TK_ERROR -1
|
|
||||||
#define VSH_TK_NONE 0
|
|
||||||
#define VSH_TK_DATA 1
|
|
||||||
#define VSH_TK_END 2
|
|
||||||
|
|
||||||
static int ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4)
|
typedef enum {
|
||||||
vshCommandGetToken(vshControl *ctl, char *str, char **end, char **res)
|
VSH_TK_ERROR, /* Failed to parse a token */
|
||||||
|
VSH_TK_ARG, /* Arbitrary argument, might be option or empty */
|
||||||
|
VSH_TK_SUBCMD_END, /* Separation between commands */
|
||||||
|
VSH_TK_END /* No more commands */
|
||||||
|
} vshCommandToken;
|
||||||
|
|
||||||
|
typedef struct __vshCommandParser {
|
||||||
|
vshCommandToken (*getNextArg)(vshControl *, struct __vshCommandParser *,
|
||||||
|
char **);
|
||||||
|
char *pos;
|
||||||
|
} vshCommandParser;
|
||||||
|
|
||||||
|
static int vshCommandParse(vshControl *ctl, vshCommandParser *parser);
|
||||||
|
|
||||||
|
static vshCommandToken ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
|
||||||
|
vshCommandStringGetArg(vshControl *ctl, vshCommandParser *parser, char **res)
|
||||||
{
|
{
|
||||||
bool double_quote = false;
|
bool double_quote = false;
|
||||||
int sz = 0;
|
int sz = 0;
|
||||||
char *p = str;
|
char *p = parser->pos;
|
||||||
char *q = vshStrdup(ctl, str);
|
char *q = vshStrdup(ctl, p);
|
||||||
|
|
||||||
*end = NULL;
|
|
||||||
*res = q;
|
*res = q;
|
||||||
|
|
||||||
while (p && *p && (*p == ' ' || *p == '\t'))
|
while (*p && (*p == ' ' || *p == '\t'))
|
||||||
p++;
|
p++;
|
||||||
|
|
||||||
if (p == NULL || *p == '\0')
|
if (*p == '\0')
|
||||||
return VSH_TK_END;
|
return VSH_TK_END;
|
||||||
if (*p == ';') {
|
if (*p == ';') {
|
||||||
*end = ++p; /* = \0 or begin of next command */
|
parser->pos = ++p; /* = \0 or begin of next command */
|
||||||
return VSH_TK_END;
|
return VSH_TK_SUBCMD_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (*p) {
|
while (*p) {
|
||||||
@ -10371,14 +10381,25 @@ vshCommandGetToken(vshControl *ctl, char *str, char **end, char **res)
|
|||||||
}
|
}
|
||||||
|
|
||||||
*q = '\0';
|
*q = '\0';
|
||||||
*end = p;
|
parser->pos = p;
|
||||||
return VSH_TK_DATA;
|
return VSH_TK_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vshCommandStringParse(vshControl *ctl, char *cmdstr)
|
||||||
|
{
|
||||||
|
vshCommandParser parser;
|
||||||
|
|
||||||
|
if (cmdstr == NULL || *cmdstr == '\0')
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
parser.pos = cmdstr;
|
||||||
|
parser.getNextArg = vshCommandStringGetArg;
|
||||||
|
return vshCommandParse(ctl, &parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
vshCommandParse(vshControl *ctl, char *cmdstr)
|
vshCommandParse(vshControl *ctl, vshCommandParser *parser)
|
||||||
{
|
{
|
||||||
char *str;
|
|
||||||
char *tkdata = NULL;
|
char *tkdata = NULL;
|
||||||
vshCmd *clast = NULL;
|
vshCmd *clast = NULL;
|
||||||
vshCmdOpt *first = NULL;
|
vshCmdOpt *first = NULL;
|
||||||
@ -10388,44 +10409,27 @@ vshCommandParse(vshControl *ctl, char *cmdstr)
|
|||||||
ctl->cmd = NULL;
|
ctl->cmd = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmdstr == NULL || *cmdstr == '\0')
|
while (1) {
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
str = cmdstr;
|
|
||||||
while (str && *str) {
|
|
||||||
vshCmdOpt *last = NULL;
|
vshCmdOpt *last = NULL;
|
||||||
const vshCmdDef *cmd = NULL;
|
const vshCmdDef *cmd = NULL;
|
||||||
int tk = VSH_TK_NONE;
|
vshCommandToken tk;
|
||||||
int data_ct = 0;
|
int data_ct = 0;
|
||||||
|
|
||||||
first = NULL;
|
first = NULL;
|
||||||
|
|
||||||
while (tk != VSH_TK_END) {
|
while (1) {
|
||||||
char *end = NULL;
|
|
||||||
const vshCmdOptDef *opt = NULL;
|
const vshCmdOptDef *opt = NULL;
|
||||||
|
|
||||||
tkdata = NULL;
|
tkdata = NULL;
|
||||||
|
tk = parser->getNextArg(ctl, parser, &tkdata);
|
||||||
|
|
||||||
/* get token */
|
|
||||||
tk = vshCommandGetToken(ctl, str, &end, &tkdata);
|
|
||||||
|
|
||||||
str = end;
|
|
||||||
|
|
||||||
if (tk == VSH_TK_END) {
|
|
||||||
VIR_FREE(tkdata);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (tk == VSH_TK_ERROR)
|
if (tk == VSH_TK_ERROR)
|
||||||
goto syntaxError;
|
goto syntaxError;
|
||||||
|
if (tk != VSH_TK_ARG)
|
||||||
|
break;
|
||||||
|
|
||||||
if (cmd == NULL) {
|
if (cmd == NULL) {
|
||||||
/* first token must be command name */
|
/* first token must be command name */
|
||||||
if (tk != VSH_TK_DATA) {
|
|
||||||
vshError(ctl,
|
|
||||||
_("unexpected token (command name): '%s'"),
|
|
||||||
tkdata);
|
|
||||||
goto syntaxError;
|
|
||||||
}
|
|
||||||
if (!(cmd = vshCmddefSearch(tkdata))) {
|
if (!(cmd = vshCmddefSearch(tkdata))) {
|
||||||
vshError(ctl, _("unknown command: '%s'"), tkdata);
|
vshError(ctl, _("unknown command: '%s'"), tkdata);
|
||||||
goto syntaxError; /* ... or ignore this command only? */
|
goto syntaxError; /* ... or ignore this command only? */
|
||||||
@ -10452,11 +10456,10 @@ vshCommandParse(vshControl *ctl, char *cmdstr)
|
|||||||
if (optstr)
|
if (optstr)
|
||||||
tkdata = optstr;
|
tkdata = optstr;
|
||||||
else
|
else
|
||||||
tk = vshCommandGetToken(ctl, str, &end, &tkdata);
|
tk = parser->getNextArg(ctl, parser, &tkdata);
|
||||||
str = end;
|
|
||||||
if (tk == VSH_TK_ERROR)
|
if (tk == VSH_TK_ERROR)
|
||||||
goto syntaxError;
|
goto syntaxError;
|
||||||
if (tk != VSH_TK_DATA) {
|
if (tk != VSH_TK_ARG) {
|
||||||
vshError(ctl,
|
vshError(ctl,
|
||||||
_("expected syntax: --%s <%s>"),
|
_("expected syntax: --%s <%s>"),
|
||||||
opt->name,
|
opt->name,
|
||||||
@ -10473,7 +10476,7 @@ vshCommandParse(vshControl *ctl, char *cmdstr)
|
|||||||
goto syntaxError;
|
goto syntaxError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (tk == VSH_TK_DATA) {
|
} else {
|
||||||
if (!(opt = vshCmddefGetData(cmd, data_ct++))) {
|
if (!(opt = vshCmddefGetData(cmd, data_ct++))) {
|
||||||
vshError(ctl, _("unexpected data '%s'"), tkdata);
|
vshError(ctl, _("unexpected data '%s'"), tkdata);
|
||||||
goto syntaxError;
|
goto syntaxError;
|
||||||
@ -10500,8 +10503,6 @@ vshCommandParse(vshControl *ctl, char *cmdstr)
|
|||||||
opt->type != VSH_OT_BOOL ? _("optdata") : _("bool"),
|
opt->type != VSH_OT_BOOL ? _("optdata") : _("bool"),
|
||||||
opt->type != VSH_OT_BOOL ? arg->data : _("(none)"));
|
opt->type != VSH_OT_BOOL ? arg->data : _("(none)"));
|
||||||
}
|
}
|
||||||
if (!str)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* command parsed -- allocate new struct for the command */
|
/* command parsed -- allocate new struct for the command */
|
||||||
@ -10523,6 +10524,9 @@ vshCommandParse(vshControl *ctl, char *cmdstr)
|
|||||||
clast->next = c;
|
clast->next = c;
|
||||||
clast = c;
|
clast = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tk == VSH_TK_END)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@ -10538,7 +10542,6 @@ vshCommandParse(vshControl *ctl, char *cmdstr)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ---------------
|
/* ---------------
|
||||||
* Misc utils
|
* Misc utils
|
||||||
* ---------------
|
* ---------------
|
||||||
@ -11188,7 +11191,7 @@ vshParseArgv(vshControl *ctl, int argc, char **argv)
|
|||||||
strncat(cmdstr, " ", sz--);
|
strncat(cmdstr, " ", sz--);
|
||||||
}
|
}
|
||||||
vshDebug(ctl, 2, "command: \"%s\"\n", cmdstr);
|
vshDebug(ctl, 2, "command: \"%s\"\n", cmdstr);
|
||||||
ret = vshCommandParse(ctl, cmdstr);
|
ret = vshCommandStringParse(ctl, cmdstr);
|
||||||
|
|
||||||
VIR_FREE(cmdstr);
|
VIR_FREE(cmdstr);
|
||||||
return ret;
|
return ret;
|
||||||
@ -11267,7 +11270,7 @@ main(int argc, char **argv)
|
|||||||
#if USE_READLINE
|
#if USE_READLINE
|
||||||
add_history(ctl->cmdstr);
|
add_history(ctl->cmdstr);
|
||||||
#endif
|
#endif
|
||||||
if (vshCommandParse(ctl, ctl->cmdstr))
|
if (vshCommandStringParse(ctl, ctl->cmdstr))
|
||||||
vshCommandRun(ctl, ctl->cmd);
|
vshCommandRun(ctl, ctl->cmd);
|
||||||
}
|
}
|
||||||
VIR_FREE(ctl->cmdstr);
|
VIR_FREE(ctl->cmdstr);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user