Our qemu monitor code has a converter from key-value pairs to a json value object. I want to re-use the code later and having it part of the monitor command generator is inflexible. Split it out into a separate helper. --- src/libvirt_private.syms | 2 + src/qemu/qemu_monitor_json.c | 161 +-------------------------------- src/util/virjson.c | 211 +++++++++++++++++++++++++++++++++++++++++++ src/util/virjson.h | 5 + 4 files changed, 220 insertions(+), 159 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index d6265ac..314b2b8 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1503,6 +1503,8 @@ virJSONValueObjectAppendNumberLong; virJSONValueObjectAppendNumberUint; virJSONValueObjectAppendNumberUlong; virJSONValueObjectAppendString; +virJSONValueObjectCreate; +virJSONValueObjectCreateVArgs; virJSONValueObjectGet; virJSONValueObjectGetBoolean; virJSONValueObjectGetKey; diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 7f23aae..2967193 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -431,7 +431,6 @@ qemuMonitorJSONMakeCommandRaw(bool wrap, const char *cmdname, ...) virJSONValuePtr obj; virJSONValuePtr jargs = NULL; va_list args; - char *key; va_start(args, cmdname); @@ -442,164 +441,8 @@ qemuMonitorJSONMakeCommandRaw(bool wrap, const char *cmdname, ...) cmdname) < 0) goto error; - while ((key = va_arg(args, char *)) != NULL) { - int ret; - char type; - - if (strlen(key) < 3) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("argument key '%s' is too short, missing type prefix"), - key); - goto error; - } - - /* Keys look like s:name the first letter is a type code: - * Explanation of type codes: - * s: string value, must be non-null - * S: string value, omitted if null - * - * i: signed integer value - * j: signed integer value, error if negative - * z: signed integer value, omitted if zero - * y: signed integer value, omitted if zero, error if negative - * - * I: signed long integer value - * J: signed long integer value, error if negative - * Z: signed long integer value, omitted if zero - * Y: signed long integer value, omitted if zero, error if negative - * - * u: unsigned integer value - * p: unsigned integer value, omitted if zero - * - * U: unsigned long integer value (see below for quirks) - * P: unsigned long integer value, omitted if zero - * - * b: boolean value - * B: boolean value, omitted if false - * - * d: double precision floating point number - * n: json null value - * a: json array - */ - type = key[0]; - key += 2; - - if (!jargs && - !(jargs = virJSONValueNewObject())) - goto error; - - /* This doesn't support maps, but no command uses those. */ - switch (type) { - case 'S': - case 's': { - char *val = va_arg(args, char *); - if (!val) { - if (type == 'S') - continue; - - virReportError(VIR_ERR_INTERNAL_ERROR, - _("argument key '%s' must not have null value"), - key); - goto error; - } - ret = virJSONValueObjectAppendString(jargs, key, val); - } break; - - case 'z': - case 'y': - case 'j': - case 'i': { - int val = va_arg(args, int); - - if (val < 0 && (type == 'j' || type == 'y')) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("argument key '%s' must not be negative"), - key); - goto error; - } - - if (!val && (type == 'z' || type == 'y')) - continue; - - ret = virJSONValueObjectAppendNumberInt(jargs, key, val); - } break; - - case 'p': - case 'u': { - unsigned int val = va_arg(args, unsigned int); - - if (!val && type == 'p') - continue; - - ret = virJSONValueObjectAppendNumberUint(jargs, key, val); - } break; - - case 'Z': - case 'Y': - case 'J': - case 'I': { - long long val = va_arg(args, long long); - - if (val < 0 && (type == 'J' || type == 'Y')) { - virReportError(VIR_ERR_INTERNAL_ERROR, - _("argument key '%s' must not be negative"), - key); - goto error; - } - - if (!val && (type == 'Z' || type == 'Y')) - continue; - - ret = virJSONValueObjectAppendNumberLong(jargs, key, val); - } break; - - case 'P': - case 'U': { - /* qemu silently truncates numbers larger than LLONG_MAX, - * so passing the full range of unsigned 64 bit integers - * is not safe here. Pass them as signed 64 bit integers - * instead. - */ - long long val = va_arg(args, long long); - - if (!val && type == 'P') - continue; - - ret = virJSONValueObjectAppendNumberLong(jargs, key, val); - } break; - - case 'd': { - double val = va_arg(args, double); - ret = virJSONValueObjectAppendNumberDouble(jargs, key, val); - } break; - - case 'B': - case 'b': { - int val = va_arg(args, int); - - if (!val && type == 'B') - continue; - - ret = virJSONValueObjectAppendBoolean(jargs, key, val); - } break; - - case 'n': { - ret = virJSONValueObjectAppendNull(jargs, key); - } break; - - case 'a': { - virJSONValuePtr val = va_arg(args, virJSONValuePtr); - ret = virJSONValueObjectAppend(jargs, key, val); - } break; - - default: - virReportError(VIR_ERR_INTERNAL_ERROR, - _("unsupported data type '%c' for arg '%s'"), type, key - 2); - goto error; - } - if (ret < 0) - goto error; - } + if (virJSONValueObjectCreateVArgs(&jargs, args) < 0) + goto error; if (jargs && virJSONValueObjectAppend(obj, wrap ? "data" : "arguments", jargs) < 0) diff --git a/src/util/virjson.c b/src/util/virjson.c index ec83b2f..0dfeaed 100644 --- a/src/util/virjson.c +++ b/src/util/virjson.c @@ -63,6 +63,217 @@ struct _virJSONParser { }; +/** + * virJSONValueObjectCreateVArgs: + * @obj: returns the created JSON object + * @...: a key-value argument pairs, terminated by NULL + * + * Creates a JSON value object filled with key-value pairs supplied as variable + * argument list. + * + * Keys look like s:name the first letter is a type code: + * Explanation of type codes: + * s: string value, must be non-null + * S: string value, omitted if null + * + * i: signed integer value + * j: signed integer value, error if negative + * z: signed integer value, omitted if zero + * y: signed integer value, omitted if zero, error if negative + * + * I: signed long integer value + * J: signed long integer value, error if negative + * Z: signed long integer value, omitted if zero + * Y: signed long integer value, omitted if zero, error if negative + * + * u: unsigned integer value + * p: unsigned integer value, omitted if zero + * + * U: unsigned long integer value (see below for quirks) + * P: unsigned long integer value, omitted if zero + * + * b: boolean value + * B: boolean value, omitted if false + * + * d: double precision floating point number + * n: json null value + * a: json array + * + * The value corresponds to the selected type. + * + * Returns -1 on error. 1 on success, if at least one key:pair was valid 0 + * in case of no error but nothing was filled (@obj will be NULL). + */ +int +virJSONValueObjectCreateVArgs(virJSONValuePtr *obj, va_list args) +{ + virJSONValuePtr jargs = NULL; + char type; + char *key; + int ret = -1; + int rc = -2; /* -2 is a sentinel to check if at least one entry was added */ + + *obj = NULL; + + if (!(jargs = virJSONValueNewObject())) + goto cleanup; + + while ((key = va_arg(args, char *)) != NULL) { + + if (strlen(key) < 3) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("argument key '%s' is too short, missing type prefix"), + key); + goto cleanup; + } + + type = key[0]; + key += 2; + + /* This doesn't support maps, but no command uses those. */ + switch (type) { + case 'S': + case 's': { + char *val = va_arg(args, char *); + if (!val) { + if (type == 'S') + continue; + + virReportError(VIR_ERR_INTERNAL_ERROR, + _("argument key '%s' must not have null value"), + key); + goto cleanup; + } + rc = virJSONValueObjectAppendString(jargs, key, val); + } break; + + case 'z': + case 'y': + case 'j': + case 'i': { + int val = va_arg(args, int); + + if (val < 0 && (type == 'j' || type == 'y')) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("argument key '%s' must not be negative"), + key); + goto cleanup; + } + + if (!val && (type == 'z' || type == 'y')) + continue; + + rc = virJSONValueObjectAppendNumberInt(jargs, key, val); + } break; + + case 'p': + case 'u': { + unsigned int val = va_arg(args, unsigned int); + + if (!val && type == 'p') + continue; + + rc = virJSONValueObjectAppendNumberUint(jargs, key, val); + } break; + + case 'Z': + case 'Y': + case 'J': + case 'I': { + long long val = va_arg(args, long long); + + if (val < 0 && (type == 'J' || type == 'Y')) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("argument key '%s' must not be negative"), + key); + goto cleanup; + } + + if (!val && (type == 'Z' || type == 'Y')) + continue; + + rc = virJSONValueObjectAppendNumberLong(jargs, key, val); + } break; + + case 'P': + case 'U': { + /* qemu silently truncates numbers larger than LLONG_MAX, + * so passing the full range of unsigned 64 bit integers + * is not safe here. Pass them as signed 64 bit integers + * instead. + */ + long long val = va_arg(args, long long); + + if (!val && type == 'P') + continue; + + rc = virJSONValueObjectAppendNumberLong(jargs, key, val); + } break; + + case 'd': { + double val = va_arg(args, double); + rc = virJSONValueObjectAppendNumberDouble(jargs, key, val); + } break; + + case 'B': + case 'b': { + int val = va_arg(args, int); + + if (!val && type == 'B') + continue; + + rc = virJSONValueObjectAppendBoolean(jargs, key, val); + } break; + + case 'n': { + rc = virJSONValueObjectAppendNull(jargs, key); + } break; + + case 'a': { + virJSONValuePtr val = va_arg(args, virJSONValuePtr); + rc = virJSONValueObjectAppend(jargs, key, val); + } break; + + default: + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unsupported data type '%c' for arg '%s'"), type, key - 2); + goto cleanup; + } + + if (rc < 0) + goto cleanup; + } + + /* verify that we added at least one key-value pair */ + if (rc == -2) { + ret = 0; + goto cleanup; + } + + *obj = jargs; + jargs = NULL; + ret = 1; + + cleanup: + virJSONValueFree(jargs); + return ret; +} + + +int +virJSONValueObjectCreate(virJSONValuePtr *obj, ...) +{ + va_list args; + int ret; + + va_start(args, obj); + ret = virJSONValueObjectCreateVArgs(obj, args); + va_end(args); + + return ret; +} + + void virJSONValueFree(virJSONValuePtr value) { diff --git a/src/util/virjson.h b/src/util/virjson.h index 9487729..be603ae 100644 --- a/src/util/virjson.h +++ b/src/util/virjson.h @@ -26,6 +26,8 @@ # include "internal.h" +# include <stdarg.h> + typedef enum { VIR_JSON_TYPE_OBJECT, @@ -79,6 +81,9 @@ struct _virJSONValue { void virJSONValueFree(virJSONValuePtr value); +int virJSONValueObjectCreate(virJSONValuePtr *obj, ...); +int virJSONValueObjectCreateVArgs(virJSONValuePtr *obj, va_list args); + virJSONValuePtr virJSONValueNewString(const char *data); virJSONValuePtr virJSONValueNewStringLen(const char *data, size_t length); virJSONValuePtr virJSONValueNewNumberInt(int data); -- 2.1.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list