From a2943243c4cfb677dc3443013bf9da37c8768bf3 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Tue, 12 Oct 2010 15:14:01 +0800 Subject: [PATCH] virsh: rework command parsing Old virsh command parsing mashes all the args back into a string and miss the quotes, this patches fix it. It is also needed for introducing qemu-monitor-command which is very useful. This patches uses the new vshCommandParser abstraction and adds vshCommandArgvParse() for arguments vector, so we don't need to mash arguments vector into a command sting. And the usage was changed: old: virsh [options] [commands] new: virsh [options]... [] virsh [options]... [args...] So we still support commands like: "define D.xml; dumpxml D" was parsed as a commands-string. and support commands like: we will not mash them into a string, we use new argv parser for it. But we don't support the command like: "define D.xml; dumpxml" was parsed as a command-name, but we have no such command-name. Signed-off-by: Lai Jiangshan --- tools/virsh.c | 68 ++++++++++++++++++++++++++++++++++--------------- tools/virsh.pod | 21 ++++++++++----- 2 files changed, 62 insertions(+), 27 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index 557cdf83e4..4101161ede 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -10336,11 +10336,51 @@ typedef enum { typedef struct __vshCommandParser { vshCommandToken (*getNextArg)(vshControl *, struct __vshCommandParser *, char **); + /* vshCommandStringGetArg() */ char *pos; + /* vshCommandArgvGetArg() */ + char **arg_pos; + char **arg_end; } vshCommandParser; static int vshCommandParse(vshControl *ctl, vshCommandParser *parser); +/* --------------- + * Command argv parsing + * --------------- + */ + +static vshCommandToken ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) +vshCommandArgvGetArg(vshControl *ctl, vshCommandParser *parser, char **res) +{ + if (parser->arg_pos == parser->arg_end) { + *res = NULL; + return VSH_TK_END; + } + + *res = vshStrdup(ctl, *parser->arg_pos); + parser->arg_pos++; + return VSH_TK_ARG; +} + +static int vshCommandArgvParse(vshControl *ctl, int nargs, char **argv) +{ + vshCommandParser parser; + + if (nargs <= 0) + return FALSE; + + parser.arg_pos = argv; + parser.arg_end = argv + nargs; + parser.getNextArg = vshCommandArgvGetArg; + return vshCommandParse(ctl, &parser); +} + +/* --------------- + * Command string parsing + * --------------- + */ + static vshCommandToken ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3) vshCommandStringGetArg(vshControl *ctl, vshCommandParser *parser, char **res) { @@ -11045,7 +11085,8 @@ static void vshUsage(void) { const vshCmdDef *cmd; - fprintf(stdout, _("\n%s [options] [commands]\n\n" + fprintf(stdout, _("\n%s [options]... []" + "\n%s [options]... [args...]\n\n" " options:\n" " -c | --connect hypervisor connection URI\n" " -r | --readonly connect readonly\n" @@ -11055,7 +11096,7 @@ vshUsage(void) " -t | --timing print timing information\n" " -l | --log output logging to file\n" " -v | --version program version\n\n" - " commands (non interactive mode):\n"), progname); + " commands (non interactive mode):\n"), progname, progname); for (cmd = commands; cmd->name; cmd++) fprintf(stdout, @@ -11175,26 +11216,13 @@ vshParseArgv(vshControl *ctl, int argc, char **argv) if (argc > end) { /* parse command */ - char *cmdstr; - int sz = 0, ret; - ctl->imode = FALSE; - - for (i = end; i < argc; i++) - sz += strlen(argv[i]) + 1; /* +1 is for blank space between items */ - - cmdstr = vshCalloc(ctl, sz + 1, 1); - - for (i = end; i < argc; i++) { - strncat(cmdstr, argv[i], sz); - sz -= strlen(argv[i]); - strncat(cmdstr, " ", sz--); + if (argc - end == 1) { + vshDebug(ctl, 2, "commands: \"%s\"\n", argv[end]); + return vshCommandStringParse(ctl, argv[end]); + } else { + return vshCommandArgvParse(ctl, argc - end, argv + end); } - vshDebug(ctl, 2, "command: \"%s\"\n", cmdstr); - ret = vshCommandStringParse(ctl, cmdstr); - - VIR_FREE(cmdstr); - return ret; } return TRUE; } diff --git a/tools/virsh.pod b/tools/virsh.pod index e0471b1b1e..209aa54055 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -4,7 +4,9 @@ virsh - management user interface =head1 SYNOPSIS -virsh [args] +B [I