[libvirt] [PATCH v2] virsh: Change option parsing functions to return tri-state information.
Eric Blake
eblake at redhat.com
Mon Mar 7 19:20:43 UTC 2011
On 03/07/2011 11:46 AM, Michal Privoznik wrote:
> This is needed to detect situations when optional argument was
> specified with non-integer value: '--int-opt foo'. To keep functions
> uniform vshCommandOptString function was also changed, because it
> returns tri-state value as well. Given result pointer is updated only
> in case of success. If parsing fails, result is not updated at all.
>
> diff --git a/tools/virsh.c b/tools/virsh.c
> index f3754d7..c274a6b 100644
> --- a/tools/virsh.c
> +++ b/tools/virsh.c
> @@ -252,13 +252,14 @@ static const vshCmdGrp *vshCmdGrpSearch(const char *grpname);
> static int vshCmdGrpHelp(vshControl *ctl, const char *name);
>
> static vshCmdOpt *vshCommandOpt(const vshCmd *cmd, const char *name);
> -static int vshCommandOptInt(const vshCmd *cmd, const char *name, int *found);
> -static unsigned long vshCommandOptUL(const vshCmd *cmd, const char *name,
> - int *found);
> -static char *vshCommandOptString(const vshCmd *cmd, const char *name,
> - int *found);
Ouch - this was not const-correct pre-patch, but at least assigning
'char *' to 'const char *' is trivial...
> -static long long vshCommandOptLongLong(const vshCmd *cmd, const char *name,
> - int *found);
> +static int vshCommandOptInt(const vshCmd *cmd, const char *name, int *value)
> + ATTRIBUTE_NONNULL(3);
> +static int vshCommandOptUL(const vshCmd *cmd, const char *name,
> + unsigned long *value) ATTRIBUTE_NONNULL(3);
> +static int vshCommandOptString(const vshCmd *cmd, const char *name,
> + char **value) ATTRIBUTE_NONNULL(3);
whereas this rewrite exposes the const-correctness issue - you can't
pass 'const char* var; &var' to a 'char **' argument and still keep the
compiler happy...
> +static int vshCommandOptLongLong(const vshCmd *cmd, const char *name,
> + unsigned long long *value) ATTRIBUTE_NONNULL(3);
> static int vshCommandOptBool(const vshCmd *cmd, const char *name);
> static char *vshCommandOptArgv(const vshCmd *cmd, int count);
>
> @@ -589,9 +590,9 @@ static const vshCmdOptDef opts_help[] = {
> static int
> cmdHelp(vshControl *ctl, const vshCmd *cmd)
> {
> - const char *name;
> + char *name = NULL;
>
> - name = vshCommandOptString(cmd, "command", NULL);
> + vshCommandOptString(cmd, "command", &name);
...leading to instances like this where you nukes const designators...
> @@ -773,7 +773,7 @@ cmdConsole(vshControl *ctl, const vshCmd *cmd)
> {
> virDomainPtr dom;
> int ret;
> - const char *name;
> + const char *name = NULL;
>
> if (!vshConnectionUsability(ctl, ctl->conn))
> return FALSE;
> @@ -781,7 +781,7 @@ cmdConsole(vshControl *ctl, const vshCmd *cmd)
> if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
> return FALSE;
>
> - name = vshCommandOptString(cmd, "devname", NULL);
> + vshCommandOptString(cmd, "devname", (char**) &name);
...or even worse, where you had to introduce a cast. Would you mind
splitting this into two patches?
The first patch should _just_ touch vshCommandOptString to change its
return type to const char *, and fix the fallout in the few functions
that need to be a bit more careful about type-safety. I already _know_
that cmdCd will be impacted: commit 5a814012 touched that function, and
exposed a place where we had been leaking memory when
vshCommandOptString returned NULL so we replaced things with a malloc'd
string, so there you will have to split things into using two variables,
one 'const char *' for vshCommandOptString, and the other 'char *' when
doing fallback. But hopefully most other functions will be okay with
using 'const char *' in the first place.
Then the second patch will swap argument order for all the vshCommandOpt
functions, including vshCommandOpt taking a const char ** third
argument, which should just work without any casts or removal of const
throughout the rest of the code.
That said,
> @@ -1288,16 +1286,14 @@ static int
> cmdDefine(vshControl *ctl, const vshCmd *cmd)
> {
> virDomainPtr dom;
> - char *from;
> - int found;
> + char *from = NULL;
> int ret = TRUE;
> char *buffer;
>
> if (!vshConnectionUsability(ctl, ctl->conn))
> return FALSE;
>
> - from = vshCommandOptString(cmd, "file", &found);
> - if (!found)
> + if (vshCommandOptString(cmd, "file", &from) <= 0)
> return FALSE;
The rest of this patch (module the const issues) shows how nice the
change is! Your patch didn't include a diffstat, but it looks like you
have a net reduction in lines of code (always a good sign that the
cleanup was worth it).
> @@ -2862,7 +2852,7 @@ cmdSetvcpus(vshControl *ctl, const vshCmd *cmd)
> if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
> return FALSE;
>
> - count = vshCommandOptInt(cmd, "count", &count);
> + vshCommandOptInt(cmd, "count", &count);
Why the indentation change here?
> @@ -2918,7 +2908,7 @@ cmdSetmem(vshControl *ctl, const vshCmd *cmd)
> {
> virDomainPtr dom;
> virDomainInfo info;
> - unsigned long kilobytes;
> + unsigned long kilobytes = 0;
> int ret = TRUE;
>
> if (!vshConnectionUsability(ctl, ctl->conn))
> @@ -2927,7 +2917,7 @@ cmdSetmem(vshControl *ctl, const vshCmd *cmd)
> if (!(dom = vshCommandOptDomain(ctl, cmd, NULL)))
> return FALSE;
>
> - kilobytes = vshCommandOptUL(cmd, "kilobytes", NULL);
> + vshCommandOptUL(cmd, "kilobytes", &kilobytes);
> if (kilobytes <= 0) {
> virDomainFree(dom);
> vshError(ctl, _("Invalid value of %lu for memory size"), kilobytes);
Hmm, I wonder if we should have been checking if vshCommandOptUL
returned a negative value. Then again, since you defaulted the value to
0, and the value is unchanged on error, and an explicit 0 is also
invalid, you still end up with the right error message.
If you change the helper functions to be ATTRIBUTE_RETURN_CHECK, then
the compiler would enforce that you check all vshCommandOpt* functions
for parse error.
>
> /*
> - * Returns option as INT
> + * @cmd command reference
> + * @name option name
> + * @value result
> + *
> + * Convert option to int
> + * Return value:
> + * >0 if option found and valid (@value updated)
> + * 0 in case option not found (@value untouched)
> + * <0 in all other cases (@value untouched)
> */
> static int
> -vshCommandOptInt(const vshCmd *cmd, const char *name, int *found)
> +vshCommandOptInt(const vshCmd *cmd, const char *name, int *value)
> {
> vshCmdOpt *arg = vshCommandOpt(cmd, name);
> - int res = 0, num_found = FALSE;
> + int ret = 0, num;
> char *end_p = NULL;
>
> if ((arg != NULL) && (arg->data != NULL)) {
> - res = strtol(arg->data, &end_p, 10);
> - if ((arg->data == end_p) || (*end_p!= 0))
> - num_found = FALSE;
> - else
> - num_found = TRUE;
> + num = strtol(arg->data, &end_p, 10);
> + ret = -1;
> + if ((arg->data != end_p) && (*end_p == 0) && value) {
> + *value = num;
> + ret = 1;
> + }
> }
> - if (found)
> - *found = num_found;
> - return res;
> + return ret;
Nice! Exactly what I had in mind.
Looking forward to v3.
--
Eric Blake eblake at redhat.com +1-801-349-2682
Libvirt virtualization library http://libvirt.org
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 619 bytes
Desc: OpenPGP digital signature
URL: <http://listman.redhat.com/archives/libvir-list/attachments/20110307/7781b9c8/attachment-0001.sig>
More information about the libvir-list
mailing list