[libvirt] [PATCH 4/8] virsh: add vrshCommandParser abstraction

2010-10-12 Thread Lai Jiangshan

add vrshCommandParser and make vshCommandParse() accepts different
parsers.

the current code for parse command string is integrated as
vshCommandStringParse().

Signed-off-by: Lai Jiangshan la...@cn.fujitsu.com
---
 virsh.c |   91 +++-
 1 file changed, 45 insertions(+), 46 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index f97ee42..27321a5 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -10158,23 +10158,29 @@ vshCommandRun(vshControl *ctl, const vshCmd *cmd)
 return ret;
 }
 
+#define VSH_TK_ERROR   -1
+#define VSH_TK_ARG 0
+#define VSH_TK_SUBCMD_END  1
+#define VSH_TK_END 2
+
+typedef struct __vshCommandParser {
+int (*getNextArg)(vshControl *, struct __vshCommandParser *, char **);
+char *pos;
+} vshCommandParser;
+
+static int vshCommandParse(vshControl *ctl, vshCommandParser *parser);
+
 /* ---
  * Command string parsing
  * ---
  */
-#define VSH_TK_ERROR-1
-#define VSH_TK_NONE0
-#define VSH_TK_DATA1
-#define VSH_TK_END2
 
 static int
-vshCommandGetToken(vshControl *ctl, char *str, char **end, char **res)
+vshCommandStringGetArg(vshControl *ctl, vshCommandParser *parser, char **res)
 {
 bool double_quote = false;
 int sz = 0;
-char *p = str, *q;
-
-*end = NULL;
+char *p = parser-pos, *q;
 
 while (p  *p  (*p == ' ' || *p == '\t'))
 p++;
@@ -10182,8 +10188,8 @@ vshCommandGetToken(vshControl *ctl, char *str, char 
**end, char **res)
 if (p == NULL || *p == '\0')
 return VSH_TK_END;
 if (*p == ';') {
-*end = ++p; /* = \0 or begin of next command */
-return VSH_TK_END;
+parser-pos = ++p; /* = \0 or begin of next command */
+return VSH_TK_SUBCMD_END;
 }
 
 q = p;
@@ -10218,14 +10224,25 @@ copy:
 }
 *(*res + sz) = '\0';
 
-*end = p;
-return VSH_TK_DATA;
+parser-pos = p;
+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
-vshCommandParse(vshControl *ctl, char *cmdstr)
+vshCommandParse(vshControl *ctl, vshCommandParser *parser)
 {
-char *str;
 char *tkdata = NULL;
 vshCmd *clast = NULL;
 vshCmdOpt *first = NULL;
@@ -10235,44 +10252,27 @@ vshCommandParse(vshControl *ctl, char *cmdstr)
 ctl-cmd = NULL;
 }
 
