All of lore.kernel.org
 help / color / mirror / Atom feed
From: Markus Armbruster <armbru@redhat.com>
To: Luiz Capitulino <lcapitulino@redhat.com>
Cc: kwolf@redhat.com, aliguori@us.ibm.com, stefanha@gmail.com,
	qemu-devel@nongnu.org, pbonzini@redhat.com,
	Wenchao Xia <xiawenc@linux.vnet.ibm.com>
Subject: Re: [Qemu-devel] [PATCH 2/3] HMP: pass in parameter for info sub command
Date: Fri, 21 Dec 2012 15:49:09 +0100	[thread overview]
Message-ID: <87vcbv1mvu.fsf@blackfin.pond.sub.org> (raw)
In-Reply-To: <20121219160743.34cdfd73@doriath.home> (Luiz Capitulino's message of "Wed, 19 Dec 2012 16:07:43 -0200")

Luiz Capitulino <lcapitulino@redhat.com> writes:

> On Wed, 19 Dec 2012 18:17:09 +0800
> Wenchao Xia <xiawenc@linux.vnet.ibm.com> wrote:
>
>>   This patch enable sub info command handler getting meaningful
>> parameter.
>> 
>> Signed-off-by: Wenchao Xia <xiawenc@linux.vnet.ibm.com>
>> ---
>>  hmp-commands.hx |    2 +-
>>  monitor.c       |   79 +++++++++++++++++++++++++++++++++++++++----------------
>>  2 files changed, 57 insertions(+), 24 deletions(-)
>> 
>> diff --git a/hmp-commands.hx b/hmp-commands.hx
>> index 010b8c9..667fab8 100644
>> --- a/hmp-commands.hx
>> +++ b/hmp-commands.hx
>> @@ -1486,7 +1486,7 @@ ETEXI
>>  
>>      {
>>          .name       = "info",
>> -        .args_type  = "item:s?",
>> +        .args_type  = "item:S?",
>>          .params     = "[subcommand]",
>>          .help       = "show various information about the system state",
>>          .mhandler.cmd = do_info,
>> diff --git a/monitor.c b/monitor.c
>> index 797680f..ce0e74d 100644
>> --- a/monitor.c
>> +++ b/monitor.c

Missing: documentation for the new arg type S in the comment that starts
with "Supported types".

>> @@ -464,6 +464,11 @@ QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX)
>>  MonitorEventState monitor_event_state[QEVENT_MAX];
>>  QemuMutex monitor_event_state_lock;
>>  
>> +static const mon_cmd_t *monitor_parse_command(Monitor *mon,
>> +                                              const char *cmdline,
>> +                                              const mon_cmd_t *table,
>> +                                              QDict *qdict);
>
> Please, move the function instead.

Move will make review harder.  I don't mind forward declarations.

>> +
>>  /*
>>   * Emits the event to every monitor instance
>>   */
>> @@ -809,26 +814,29 @@ static void user_async_cmd_handler(Monitor *mon, const mon_cmd_t *cmd,
>>  static void do_info(Monitor *mon, const QDict *qdict)
>>  {
>>      const mon_cmd_t *cmd;
>> +    QDict *qdict_info;
>>      const char *item = qdict_get_try_str(qdict, "item");
>>  
>>      if (!item) {
>>          goto help;
>>      }
>>  
>> -    for (cmd = info_cmds; cmd->name != NULL; cmd++) {
>> -        if (compare_cmd(item, cmd->name))
>> -            break;
>> -    }
>> +    qdict_info = qdict_new();
>>  
>> -    if (cmd->name == NULL) {
>> -        goto help;
>> +    cmd = monitor_parse_command(mon, item, info_cmds, qdict_info);
>> +    if (!cmd) {
>> +        QDECREF(qdict_info);
>> +        /* don't help here, to avoid error message got ignored */

I'm afraid I don't understand your comment.

Oh, you mean you don't want to call help_cmd() here!

>> +        return;
>>      }
>>  
>> -    cmd->mhandler.info(mon, NULL);
>> +    cmd->mhandler.info(mon, qdict_info);
>> +    QDECREF(qdict_info);
>>      return;
>>  
>>  help:
>>      help_cmd(mon, "info");
>> +    return;
>>  }

The function now looks like this:

    static void do_info(Monitor *mon, const QDict *qdict)
    {
        const mon_cmd_t *cmd;
        QDict *qdict_info;
        const char *item = qdict_get_try_str(qdict, "item");

        if (!item) {
            goto help;
        }

        qdict_info = qdict_new();

        cmd = monitor_parse_command(mon, item, info_cmds, qdict_info);
        if (!cmd) {
            QDECREF(qdict_info);
            /* don't help here, to avoid error message got ignored */
            return;
        }

        cmd->mhandler.info(mon, qdict_info);
        QDECREF(qdict_info);
        return;

    help:
        help_cmd(mon, "info");
        return;
    }

Control flow isn't nice.  What about:

    static void do_info(Monitor *mon, const QDict *qdict)
    {
        const mon_cmd_t *cmd;
        QDict *qdict_info;
        const char *item = qdict_get_try_str(qdict, "item");

        if (!item) {
            help_cmd(mon, "info");
            return;
        }

        qdict_info = qdict_new();

        cmd = monitor_parse_command(mon, item, info_cmds, qdict_info);
        if (!cmd) {
            goto out;
        }

        cmd->mhandler.info(mon, qdict_info);
    out:
        QDECREF(qdict_info);
        return;
    }

>>  
>>  CommandInfoList *qmp_query_commands(Error **errp)
>> @@ -3534,18 +3542,15 @@ static const mon_cmd_t *search_dispatch_table(const mon_cmd_t *disp_table,
>>      return NULL;
>>  }
>>  
>> -static const mon_cmd_t *monitor_find_command(const char *cmdname)
>> +static const mon_cmd_t *monitor_find_command(const char *cmdname,
>> +                                             const mon_cmd_t *table)
>>  {
>> -    return search_dispatch_table(mon_cmds, cmdname);
>> -}
>> -
>> -static const mon_cmd_t *qmp_find_cmd(const char *cmdname)
>> -{
>> -    return search_dispatch_table(qmp_cmds, cmdname);
>> +    return search_dispatch_table(table, cmdname);
>
> Please, keep only search_dispatch_table().

Yes, because the resulting function is silly :)

    static const mon_cmd_t *monitor_find_command(const char *cmdname,
                                                 const mon_cmd_t *table)
    {
        return search_dispatch_table(table, cmdname);
    }

> Actually, maybe you could change handle_qmp_command() to just loop through
> command names and compare them with memcpy() (in a different patch, please)
> then you keep monitor_find_command() for handle_hmp_command().
>
>>  }
>>  
>>  static const mon_cmd_t *monitor_parse_command(Monitor *mon,
>>                                                const char *cmdline,
>> +                                              const mon_cmd_t *table,
>>                                                QDict *qdict)
>>  {
>>      const char *p, *typestr;
>> @@ -3564,7 +3569,7 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon,
>>      if (!p)
>>          return NULL;
>>  
>> -    cmd = monitor_find_command(cmdname);
>> +    cmd = monitor_find_command(cmdname, table);
>>      if (!cmd) {
>>          monitor_printf(mon, "unknown command: '%s'\n", cmdname);
>>          return NULL;
>> @@ -3872,6 +3877,31 @@ static const mon_cmd_t *monitor_parse_command(Monitor *mon,
>>                  }
>>              }
>>              break;
>> +        case 'S':
>> +            {
>> +                /* package all remaining string */
>> +                int len;
>> +
>> +                while (qemu_isspace(*p)) {
>> +                    p++;
>> +                }
>> +                if (*typestr == '?') {
>> +                    typestr++;
>> +                    if (*p == '\0') {
>> +                        /* no remaining string: NULL argument */
>> +                        break;
>> +                    }
>> +                }
>> +                len = strlen(p);
>> +                if (len <= 0) {
>> +                    monitor_printf(mon, "%s: string expected\n",
>> +                                   cmdname);

A "string" in this context is an argument for arg type 's', i.e. a
sequence of characters delimited by unescaped '"', or a sequence of
non-whitespace characters not starting with '"'.  That's not what we
expect here.  We expect arbitrary arguments.

Suggest "arguments expected".

>> +                    break;
>> +                }
>> +                qdict_put(qdict, key, qstring_from_str(p));
>> +                p += len;
>> +            }
>
> This is a true HMP-style hack :)
>
> I don't know how to make this better though (at least not without asking you
> to re-write the whole thing). Maybe Markus has a better idea?

Let me try :)

