aboutsummaryrefslogtreecommitdiff
path: root/util/keyval.c
AgeCommit message (Collapse)AuthorFilesLines
2020-12-19keyval: Use GString to accumulate value stringsMarkus Armbruster1-5/+6
QString supports modifying its string, but it's quite limited: you can only append. The remaining callers use it for building an initial string, never for modifying it later. Change keyval_parse_one() to do build the initial string with GString. This is another step towards making QString immutable. Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <20201211171152.146877-19-armbru@redhat.com>
2020-10-15keyval: Parse help optionsKevin Wolf1-12/+51
This adds a special meaning for 'help' and '?' as options to the keyval parser. Instead of being an error (because of a missing value) or a value for an implied key, they now request help, which is a new boolean output of the parser in addition to the QDict. A new parameter 'p_help' is added to keyval_parse() that contains on return whether help was requested. If NULL is passed, requesting help results in an error and all other cases work like before. Turning previous error cases into help is a compatible extension. The behaviour potentially changes for implied keys: They could previously get 'help' as their value, which is now interpreted as requesting help. This is not a problem in practice because 'help' and '?' are not a valid values for the implied key of any option parsed with keyval_parse(): * audiodev: union Audiodev, implied key "driver" is enum AudiodevDriver, "help" and "?" are not among its values * display: union DisplayOptions, implied key "type" is enum DisplayType, "help" and "?" are not among its values * blockdev: union BlockdevOptions, implied key "driver is enum BlockdevDriver, "help" and "?" are not among its values * export: union BlockExport, implied key "type" is enum BlockExportType, "help" and "?" are not among its values * monitor: struct MonitorOptions, implied key "mode" is enum MonitorMode, "help" and "?" are not among its values * nbd-server: struct NbdServerOptions, no implied key. Signed-off-by: Kevin Wolf <kwolf@redhat.com> Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <20201011073505.1185335-5-armbru@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2020-10-15keyval: Fix parsing of ',' in value of implied keyMarkus Armbruster1-11/+17
The previous commit demonstrated documentation and code disagree on parsing of ',' in the value of an implied key. Fix the code to match the documentation. This breaks uses of keyval_parse() that pass an implied key and accept a value containing ','. None of the existing uses does: * audiodev: implied key "driver" is enum AudiodevDriver, none of the values contains ',' * display: implied key "type" is enum DisplayType, none of the values contains ',' * blockdev: implied key "driver is enum BlockdevDriver, none of the values contains ',' * export: implied key "type" is enum BlockExportType, none of the values contains ',' * monitor: implied key "mode" is enum MonitorMode, none of the values contains ',' * nbd-server: no implied key. Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <20201011073505.1185335-4-armbru@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2020-10-15keyval: Fix and clarify grammarMarkus Armbruster1-6/+10
The grammar has a few issues: * key-fragment = / [^=,.]* / Prose restricts key fragments: they "must be valid QAPI names or consist only of decimal digits". Technically, '' consists only of decimal digits. The code rejects that. Fix the grammar. * val = { / [^,]* / | ',,' } Use + instead of *. Accepts the same language. * val-no-key = / [^=,]* / The code rejects an empty value. Fix the grammar. * Section "Additional syntax for use with an implied key" is confusing. Rewrite it. Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <20201011073505.1185335-2-armbru@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2018-05-04qobject: Replace qobject_incref/QINCREF qobject_decref/QDECREFMarc-André Lureau1-6/+6
Now that we can safely call QOBJECT() on QObject * as well as its subtypes, we can have macros qobject_ref() / qobject_unref() that work everywhere instead of having to use QINCREF() / QDECREF() for QObject and qobject_incref() / qobject_decref() for its subtypes. The replacement is mechanical, except I broke a long line, and added a cast in monitor_qmp_cleanup_req_queue_locked(). Unlike qobject_decref(), qobject_unref() doesn't accept void *. Note that the new macros evaluate their argument exactly once, thus no need to shout them. Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Message-Id: <20180419150145.24795-4-marcandre.lureau@redhat.com> Reviewed-by: Markus Armbruster <armbru@redhat.com> [Rebased, semantic conflict resolved, commit message improved] Signed-off-by: Markus Armbruster <armbru@redhat.com>
2018-03-19qapi: Replace qobject_to_X(o) by qobject_to(X, o)Max Reitz1-2/+2
This patch was generated using the following Coccinelle script: @@ expression Obj; @@ ( - qobject_to_qnum(Obj) + qobject_to(QNum, Obj) | - qobject_to_qstring(Obj) + qobject_to(QString, Obj) | - qobject_to_qdict(Obj) + qobject_to(QDict, Obj) | - qobject_to_qlist(Obj) + qobject_to(QList, Obj) | - qobject_to_qbool(Obj) + qobject_to(QBool, Obj) ) and a bit of manual fix-up for overly long lines and three places in tests/check-qjson.c that Coccinelle did not find. Signed-off-by: Max Reitz <mreitz@redhat.com> Reviewed-by: Alberto Garcia <berto@igalia.com> Message-Id: <20180224154033.29559-4-mreitz@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> [eblake: swap order from qobject_to(o, X), rebase to master, also a fix to latent false-positive compiler complaint about hw/i386/acpi-build.c] Signed-off-by: Eric Blake <eblake@redhat.com>
2018-02-09Include qapi/qmp/qdict.h exactly where neededMarkus Armbruster1-0/+1
This cleanup makes the number of objects depending on qapi/qmp/qdict.h drop from 4550 (out of 4743) to 368 in my "build everything" tree. For qapi/qmp/qobject.h, the number drops from 4552 to 390. While there, separate #include from file comment with a blank line. Reviewed-by: Eric Blake <eblake@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <20180201111846.21846-13-armbru@redhat.com>
2018-02-09Include qapi/qmp/qlist.h exactly where neededMarkus Armbruster1-0/+1
This cleanup makes the number of objects depending on qapi/qmp/qlist.h drop from 4551 (out of 4743) to 16 in my "build everything" tree. While there, separate #include from file comment with a blank line. Reviewed-by: Eric Blake <eblake@redhat.com> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <20180201111846.21846-12-armbru@redhat.com>
2017-09-04qapi: Generate FOO_str() macro for QAPI enum FOOMarkus Armbruster1-1/+0
The next commit will put it to use. May look pointless now, but we're going to change the FOO_lookup's type, and then it'll help. Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <1503564371-26090-13-git-send-email-armbru@redhat.com> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
2017-05-31qapi: Reject alternates that can't work with keyval_parse()Markus Armbruster1-5/+5
Alternates are sum types like unions, but use the JSON type on the wire / QType in QObject instead of an explicit tag. That's why we require alternate members to have distinct QTypes. The recently introduced keyval_parse() (commit d454dbe) can only produce string scalars. The qobject_input_visitor_new_keyval() input visitor mostly hides the difference, so code using a QObject input visitor doesn't have to care whether its input was parsed from JSON or KEY=VALUE,... The difference leaks for alternates, as noted in commit 0ee9ae7: a non-string, non-enum scalar alternate value can't currently be expressed. In part, this is just our insufficiently sophisticated implementation. Consider alternate type 'GuestFileWhence'. It has an integer member and a 'QGASeek' member. The latter is an enumeration with values 'set', 'cur', 'end'. The meaning of b=set, b=cur, b=end, b=0, b=1 and so forth is perfectly obvious. However, our current implementation falls apart at run time for b=0, b=1, and so forth. Fixable, but not today; add a test case and a TODO comment. Now consider an alternate type with a string and an integer member. What's the meaning of a=42? Is it the string "42" or the integer 42? Whichever meaning you pick makes the other inexpressible. This isn't just an implementation problem, it's fundamental. Our current implementation will pick string. So far, we haven't needed such alternates. To make sure we stop and think before we add one that cannot sanely work with keyval_parse(), let's require alternate members to have sufficiently distinct representation in KEY=VALUE,... syntax: * A string member clashes with any other scalar member * An enumeration member clashes with bool members when it has value 'on' or 'off'. * An enumeration member clashes with numeric members when it has a value that starts with '-', '+', or a decimal digit. This is a rather lazy approximation of the actual number syntax accepted by the visitor. Note that enumeration values starting with '-' and '+' are rejected elsewhere already, but better safe than sorry. Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <1495471335-23707-5-git-send-email-armbru@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com> Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
2017-03-21keyval: Document issues with 'any' and alternate typesMarkus Armbruster1-0/+10
Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <1490014548-15083-5-git-send-email-armbru@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com>
2017-03-21keyval: Improve some commentsMarkus Armbruster1-16/+31
Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <1490014548-15083-3-git-send-email-armbru@redhat.com> Reviewed-by: Eric Blake <eblake@redhat.com>
2017-03-07keyval: Support listsMarkus Armbruster1-12/+171
Additionally permit non-negative integers as key components. A dictionary's keys must either be all integers or none. If all keys are integers, convert the dictionary to a list. The set of keys must be [0,N]. Examples: * list.1=goner,list.0=null,list.1=eins,list.2=zwei is equivalent to JSON [ "null", "eins", "zwei" ] * a.b.c=1,a.b.0=2 is inconsistent: a.b.c clashes with a.b.0 * list.0=null,list.2=eins,list.2=zwei has a hole: list.1 is missing Similar design flaw as for objects: there is no way to denote an empty list. While interpreting "key absent" as empty list seems natural (removing a list member from the input string works when there are multiple ones, so why not when there's just one), it doesn't work: "key absent" already means "optional list absent", which isn't the same as "empty list present". Update the keyval object visitor to use this a.0 syntax in error messages rather than the usual a[0]. Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <1488317230-26248-25-git-send-email-armbru@redhat.com> [Off-by-one fix squashed in, as per Kevin's review] Reviewed-by: Kevin Wolf <kwolf@redhat.com>
2017-03-07keyval: Restrict key components to valid QAPI namesMarkus Armbruster1-4/+8
Until now, key components are separated by '.'. This leaves little room for evolving the syntax, and is incompatible with the __RFQDN_ prefix convention for downstream extensions. Since key components will be commonly used as QAPI member names by the QObject input visitor, we can just as well borrow the QAPI naming rules here: letters, digits, hyphen and period starting with a letter, with an optional __RFQDN_ prefix for downstream extensions. Signed-off-by: Markus Armbruster <armbru@redhat.com> Reviewed-by: Kevin Wolf <kwolf@redhat.com> Message-Id: <1488317230-26248-20-git-send-email-armbru@redhat.com>
2017-03-07keyval: New keyval_parse()Markus Armbruster1-0/+231
keyval_parse() parses KEY=VALUE,... into a QDict. Works like qemu_opts_parse(), except: * Returns a QDict instead of a QemuOpts (d'oh). * Supports nesting, unlike QemuOpts: a KEY is split into key fragments at '.' (dotted key convention; the block layer does something similar on top of QemuOpts). The key fragments are QDict keys, and the last one's value is updated to VALUE. * Each key fragment may be up to 127 bytes long. qemu_opts_parse() limits the entire key to 127 bytes. * Overlong key fragments are rejected. qemu_opts_parse() silently truncates them. * Empty key fragments are rejected. qemu_opts_parse() happily accepts empty keys. * It does not store the returned value. qemu_opts_parse() stores it in the QemuOptsList. * It does not treat parameter "id" specially. qemu_opts_parse() ignores all but the first "id", and fails when its value isn't id_wellformed(), or duplicate (a QemuOpts with the same ID is already stored). It also screws up when a value contains ",id=". * Implied value is not supported. qemu_opts_parse() desugars "foo" to "foo=on", and "nofoo" to "foo=off". * An implied key's value can't be empty, and can't contain ','. I intend to grow this into a saner replacement for QemuOpts. It'll take time, though. Note: keyval_parse() provides no way to do lists, and its key syntax is incompatible with the __RFQDN_ prefix convention for downstream extensions, because it blindly splits at '.', even in __RFQDN_. Both issues will be addressed later in the series. Signed-off-by: Markus Armbruster <armbru@redhat.com> Message-Id: <1488317230-26248-4-git-send-email-armbru@redhat.com>