-if (cmdstr == NULL || *cmdstr == '\0')
-return FALSE;
-
-str = cmdstr;
-while (str  *str) {
+for (;;) {
 vshCmdOpt *last = NULL;
 const vshCmdDef *cmd = NULL;
-int tk = VSH_TK_NONE;
+int tk;
 int data_ct = 0;
 
 first = NULL;
 
-while (tk != VSH_TK_END) {
-char *end = NULL;
+for (;;) {
 const vshCmdOptDef *opt = 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)
 goto syntaxError;
+if (tk != VSH_TK_ARG)
+break;
 
 if (cmd == NULL) {
 /* 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))) {
 vshError(ctl, _(unknown command: '%s'), tkdata);
 goto syntaxError;   /* ... or ignore this command only? */
@@ -10299,11 +10299,10 @@ vshCommandParse(vshControl *ctl, char *cmdstr)
 if (optstr)
 tkdata = optstr;
 else
-tk = vshCommandGetToken(ctl, str, end, tkdata);
-str = end;
+tk = parser-getNextArg(ctl, parser, tkdata);
 if (tk == VSH_TK_ERROR)
 goto syntaxError;
-if (tk != VSH_TK_DATA) {
+if (tk != VSH_TK_ARG) {
 vshError(ctl,
  _(expected syntax: --%s %s),
  opt-name,
@@ -10320,7 +10319,7 @@ vshCommandParse(vshControl *ctl, char *cmdstr)
 goto syntaxError;
 }
 }
-} else if (tk == VSH_TK_DATA) {
+} else {
 if (!(opt = vshCmddefGetData(cmd, 

Re: [libvirt] [PATCH 4/8] virsh: add vrshCommandParser abstraction

2010-10-12 Thread Eric Blake

On 10/12/2010 01:13 AM, Lai Jiangshan wrote:


add vrshCommandParser and make vshCommandParse() accepts different


s/vrsh/vsh/; s/accepts/accept/


parsers.

the current code for parse command string is integrated as
vshCommandStringParse().

Signed-off-by: Lai Jiangshanla...@cn.fujitsu.com
---
  virsh.c |   91 
+++-
  1 file changed, 45 insertions(+), 46 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index f97ee42..27321a5 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -10158,23 +10158,29 @@ vshCommandRun(vshControl *ctl, const vshCmd *cmd)
  return ret;
  }

+#define VSH_TK_ERROR   -1
+#define VSH_TK_ARG 0
+#define VSH_TK_SUBCMD_END  1
+#define VSH_TK_END 2


Hmm, in addition to floating this earlier, you also lost _NONE and added 
_SUBCMD_END.  The enum I suggested in patch 3 is sounding more 
appealing, so I'll squash it in now.



+
+typedef struct __vshCommandParser {
+int (*getNextArg)(vshControl *, struct __vshCommandParser *, char **);
+char *pos;
+} vshCommandParser;
+
+static int vshCommandParse(vshControl *ctl, vshCommandParser *parser);


I'm a fan of avoiding forward static declarations if the file can be 
rearranged topologically.



+
  /* ---
   * Command string parsing
   * ---
   */


This logically belongs before enums related to command parsing.


-#define VSH_TK_ERROR-1
-#define VSH_TK_NONE0
-#define VSH_TK_DATA1
-#define VSH_TK_END2

  static int
-vshCommandGetToken(vshControl *ctl, char *str, char **end, char **res)
+vshCommandStringGetArg(vshControl *ctl, vshCommandParser *parser, char **res)
  {
  bool double_quote = false;
  int sz = 0;
-char *p = str, *q;
-
-*end = NULL;
+char *p = parser-pos, *q;


Rebasing this on top of my edits to patch 1 is getting interesting.



  while (p  *p  (*p == ' ' || *p == '\t'))


You no longer need to check if p is NULL,


+static int vshCommandStringParse(vshControl *ctl, char *cmdstr)
+{
+vshCommandParser parser;
+
+if (cmdstr == NULL || *cmdstr == '\0')
+return FALSE;
+
+parser.pos = cmdstr;


...since this guarantees it is non-NULL.


+for (;;) {


$ git grep 'for.*;;' | wc -l
14
$ git grep 'while.*true' | wc -l
6
$ git grep 'while.*1' | wc -l
70

Guess which one I'm changing this to, for consistency :)

ACK, with those nits fixed.  Here's what I squashed in:

diff --git i/tools/virsh.c w/tools/virsh.c
index 56985a4..d9f72f3 100644
--- i/tools/virsh.c
+++ w/tools/virsh.c
@@ -10174,38 +10174,40 @@ vshCommandRun(vshControl *ctl, const vshCmd *cmd)
 return ret;
 }

-#define VSH_TK_ERROR   -1
-#define VSH_TK_ARG 0
-#define VSH_TK_SUBCMD_END  1
-#define VSH_TK_END 2
+/* ---
+ * Command string parsing
+ * ---
+ */
+
+typedef enum {
+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 {
-int (*getNextArg)(vshControl *, struct __vshCommandParser *, char **);
+vshCommandToken (*getNextArg)(vshControl *, struct 
__vshCommandParser *,

+  char **);
 char *pos;
 } vshCommandParser;

 static int vshCommandParse(vshControl *ctl, vshCommandParser *parser);

-/* ---
- * Command string parsing
- * ---
- */
-
-static int ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
+static vshCommandToken ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3)
 vshCommandStringGetArg(vshControl *ctl, vshCommandParser *parser, char 
**res)

 {
 bool double_quote = false;
 int sz = 0;
 char *p = parser-pos;
-char *q = vshStrdup(ctl, str);
+char *q = vshStrdup(ctl, p);

-*end = NULL;
 *res = q;

-while (p  *p  (*p == ' ' || *p == '\t'))
+while (*p  (*p == ' ' || *p == '\t'))
 p++;

-if (p == NULL || *p == '\0')
+if (*p == '\0')
 return VSH_TK_END;
 if (*p == ';') {
 parser-pos = ++p; /* = \0 or begin of next command */
@@ -10261,15 +10262,15 @@ vshCommandParse(vshControl *ctl, 
vshCommandParser *parser)

 ctl-cmd = NULL;
 }

-for (;;) {
+while (1) {
 vshCmdOpt *last = NULL;
 const vshCmdDef *cmd = NULL;
-int tk;
+vshCommandToken tk;
 int data_ct = 0;

 first = NULL;

-for (;;) {
+while (1) {
 const vshCmdOptDef *opt = NULL;

 tkdata = NULL;

--
Eric Blake   ebl...@redhat.com+1-801-349-2682
Libvirt virtualization library http://libvirt.org

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list