The new arg type 'S' consumes the rest of the line unparsed, and puts it
into the argument qdict.  Has to come last, obviously.

do_info() extracts it, then parses it like a full command.  The info
command effectively adds like a prefix that switches command parsing to
an alternate table of commands.  Works, quite flexible, but pretty
arcane.

Try #1:

Implement the command prefix concept the direct way.  Mark the command
as prefix.  Instead of a handler, it gets a pointer to the alternate
table of commands.  When monitor_parse_command() recognizes a prefix
command, it drops the first word, switches to the alternate table, and
starts over.

Try #2:

We already have commands that take key=value,... arguments (arg type
'O'): device_add and netdev_add.  Perhaps info could use args_type
"item:s?,opts:O".  First argument is unchanged.  The new second argument
accepts key=value,... options.  'O' argument is always optional.  One
key can be declared optional, so that value (no '=') is shorthand for
that key=value.

>> +            break;
>>          default:
>>          bad_type:
>>              monitor_printf(mon, "%s: unknown type '%c'\n", cmdname, c);
>> @@ -3925,7 +3955,7 @@ static void handle_user_command(Monitor *mon, const char *cmdline)
>>  
>>      qdict = qdict_new();
>>  
>> -    cmd = monitor_parse_command(mon, cmdline, qdict);
>> +    cmd = monitor_parse_command(mon, cmdline, mon_cmds, qdict);
>>      if (!cmd)
>>          goto out;
>>  
>> @@ -4144,12 +4174,7 @@ static void monitor_find_completion(const char *cmdline)
>>              break;
>>          case 's':
>>              /* XXX: more generic ? */
>> -            if (!strcmp(cmd->name, "info")) {
>> -                readline_set_completion_index(cur_mon->rs, strlen(str));
>> -                for(cmd = info_cmds; cmd->name != NULL; cmd++) {
>> -                    cmd_completion(str, cmd->name);
>> -                }
>> -            } else if (!strcmp(cmd->name, "sendkey")) {
>> +            if (!strcmp(cmd->name, "sendkey")) {
>>                  char *sep = strrchr(str, '-');
>>                  if (sep)
>>                      str = sep + 1;

You move the special case hack for info argument completion to case 'S'
(next hunk), but leave behind the /* XXX: more generic ? */ that marks
it as hack!  Please move it along with the hack.

>> @@ -4163,6 +4188,14 @@ static void monitor_find_completion(const char *cmdline)
>>                      cmd_completion(str, cmd->name);
>>                  }
>>              }
>> +        case 'S':
>> +            /* generic string packaged */
>> +            if (!strcmp(cmd->name, "info")) {
>> +                readline_set_completion_index(cur_mon->rs, strlen(str));
>> +                for (cmd = info_cmds; cmd->name != NULL; cmd++) {
>> +                    cmd_completion(str, cmd->name);
>> +                }
>> +            }
>>              break;
>>          default:
>>              break;
>> @@ -4483,7 +4516,7 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
>>          goto err_out;
>>      }
>>  
>> -    cmd = qmp_find_cmd(cmd_name);
>> +    cmd = monitor_find_command(cmd_name, qmp_cmds);
>>      if (!cmd) {
>>          qerror_report(QERR_COMMAND_NOT_FOUND, cmd_name);
>>          goto err_out;

  parent reply	other threads:[~2012-12-21 14:49 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-12-19 10:17 [Qemu-devel] [PATCH 0/3] HMP: enable info sub command taking parameter Wenchao Xia
2012-12-19 10:17 ` [Qemu-devel] [PATCH 1/3] HMP: add QDict to info callback handler Wenchao Xia
2012-12-21 14:01   ` Markus Armbruster
2012-12-25  2:52     ` Wenchao Xia
2012-12-19 10:17 ` [Qemu-devel] [PATCH 2/3] HMP: pass in parameter for info sub command Wenchao Xia
2012-12-19 18:07   ` Luiz Capitulino
2012-12-20  3:02     ` Wenchao Xia
2012-12-22 21:36       ` Luiz Capitulino
2012-12-21 14:49     ` Markus Armbruster [this message]
2012-12-21 18:17       ` Eric Blake
2012-12-25  4:29       ` Wenchao Xia
2012-12-19 10:17 ` [Qemu-devel] [PATCH 3/3] HMP: show internal snapshots on a single device Wenchao Xia
2012-12-21 14:07   ` Markus Armbruster
2012-12-25  3:11     ` Wenchao Xia

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87vcbv1mvu.fsf@blackfin.pond.sub.org \
    --to=armbru@redhat.com \
    --cc=aliguori@us.ibm.com \
    --cc=kwolf@redhat.com \
    --cc=lcapitulino@redhat.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=stefanha@gmail.com \
    --cc=xiawenc@linux.vnet.ibm.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.