qapi: QMP introspection
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJV/7jVAAoJEDhwtADrkYZTzmgP/0sb+BhowenjmaOa8OD0KvPH 1paRbaZx2KqLILITwV4KbpB02Ay+i0TUeUSQA7jIxx3OaWd/gVvnR84Qz6lPgMFv DaffXoxmJCSdeR5MbyXPGullFLhqV+GmfC2/wTLf/H2pUPpBlaB5F2U9KWuhngZG 3ivM+ejL2Ya1rjqtcLl4QjAOkwd8nLTClOEoGYlre5Obiy04l7md6vibg9uzkZVA R5+yl08KbtTCdzZ4AzIX3RnbE1uJ+RPQuKcqYJVf84IEm/oor8gGQO0DsDr2dkfb s9HO0Jh0eZOWBQ+ntZwT4q64zUtea9PLwZYSp0osRE+z+VNfxL7JYdUniCSbnTBW bksWThp/UjWea02w8+HINIsoscq+WzNCouX3GLZSKvOD0VEzxGQIylr6V42o+h61 QCnRoeOLN8zET+048+/+2fUqKk3OrpULejbiXpGMz/F1mMJwCNKSBI2URhZtn6DX WQrjc/GE8hp8I/PkggBI6VyjZTk91P+L9FXGINzLMAj/I4hSA4hyH0oyf6fGfQZM 51BwvjLuRJrzGUGXpVTkDeCBunMvKoGzTH/2FIlVDjzkEtPCfGquyruEhd2AAsYJ PlzEN4kPrNUxknZU2VWTCwoOuRSbVX/JVXtYy9ykxc7O+iqZCO5TA9cxuKRDzflm 4URshvojNCfVT3ruZG56 =ut3L -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2015-09-21' into staging qapi: QMP introspection # gpg: Signature made Mon 21 Sep 2015 08:59:17 BST using RSA key ID EB918653 # gpg: Good signature from "Markus Armbruster <armbru@redhat.com>" # gpg: aka "Markus Armbruster <armbru@pond.sub.org>" * remotes/armbru/tags/pull-qapi-2015-09-21: (26 commits) qapi-introspect: Hide type names qapi: New QMP command query-qmp-schema for QMP introspection qapi: Pseudo-type '**' is now unused, drop it qapi-schema: Fix up misleading specification of netdev_add qom: Don't use 'gen': false for qom-get, qom-set, object-add qapi: Introduce a first class 'any' type qapi: Make output visitor return qnull() instead of NULL qapi: Improve built-in type documentation qapi-commands: De-duplicate output marshaling functions qapi: De-duplicate parameter list generation qapi: Rename qmp_marshal_input_FOO() to qmp_marshal_FOO() qapi-commands: Rearrange code qapi-visit: Rearrange code a bit qapi: Clean up after recent conversions to QAPISchemaVisitor qapi: Replace dirty is_c_ptr() by method c_null() qapi-event: Convert to QAPISchemaVisitor, fixing data with base qapi-event: Eliminate global variable event_enum_value qapi: De-duplicate enum code generation qapi-commands: Convert to QAPISchemaVisitor qapi-visit: Convert to QAPISchemaVisitor, fixing bugs ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
		
						commit
						9e72681d16
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -34,6 +34,7 @@
 | 
			
		||||
/qapi-visit.[ch]
 | 
			
		||||
/qapi-event.[ch]
 | 
			
		||||
/qmp-commands.h
 | 
			
		||||
/qmp-introspect.[ch]
 | 
			
		||||
/qmp-marshal.c
 | 
			
		||||
/qemu-doc.html
 | 
			
		||||
/qemu-tech.html
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										9
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								Makefile
									
									
									
									
									
								
							@ -52,6 +52,8 @@ endif
 | 
			
		||||
GENERATED_HEADERS = config-host.h qemu-options.def
 | 
			
		||||
GENERATED_HEADERS += qmp-commands.h qapi-types.h qapi-visit.h qapi-event.h
 | 
			
		||||
GENERATED_SOURCES += qmp-marshal.c qapi-types.c qapi-visit.c qapi-event.c
 | 
			
		||||
GENERATED_HEADERS += qmp-introspect.h
 | 
			
		||||
GENERATED_SOURCES += qmp-introspect.c
 | 
			
		||||
 | 
			
		||||
GENERATED_HEADERS += trace/generated-events.h
 | 
			
		||||
GENERATED_SOURCES += trace/generated-events.c
 | 
			
		||||
@ -269,7 +271,7 @@ $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
 | 
			
		||||
 | 
			
		||||
qapi-modules = $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/qapi/common.json \
 | 
			
		||||
               $(SRC_PATH)/qapi/block.json $(SRC_PATH)/qapi/block-core.json \
 | 
			
		||||
               $(SRC_PATH)/qapi/event.json
 | 
			
		||||
               $(SRC_PATH)/qapi/event.json $(SRC_PATH)/qapi/introspect.json
 | 
			
		||||
 | 
			
		||||
qapi-types.c qapi-types.h :\
 | 
			
		||||
$(qapi-modules) $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
 | 
			
		||||
@ -291,6 +293,11 @@ $(qapi-modules) $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py)
 | 
			
		||||
	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py \
 | 
			
		||||
		$(gen-out-type) -o "." -m $<, \
 | 
			
		||||
		"  GEN   $@")
 | 
			
		||||
qmp-introspect.h qmp-introspect.c :\
 | 
			
		||||
$(qapi-modules) $(SRC_PATH)/scripts/qapi-introspect.py $(qapi-py)
 | 
			
		||||
	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-introspect.py \
 | 
			
		||||
		$(gen-out-type) -o "." $<, \
 | 
			
		||||
		"  GEN   $@")
 | 
			
		||||
 | 
			
		||||
QGALIB_GEN=$(addprefix qga/qapi-generated/, qga-qapi-types.h qga-qapi-visit.h qga-qmp-commands.h)
 | 
			
		||||
$(qga-obj-y) qemu-ga.o: $(QGALIB_GEN)
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,8 @@
 | 
			
		||||
#######################################################################
 | 
			
		||||
# Common libraries for tools and emulators
 | 
			
		||||
stub-obj-y = stubs/
 | 
			
		||||
util-obj-y = util/ qobject/ qapi/ qapi-types.o qapi-visit.o qapi-event.o
 | 
			
		||||
util-obj-y = util/ qobject/ qapi/
 | 
			
		||||
util-obj-y += qmp-introspect.o qapi-types.o qapi-visit.o qapi-event.o
 | 
			
		||||
 | 
			
		||||
#######################################################################
 | 
			
		||||
# block-obj-y is code used by both qemu system emulation and qemu-img
 | 
			
		||||
@ -92,6 +93,7 @@ common-obj-$(CONFIG_FDT) += device_tree.o
 | 
			
		||||
# qapi
 | 
			
		||||
 | 
			
		||||
common-obj-y += qmp-marshal.o
 | 
			
		||||
common-obj-y += qmp-introspect.o
 | 
			
		||||
common-obj-y += qmp.o hmp.o
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -111,10 +111,7 @@ and field names within a type, should be all lower case with words
 | 
			
		||||
separated by a hyphen.  However, some existing older commands and
 | 
			
		||||
complex types use underscore; when extending such expressions,
 | 
			
		||||
consistency is preferred over blindly avoiding underscore.  Event
 | 
			
		||||
names should be ALL_CAPS with words separated by underscore.  The
 | 
			
		||||
special string '**' appears for some commands that manually perform
 | 
			
		||||
their own type checking rather than relying on the type-safe code
 | 
			
		||||
produced by the qapi code generators.
 | 
			
		||||
names should be ALL_CAPS with words separated by underscore.
 | 
			
		||||
 | 
			
		||||
Any name (command, event, type, field, or enum value) beginning with
 | 
			
		||||
"x-" is marked experimental, and may be withdrawn or changed
 | 
			
		||||
@ -140,17 +137,25 @@ must have a value that forms a struct name.
 | 
			
		||||
 | 
			
		||||
=== Built-in Types ===
 | 
			
		||||
 | 
			
		||||
The following types are built-in to the parser:
 | 
			
		||||
  'str' - arbitrary UTF-8 string
 | 
			
		||||
  'int' - 64-bit signed integer (although the C code may place further
 | 
			
		||||
          restrictions on acceptable range)
 | 
			
		||||
  'number' - floating point number
 | 
			
		||||
  'bool' - JSON value of true or false
 | 
			
		||||
  'int8', 'int16', 'int32', 'int64' - like 'int', but enforce maximum
 | 
			
		||||
                                      bit size
 | 
			
		||||
  'uint8', 'uint16', 'uint32', 'uint64' - unsigned counterparts
 | 
			
		||||
  'size' - like 'uint64', but allows scaled suffix from command line
 | 
			
		||||
           visitor
 | 
			
		||||
The following types are predefined, and map to C as follows:
 | 
			
		||||
 | 
			
		||||
  Schema    C          JSON
 | 
			
		||||
  str       char *     any JSON string, UTF-8
 | 
			
		||||
  number    double     any JSON number
 | 
			
		||||
  int       int64_t    a JSON number without fractional part
 | 
			
		||||
                       that fits into the C integer type
 | 
			
		||||
  int8      int8_t     likewise
 | 
			
		||||
  int16     int16_t    likewise
 | 
			
		||||
  int32     int32_t    likewise
 | 
			
		||||
  int64     int64_t    likewise
 | 
			
		||||
  uint8     uint8_t    likewise
 | 
			
		||||
  uint16    uint16_t   likewise
 | 
			
		||||
  uint32    uint32_t   likewise
 | 
			
		||||
  uint64    uint64_t   likewise
 | 
			
		||||
  size      uint64_t   like uint64_t, except StringInputVisitor
 | 
			
		||||
                       accepts size suffixes
 | 
			
		||||
  bool      bool       JSON true or false
 | 
			
		||||
  any       QObject *  any JSON value
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
=== Includes ===
 | 
			
		||||
@ -453,17 +458,14 @@ which would validate this Client JSON Protocol transaction:
 | 
			
		||||
 <= { "return": [ { "value": "one" }, { } ] }
 | 
			
		||||
 | 
			
		||||
In rare cases, QAPI cannot express a type-safe representation of a
 | 
			
		||||
corresponding Client JSON Protocol command.  In these cases, if the
 | 
			
		||||
command expression includes the key 'gen' with boolean value false,
 | 
			
		||||
then the 'data' or 'returns' member that intends to bypass generated
 | 
			
		||||
type-safety and do its own manual validation should use an inline
 | 
			
		||||
dictionary definition, with a value of '**' rather than a valid type
 | 
			
		||||
name for the keys that the generated code will not validate.  Please
 | 
			
		||||
try to avoid adding new commands that rely on this, and instead use
 | 
			
		||||
type-safe unions.  For an example of bypass usage:
 | 
			
		||||
corresponding Client JSON Protocol command.  You then have to suppress
 | 
			
		||||
generation of a marshalling function by including a key 'gen' with
 | 
			
		||||
boolean value false, and instead write your own function.  Please try
 | 
			
		||||
to avoid adding new commands that rely on this, and instead use
 | 
			
		||||
type-safe unions.  For an example of this usage:
 | 
			
		||||
 | 
			
		||||
 { 'command': 'netdev_add',
 | 
			
		||||
   'data': {'type': 'str', 'id': 'str', '*props': '**'},
 | 
			
		||||
   'data': {'type': 'str', 'id': 'str'},
 | 
			
		||||
   'gen': false }
 | 
			
		||||
 | 
			
		||||
Normally, the QAPI schema is used to describe synchronous exchanges,
 | 
			
		||||
@ -500,13 +502,204 @@ Resulting in this JSON object:
 | 
			
		||||
  "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
== Client JSON Protocol introspection ==
 | 
			
		||||
 | 
			
		||||
Clients of a Client JSON Protocol commonly need to figure out what
 | 
			
		||||
exactly the server (QEMU) supports.
 | 
			
		||||
 | 
			
		||||
For this purpose, QMP provides introspection via command
 | 
			
		||||
query-qmp-schema.  QGA currently doesn't support introspection.
 | 
			
		||||
 | 
			
		||||
query-qmp-schema returns a JSON array of SchemaInfo objects.  These
 | 
			
		||||
objects together describe the wire ABI, as defined in the QAPI schema.
 | 
			
		||||
 | 
			
		||||
However, the SchemaInfo can't reflect all the rules and restrictions
 | 
			
		||||
that apply to QMP.  It's interface introspection (figuring out what's
 | 
			
		||||
there), not interface specification.  The specification is in the QAPI
 | 
			
		||||
schema.  To understand how QMP is to be used, you need to study the
 | 
			
		||||
QAPI schema.
 | 
			
		||||
 | 
			
		||||
Like any other command, query-qmp-schema is itself defined in the QAPI
 | 
			
		||||
schema, along with the SchemaInfo type.  This text attempts to give an
 | 
			
		||||
overview how things work.  For details you need to consult the QAPI
 | 
			
		||||
schema.
 | 
			
		||||
 | 
			
		||||
SchemaInfo objects have common members "name" and "meta-type", and
 | 
			
		||||
additional variant members depending on the value of meta-type.
 | 
			
		||||
 | 
			
		||||
Each SchemaInfo object describes a wire ABI entity of a certain
 | 
			
		||||
meta-type: a command, event or one of several kinds of type.
 | 
			
		||||
 | 
			
		||||
SchemaInfo for commands and events have the same name as in the QAPI
 | 
			
		||||
schema.
 | 
			
		||||
 | 
			
		||||
Command and event names are part of the wire ABI, but type names are
 | 
			
		||||
not.  Therefore, the SchemaInfo for types have auto-generated
 | 
			
		||||
meaningless names.  For readability, the examples in this section use
 | 
			
		||||
meaningful type names instead.
 | 
			
		||||
 | 
			
		||||
To examine a type, start with a command or event using it, then follow
 | 
			
		||||
references by name.
 | 
			
		||||
 | 
			
		||||
QAPI schema definitions not reachable that way are omitted.
 | 
			
		||||
 | 
			
		||||
The SchemaInfo for a command has meta-type "command", and variant
 | 
			
		||||
members "arg-type" and "ret-type".  On the wire, the "arguments"
 | 
			
		||||
member of a client's "execute" command must conform to the object type
 | 
			
		||||
named by "arg-type".  The "return" member that the server passes in a
 | 
			
		||||
success response conforms to the type named by "ret-type".
 | 
			
		||||
 | 
			
		||||
If the command takes no arguments, "arg-type" names an object type
 | 
			
		||||
without members.  Likewise, if the command returns nothing, "ret-type"
 | 
			
		||||
names an object type without members.
 | 
			
		||||
 | 
			
		||||
Example: the SchemaInfo for command query-qmp-schema
 | 
			
		||||
 | 
			
		||||
    { "name": "query-qmp-schema", "meta-type": "command",
 | 
			
		||||
      "arg-type": ":empty", "ret-type": "SchemaInfoList" }
 | 
			
		||||
 | 
			
		||||
    Type ":empty" is an object type without members, and type
 | 
			
		||||
    "SchemaInfoList" is the array of SchemaInfo type.
 | 
			
		||||
 | 
			
		||||
The SchemaInfo for an event has meta-type "event", and variant member
 | 
			
		||||
"arg-type".  On the wire, a "data" member that the server passes in an
 | 
			
		||||
event conforms to the object type named by "arg-type".
 | 
			
		||||
 | 
			
		||||
If the event carries no additional information, "arg-type" names an
 | 
			
		||||
object type without members.  The event may not have a data member on
 | 
			
		||||
the wire then.
 | 
			
		||||
 | 
			
		||||
Each command or event defined with dictionary-valued 'data' in the
 | 
			
		||||
QAPI schema implicitly defines an object type.
 | 
			
		||||
 | 
			
		||||
Example: the SchemaInfo for EVENT_C from section Events
 | 
			
		||||
 | 
			
		||||
    { "name": "EVENT_C", "meta-type": "event",
 | 
			
		||||
      "arg-type": ":obj-EVENT_C-arg" }
 | 
			
		||||
 | 
			
		||||
    Type ":obj-EVENT_C-arg" is an implicitly defined object type with
 | 
			
		||||
    the two members from the event's definition.
 | 
			
		||||
 | 
			
		||||
The SchemaInfo for struct and union types has meta-type "object".
 | 
			
		||||
 | 
			
		||||
The SchemaInfo for a struct type has variant member "members".
 | 
			
		||||
 | 
			
		||||
The SchemaInfo for a union type additionally has variant members "tag"
 | 
			
		||||
and "variants".
 | 
			
		||||
 | 
			
		||||
"members" is a JSON array describing the object's common members, if
 | 
			
		||||
any.  Each element is a JSON object with members "name" (the member's
 | 
			
		||||
name), "type" (the name of its type), and optionally "default".  The
 | 
			
		||||
member is optional if "default" is present.  Currently, "default" can
 | 
			
		||||
only have value null.  Other values are reserved for future
 | 
			
		||||
extensions.
 | 
			
		||||
 | 
			
		||||
Example: the SchemaInfo for MyType from section Struct types
 | 
			
		||||
 | 
			
		||||
    { "name": "MyType", "meta-type": "object",
 | 
			
		||||
      "members": [
 | 
			
		||||
          { "name": "member1", "type": "str" },
 | 
			
		||||
          { "name": "member2", "type": "int" },
 | 
			
		||||
          { "name": "member3", "type": "str", "default": null } ] }
 | 
			
		||||
 | 
			
		||||
"tag" is the name of the common member serving as type tag.
 | 
			
		||||
"variants" is a JSON array describing the object's variant members.
 | 
			
		||||
Each element is a JSON object with members "case" (the value of type
 | 
			
		||||
tag this element applies to) and "type" (the name of an object type
 | 
			
		||||
that provides the variant members for this type tag value).
 | 
			
		||||
 | 
			
		||||
Example: the SchemaInfo for flat union BlockdevOptions from section
 | 
			
		||||
Union types
 | 
			
		||||
 | 
			
		||||
    { "name": "BlockdevOptions", "meta-type": "object",
 | 
			
		||||
      "members": [
 | 
			
		||||
          { "name": "driver", "type": "BlockdevDriver" },
 | 
			
		||||
          { "name": "readonly", "type": "bool"} ],
 | 
			
		||||
      "tag": "driver",
 | 
			
		||||
      "variants": [
 | 
			
		||||
          { "case": "file", "type": "FileOptions" },
 | 
			
		||||
          { "case": "qcow2", "type": "Qcow2Options" } ] }
 | 
			
		||||
 | 
			
		||||
Note that base types are "flattened": its members are included in the
 | 
			
		||||
"members" array.
 | 
			
		||||
 | 
			
		||||
A simple union implicitly defines an enumeration type for its implicit
 | 
			
		||||
discriminator (called "type" on the wire, see section Union types).
 | 
			
		||||
 | 
			
		||||
A simple union implicitly defines an object type for each of its
 | 
			
		||||
variants.
 | 
			
		||||
 | 
			
		||||
Example: the SchemaInfo for simple union BlockdevOptions from section
 | 
			
		||||
Union types
 | 
			
		||||
 | 
			
		||||
    { "name": "BlockdevOptions", "meta-type": "object",
 | 
			
		||||
      "members": [
 | 
			
		||||
          { "name": "kind", "type": "BlockdevOptionsKind" } ],
 | 
			
		||||
      "tag": "type",
 | 
			
		||||
      "variants": [
 | 
			
		||||
          { "case": "file", "type": ":obj-FileOptions-wrapper" },
 | 
			
		||||
          { "case": "qcow2", "type": ":obj-Qcow2Options-wrapper" } ] }
 | 
			
		||||
 | 
			
		||||
    Enumeration type "BlockdevOptionsKind" and the object types
 | 
			
		||||
    ":obj-FileOptions-wrapper", ":obj-Qcow2Options-wrapper" are
 | 
			
		||||
    implicitly defined.
 | 
			
		||||
 | 
			
		||||
The SchemaInfo for an alternate type has meta-type "alternate", and
 | 
			
		||||
variant member "members".  "members" is a JSON array.  Each element is
 | 
			
		||||
a JSON object with member "type", which names a type.  Values of the
 | 
			
		||||
alternate type conform to exactly one of its member types.
 | 
			
		||||
 | 
			
		||||
Example: the SchemaInfo for BlockRef from section Alternate types
 | 
			
		||||
 | 
			
		||||
    { "name": "BlockRef", "meta-type": "alternate",
 | 
			
		||||
      "members": [
 | 
			
		||||
          { "type": "BlockdevOptions" },
 | 
			
		||||
          { "type": "str" } ] }
 | 
			
		||||
 | 
			
		||||
The SchemaInfo for an array type has meta-type "array", and variant
 | 
			
		||||
member "element-type", which names the array's element type.  Array
 | 
			
		||||
types are implicitly defined.
 | 
			
		||||
 | 
			
		||||
Example: the SchemaInfo for ['str']
 | 
			
		||||
 | 
			
		||||
    { "name": "strList", "meta-type": "array",
 | 
			
		||||
      "element-type": "str" }
 | 
			
		||||
 | 
			
		||||
The SchemaInfo for an enumeration type has meta-type "enum" and
 | 
			
		||||
variant member "values".
 | 
			
		||||
 | 
			
		||||
Example: the SchemaInfo for MyEnum from section Enumeration types
 | 
			
		||||
 | 
			
		||||
    { "name": "MyEnum", "meta-type": "enum",
 | 
			
		||||
      "values": [ "value1", "value2", "value3" ] }
 | 
			
		||||
 | 
			
		||||
The SchemaInfo for a built-in type has the same name as the type in
 | 
			
		||||
the QAPI schema (see section Built-in Types), with one exception
 | 
			
		||||
detailed below.  It has variant member "json-type" that shows how
 | 
			
		||||
values of this type are encoded on the wire.
 | 
			
		||||
 | 
			
		||||
Example: the SchemaInfo for str
 | 
			
		||||
 | 
			
		||||
    { "name": "str", "meta-type": "builtin", "json-type": "string" }
 | 
			
		||||
 | 
			
		||||
The QAPI schema supports a number of integer types that only differ in
 | 
			
		||||
how they map to C.  They are identical as far as SchemaInfo is
 | 
			
		||||
concerned.  Therefore, they get all mapped to a single type "int" in
 | 
			
		||||
SchemaInfo.
 | 
			
		||||
 | 
			
		||||
As explained above, type names are not part of the wire ABI.  Not even
 | 
			
		||||
the names of built-in types.  Clients should examine member
 | 
			
		||||
"json-type" instead of hard-coding names of built-in types.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
== Code generation ==
 | 
			
		||||
 | 
			
		||||
Schemas are fed into 3 scripts to generate all the code/files that, paired
 | 
			
		||||
with the core QAPI libraries, comprise everything required to take JSON
 | 
			
		||||
commands read in by a Client JSON Protocol server, unmarshal the arguments into
 | 
			
		||||
the underlying C types, call into the corresponding C function, and map the
 | 
			
		||||
response back to a Client JSON Protocol response to be returned to the user.
 | 
			
		||||
Schemas are fed into four scripts to generate all the code/files that,
 | 
			
		||||
paired with the core QAPI libraries, comprise everything required to
 | 
			
		||||
take JSON commands read in by a Client JSON Protocol server, unmarshal
 | 
			
		||||
the arguments into the underlying C types, call into the corresponding
 | 
			
		||||
C function, and map the response back to a Client JSON Protocol
 | 
			
		||||
response to be returned to the user.
 | 
			
		||||
 | 
			
		||||
As an example, we'll use the following schema, which describes a single
 | 
			
		||||
complex user-defined type (which will produce a C struct, along with a list
 | 
			
		||||
@ -545,22 +738,6 @@ Example:
 | 
			
		||||
    $ cat qapi-generated/example-qapi-types.c
 | 
			
		||||
[Uninteresting stuff omitted...]
 | 
			
		||||
 | 
			
		||||
    void qapi_free_UserDefOneList(UserDefOneList *obj)
 | 
			
		||||
    {
 | 
			
		||||
        QapiDeallocVisitor *md;
 | 
			
		||||
        Visitor *v;
 | 
			
		||||
 | 
			
		||||
        if (!obj) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        md = qapi_dealloc_visitor_new();
 | 
			
		||||
        v = qapi_dealloc_get_visitor(md);
 | 
			
		||||
        visit_type_UserDefOneList(v, &obj, NULL, NULL);
 | 
			
		||||
        qapi_dealloc_visitor_cleanup(md);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    void qapi_free_UserDefOne(UserDefOne *obj)
 | 
			
		||||
    {
 | 
			
		||||
        QapiDeallocVisitor *md;
 | 
			
		||||
@ -575,6 +752,21 @@ Example:
 | 
			
		||||
        visit_type_UserDefOne(v, &obj, NULL, NULL);
 | 
			
		||||
        qapi_dealloc_visitor_cleanup(md);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void qapi_free_UserDefOneList(UserDefOneList *obj)
 | 
			
		||||
    {
 | 
			
		||||
        QapiDeallocVisitor *md;
 | 
			
		||||
        Visitor *v;
 | 
			
		||||
 | 
			
		||||
        if (!obj) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        md = qapi_dealloc_visitor_new();
 | 
			
		||||
        v = qapi_dealloc_get_visitor(md);
 | 
			
		||||
        visit_type_UserDefOneList(v, &obj, NULL, NULL);
 | 
			
		||||
        qapi_dealloc_visitor_cleanup(md);
 | 
			
		||||
    }
 | 
			
		||||
    $ cat qapi-generated/example-qapi-types.h
 | 
			
		||||
[Uninteresting stuff omitted...]
 | 
			
		||||
 | 
			
		||||
@ -585,25 +777,25 @@ Example:
 | 
			
		||||
 | 
			
		||||
    typedef struct UserDefOne UserDefOne;
 | 
			
		||||
 | 
			
		||||
    typedef struct UserDefOneList {
 | 
			
		||||
        union {
 | 
			
		||||
            UserDefOne *value;
 | 
			
		||||
            uint64_t padding;
 | 
			
		||||
        };
 | 
			
		||||
        struct UserDefOneList *next;
 | 
			
		||||
    } UserDefOneList;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
[Functions on built-in types omitted...]
 | 
			
		||||
    typedef struct UserDefOneList UserDefOneList;
 | 
			
		||||
 | 
			
		||||
    struct UserDefOne {
 | 
			
		||||
        int64_t integer;
 | 
			
		||||
        char *string;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    void qapi_free_UserDefOneList(UserDefOneList *obj);
 | 
			
		||||
    void qapi_free_UserDefOne(UserDefOne *obj);
 | 
			
		||||
 | 
			
		||||
    struct UserDefOneList {
 | 
			
		||||
        union {
 | 
			
		||||
            UserDefOne *value;
 | 
			
		||||
            uint64_t padding;
 | 
			
		||||
        };
 | 
			
		||||
        UserDefOneList *next;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    void qapi_free_UserDefOneList(UserDefOneList *obj);
 | 
			
		||||
 | 
			
		||||
    #endif
 | 
			
		||||
 | 
			
		||||
=== scripts/qapi-visit.py ===
 | 
			
		||||
@ -722,7 +914,7 @@ Example:
 | 
			
		||||
    $ cat qapi-generated/example-qmp-marshal.c
 | 
			
		||||
[Uninteresting stuff omitted...]
 | 
			
		||||
 | 
			
		||||
    static void qmp_marshal_output_my_command(UserDefOne *ret_in, QObject **ret_out, Error **errp)
 | 
			
		||||
    static void qmp_marshal_output_UserDefOne(UserDefOne *ret_in, QObject **ret_out, Error **errp)
 | 
			
		||||
    {
 | 
			
		||||
        Error *local_err = NULL;
 | 
			
		||||
        QmpOutputVisitor *mo = qmp_output_visitor_new();
 | 
			
		||||
@ -745,7 +937,7 @@ Example:
 | 
			
		||||
        qapi_dealloc_visitor_cleanup(md);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void qmp_marshal_input_my_command(QDict *args, QObject **ret, Error **errp)
 | 
			
		||||
    static void qmp_marshal_my_command(QDict *args, QObject **ret, Error **errp)
 | 
			
		||||
    {
 | 
			
		||||
        Error *local_err = NULL;
 | 
			
		||||
        UserDefOne *retval;
 | 
			
		||||
@ -765,7 +957,7 @@ Example:
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        qmp_marshal_output_my_command(retval, ret, &local_err);
 | 
			
		||||
        qmp_marshal_output_UserDefOne(retval, ret, &local_err);
 | 
			
		||||
 | 
			
		||||
    out:
 | 
			
		||||
        error_propagate(errp, local_err);
 | 
			
		||||
@ -778,7 +970,7 @@ Example:
 | 
			
		||||
 | 
			
		||||
    static void qmp_init_marshal(void)
 | 
			
		||||
    {
 | 
			
		||||
        qmp_register_command("my-command", qmp_marshal_input_my_command, QCO_NO_OPTIONS);
 | 
			
		||||
        qmp_register_command("my-command", qmp_marshal_my_command, QCO_NO_OPTIONS);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    qapi_init(qmp_init_marshal);
 | 
			
		||||
@ -830,9 +1022,9 @@ Example:
 | 
			
		||||
        QDECREF(qmp);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const char *example_QAPIEvent_lookup[] = {
 | 
			
		||||
        "MY_EVENT",
 | 
			
		||||
        NULL,
 | 
			
		||||
    const char *const example_QAPIEvent_lookup[] = {
 | 
			
		||||
        [EXAMPLE_QAPI_EVENT_MY_EVENT] = "MY_EVENT",
 | 
			
		||||
        [EXAMPLE_QAPI_EVENT_MAX] = NULL,
 | 
			
		||||
    };
 | 
			
		||||
    $ cat qapi-generated/example-qapi-event.h
 | 
			
		||||
[Uninteresting stuff omitted...]
 | 
			
		||||
@ -847,10 +1039,45 @@ Example:
 | 
			
		||||
 | 
			
		||||
    void qapi_event_send_my_event(Error **errp);
 | 
			
		||||
 | 
			
		||||
    extern const char *example_QAPIEvent_lookup[];
 | 
			
		||||
    typedef enum example_QAPIEvent {
 | 
			
		||||
        EXAMPLE_QAPI_EVENT_MY_EVENT = 0,
 | 
			
		||||
        EXAMPLE_QAPI_EVENT_MAX = 1,
 | 
			
		||||
    } example_QAPIEvent;
 | 
			
		||||
 | 
			
		||||
    extern const char *const example_QAPIEvent_lookup[];
 | 
			
		||||
 | 
			
		||||
    #endif
 | 
			
		||||
 | 
			
		||||
=== scripts/qapi-introspect.py ===
 | 
			
		||||
 | 
			
		||||
Used to generate the introspection C code for a schema. The following
 | 
			
		||||
files are created:
 | 
			
		||||
 | 
			
		||||
$(prefix)qmp-introspect.c - Defines a string holding a JSON
 | 
			
		||||
                            description of the schema.
 | 
			
		||||
$(prefix)qmp-introspect.h - Declares the above string.
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
    $ python scripts/qapi-introspect.py --output-dir="qapi-generated"
 | 
			
		||||
    --prefix="example-" example-schema.json
 | 
			
		||||
    $ cat qapi-generated/example-qmp-introspect.c
 | 
			
		||||
[Uninteresting stuff omitted...]
 | 
			
		||||
 | 
			
		||||
    const char example_qmp_schema_json[] = "["
 | 
			
		||||
        "{\"arg-type\": \"0\", \"meta-type\": \"event\", \"name\": \"MY_EVENT\"}, "
 | 
			
		||||
        "{\"arg-type\": \"1\", \"meta-type\": \"command\", \"name\": \"my-command\", \"ret-type\": \"2\"}, "
 | 
			
		||||
        "{\"members\": [], \"meta-type\": \"object\", \"name\": \"0\"}, "
 | 
			
		||||
        "{\"members\": [{\"name\": \"arg1\", \"type\": \"2\"}], \"meta-type\": \"object\", \"name\": \"1\"}, "
 | 
			
		||||
        "{\"members\": [{\"name\": \"integer\", \"type\": \"int\"}, {\"name\": \"string\", \"type\": \"str\"}], \"meta-type\": \"object\", \"name\": \"2\"}, "
 | 
			
		||||
        "{\"json-type\": \"int\", \"meta-type\": \"builtin\", \"name\": \"int\"}, "
 | 
			
		||||
        "{\"json-type\": \"string\", \"meta-type\": \"builtin\", \"name\": \"str\"}]";
 | 
			
		||||
    $ cat qapi-generated/example-qmp-introspect.h
 | 
			
		||||
[Uninteresting stuff omitted...]
 | 
			
		||||
 | 
			
		||||
    #ifndef EXAMPLE_QMP_INTROSPECT_H
 | 
			
		||||
    #define EXAMPLE_QMP_INTROSPECT_H
 | 
			
		||||
 | 
			
		||||
    extern const char example_qmp_schema_json[];
 | 
			
		||||
 | 
			
		||||
    #endif
 | 
			
		||||
 | 
			
		||||
@ -127,7 +127,7 @@ following at the bottom:
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "hello-world",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_hello_world,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_hello_world,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
You're done. Now build qemu, run it as suggested in the "Testing" section,
 | 
			
		||||
@ -179,7 +179,7 @@ The last step is to update the qmp-commands.hx file:
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "hello-world",
 | 
			
		||||
        .args_type  = "message:s?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_hello_world,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_hello_world,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
Notice that the "args_type" member got our "message" argument. The character
 | 
			
		||||
@ -461,7 +461,7 @@ The last step is to add the correspoding entry in the qmp-commands.hx file:
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-alarm-clock",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_alarm_clock,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_alarm_clock,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
Time to test the new command. Build qemu, run it as described in the "Testing"
 | 
			
		||||
@ -607,7 +607,7 @@ To test this you have to add the corresponding qmp-commands.hx entry:
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-alarm-methods",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_alarm_methods,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_alarm_methods,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
Now Build qemu, run it as explained in the "Testing" section and try our new
 | 
			
		||||
 | 
			
		||||
@ -42,9 +42,6 @@ void monitor_read_command(Monitor *mon, int show_prompt);
 | 
			
		||||
int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
 | 
			
		||||
                          void *opaque);
 | 
			
		||||
 | 
			
		||||
void qmp_qom_set(QDict *qdict, QObject **ret, Error **errp);
 | 
			
		||||
void qmp_qom_get(QDict *qdict, QObject **ret, Error **errp);
 | 
			
		||||
void qmp_object_add(QDict *qdict, QObject **ret, Error **errp);
 | 
			
		||||
void object_add(const char *type, const char *id, const QDict *qdict,
 | 
			
		||||
                Visitor *v, Error **errp);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -40,6 +40,8 @@ struct Visitor
 | 
			
		||||
    void (*type_str)(Visitor *v, char **obj, const char *name, Error **errp);
 | 
			
		||||
    void (*type_number)(Visitor *v, double *obj, const char *name,
 | 
			
		||||
                        Error **errp);
 | 
			
		||||
    void (*type_any)(Visitor *v, QObject **obj, const char *name,
 | 
			
		||||
                     Error **errp);
 | 
			
		||||
 | 
			
		||||
    /* May be NULL */
 | 
			
		||||
    void (*optional)(Visitor *v, bool *present, const char *name,
 | 
			
		||||
 | 
			
		||||
@ -58,6 +58,7 @@ void visit_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp);
 | 
			
		||||
void visit_type_bool(Visitor *v, bool *obj, const char *name, Error **errp);
 | 
			
		||||
void visit_type_str(Visitor *v, char **obj, const char *name, Error **errp);
 | 
			
		||||
void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp);
 | 
			
		||||
void visit_type_any(Visitor *v, QObject **obj, const char *name, Error **errp);
 | 
			
		||||
bool visit_start_union(Visitor *v, bool data_present, Error **errp);
 | 
			
		||||
void visit_end_union(Visitor *v, bool data_present, Error **errp);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										18
									
								
								monitor.c
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								monitor.c
									
									
									
									
									
								
							@ -74,6 +74,7 @@
 | 
			
		||||
#include "block/qapi.h"
 | 
			
		||||
#include "qapi/qmp-event.h"
 | 
			
		||||
#include "qapi-event.h"
 | 
			
		||||
#include "qmp-introspect.h"
 | 
			
		||||
#include "sysemu/block-backend.h"
 | 
			
		||||
 | 
			
		||||
/* for hmp_info_irq/pic */
 | 
			
		||||
@ -928,6 +929,21 @@ EventInfoList *qmp_query_events(Error **errp)
 | 
			
		||||
    return ev_list;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Minor hack: generated marshalling suppressed for this command
 | 
			
		||||
 * ('gen': false in the schema) so we can parse the JSON string
 | 
			
		||||
 * directly into QObject instead of first parsing it with
 | 
			
		||||
 * visit_type_SchemaInfoList() into a SchemaInfoList, then marshal it
 | 
			
		||||
 * to QObject with generated output marshallers, every time.  Instead,
 | 
			
		||||
 * we do it in test-qmp-input-visitor.c, just to make sure
 | 
			
		||||
 * qapi-introspect.py's output actually conforms to the schema.
 | 
			
		||||
 */
 | 
			
		||||
static void qmp_query_qmp_schema(QDict *qdict, QObject **ret_data,
 | 
			
		||||
                                 Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    *ret_data = qobject_from_json(qmp_schema_json);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* set the current CPU defined by the user */
 | 
			
		||||
int monitor_set_cpu(int cpu_index)
 | 
			
		||||
{
 | 
			
		||||
@ -3912,7 +3928,7 @@ static QObject *get_qmp_greeting(void)
 | 
			
		||||
{
 | 
			
		||||
    QObject *ver = NULL;
 | 
			
		||||
 | 
			
		||||
    qmp_marshal_input_query_version(NULL, &ver, NULL);
 | 
			
		||||
    qmp_marshal_query_version(NULL, &ver, NULL);
 | 
			
		||||
    return qobject_from_jsonf("{'QMP':{'version': %p,'capabilities': []}}",ver);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,6 +17,9 @@
 | 
			
		||||
# Tracing commands
 | 
			
		||||
{ 'include': 'qapi/trace.json' }
 | 
			
		||||
 | 
			
		||||
# QAPI introspection
 | 
			
		||||
{ 'include': 'qapi/introspect.json' }
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @LostTickPolicy:
 | 
			
		||||
#
 | 
			
		||||
@ -1698,8 +1701,7 @@
 | 
			
		||||
##
 | 
			
		||||
{ 'command': 'qom-get',
 | 
			
		||||
  'data': { 'path': 'str', 'property': 'str' },
 | 
			
		||||
  'returns': '**',
 | 
			
		||||
  'gen': false }
 | 
			
		||||
  'returns': 'any' }
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @qom-set:
 | 
			
		||||
@ -1716,8 +1718,7 @@
 | 
			
		||||
# Since: 1.2
 | 
			
		||||
##
 | 
			
		||||
{ 'command': 'qom-set',
 | 
			
		||||
  'data': { 'path': 'str', 'property': 'str', 'value': '**' },
 | 
			
		||||
  'gen': false }
 | 
			
		||||
  'data': { 'path': 'str', 'property': 'str', 'value': 'any' } }
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @set_password:
 | 
			
		||||
@ -2081,11 +2082,12 @@
 | 
			
		||||
#
 | 
			
		||||
# @id: the name of the new network backend
 | 
			
		||||
#
 | 
			
		||||
# @props: #optional a list of properties to be passed to the backend in
 | 
			
		||||
#         the format 'name=value', like 'ifname=tap0,script=no'
 | 
			
		||||
# Additional arguments depend on the type.
 | 
			
		||||
#
 | 
			
		||||
# Notes: The semantics of @props is not well defined.  Future commands will be
 | 
			
		||||
#        introduced that provide stronger typing for backend creation.
 | 
			
		||||
# TODO This command effectively bypasses QAPI completely due to its
 | 
			
		||||
# "additional arguments" business.  It shouldn't have been added to
 | 
			
		||||
# the schema in this form.  It should be qapified properly, or
 | 
			
		||||
# replaced by a properly qapified command.
 | 
			
		||||
#
 | 
			
		||||
# Since: 0.14.0
 | 
			
		||||
#
 | 
			
		||||
@ -2093,8 +2095,8 @@
 | 
			
		||||
#          If @type is not a valid network backend, DeviceNotFound
 | 
			
		||||
##
 | 
			
		||||
{ 'command': 'netdev_add',
 | 
			
		||||
  'data': {'type': 'str', 'id': 'str', '*props': '**'},
 | 
			
		||||
  'gen': false }
 | 
			
		||||
  'data': {'type': 'str', 'id': 'str'},
 | 
			
		||||
  'gen': false }                # so we can get the additional arguments
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @netdev_del:
 | 
			
		||||
@ -2127,8 +2129,7 @@
 | 
			
		||||
# Since: 2.0
 | 
			
		||||
##
 | 
			
		||||
{ 'command': 'object-add',
 | 
			
		||||
  'data': {'qom-type': 'str', 'id': 'str', '*props': '**'},
 | 
			
		||||
  'gen': false }
 | 
			
		||||
  'data': {'qom-type': 'str', 'id': 'str', '*props': 'any'} }
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @object-del:
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										273
									
								
								qapi/introspect.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										273
									
								
								qapi/introspect.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,273 @@
 | 
			
		||||
# -*- Mode: Python -*-
 | 
			
		||||
#
 | 
			
		||||
# QAPI/QMP introspection
 | 
			
		||||
#
 | 
			
		||||
# Copyright (C) 2015 Red Hat, Inc.
 | 
			
		||||
#
 | 
			
		||||
# Authors:
 | 
			
		||||
#  Markus Armbruster <armbru@redhat.com>
 | 
			
		||||
#
 | 
			
		||||
# This work is licensed under the terms of the GNU GPL, version 2 or later.
 | 
			
		||||
# See the COPYING file in the top-level directory.
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @query-qmp-schema
 | 
			
		||||
#
 | 
			
		||||
# Command query-qmp-schema exposes the QMP wire ABI as an array of
 | 
			
		||||
# SchemaInfo.  This lets QMP clients figure out what commands and
 | 
			
		||||
# events are available in this QEMU, and their parameters and results.
 | 
			
		||||
#
 | 
			
		||||
# However, the SchemaInfo can't reflect all the rules and restrictions
 | 
			
		||||
# that apply to QMP.  It's interface introspection (figuring out
 | 
			
		||||
# what's there), not interface specification.  The specification is in
 | 
			
		||||
# the QAPI schema.
 | 
			
		||||
#
 | 
			
		||||
# Returns: array of @SchemaInfo, where each element describes an
 | 
			
		||||
# entity in the ABI: command, event, type, ...
 | 
			
		||||
#
 | 
			
		||||
# Note: the QAPI schema is also used to help define *internal*
 | 
			
		||||
# interfaces, by defining QAPI types.  These are not part of the QMP
 | 
			
		||||
# wire ABI, and therefore not returned by this command.
 | 
			
		||||
#
 | 
			
		||||
# Since: 2.5
 | 
			
		||||
##
 | 
			
		||||
{ 'command': 'query-qmp-schema',
 | 
			
		||||
  'returns': [ 'SchemaInfo' ],
 | 
			
		||||
  'gen': false }                # just to simplify qmp_query_json()
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @SchemaMetaType
 | 
			
		||||
#
 | 
			
		||||
# This is a @SchemaInfo's meta type, i.e. the kind of entity it
 | 
			
		||||
# describes.
 | 
			
		||||
#
 | 
			
		||||
# @builtin: a predefined type such as 'int' or 'bool'.
 | 
			
		||||
#
 | 
			
		||||
# @enum: an enumeration type
 | 
			
		||||
#
 | 
			
		||||
# @array: an array type
 | 
			
		||||
#
 | 
			
		||||
# @object: an object type (struct or union)
 | 
			
		||||
#
 | 
			
		||||
# @alternate: an alternate type
 | 
			
		||||
#
 | 
			
		||||
# @command: a QMP command
 | 
			
		||||
#
 | 
			
		||||
# @event: a QMP event
 | 
			
		||||
#
 | 
			
		||||
# Since: 2.5
 | 
			
		||||
##
 | 
			
		||||
{ 'enum': 'SchemaMetaType',
 | 
			
		||||
  'data': [ 'builtin', 'enum', 'array', 'object', 'alternate',
 | 
			
		||||
            'command', 'event' ] }
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @SchemaInfoBase
 | 
			
		||||
#
 | 
			
		||||
# Members common to any @SchemaInfo.
 | 
			
		||||
#
 | 
			
		||||
# Since: 2.5
 | 
			
		||||
##
 | 
			
		||||
{ 'struct': 'SchemaInfoBase',
 | 
			
		||||
  'data': { 'name': 'str', 'meta-type': 'SchemaMetaType' } }
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @SchemaInfo
 | 
			
		||||
#
 | 
			
		||||
# @name: the entity's name, inherited from @base.
 | 
			
		||||
#        Commands and events have the name defined in the QAPI schema.
 | 
			
		||||
#        Unlike command and event names, type names are not part of
 | 
			
		||||
#        the wire ABI.  Consequently, type names are meaningless
 | 
			
		||||
#        strings here.
 | 
			
		||||
#
 | 
			
		||||
# All references to other SchemaInfo are by name.
 | 
			
		||||
#
 | 
			
		||||
# @meta-type: the entity's meta type, inherited from @base.
 | 
			
		||||
#
 | 
			
		||||
# Additional members depend on the value of @meta-type.
 | 
			
		||||
#
 | 
			
		||||
# Since: 2.5
 | 
			
		||||
##
 | 
			
		||||
{ 'union': 'SchemaInfo',
 | 
			
		||||
  'base': 'SchemaInfoBase',
 | 
			
		||||
  'discriminator': 'meta-type',
 | 
			
		||||
  'data': {
 | 
			
		||||
      'builtin': 'SchemaInfoBuiltin',
 | 
			
		||||
      'enum': 'SchemaInfoEnum',
 | 
			
		||||
      'array': 'SchemaInfoArray',
 | 
			
		||||
      'object': 'SchemaInfoObject',
 | 
			
		||||
      'alternate': 'SchemaInfoAlternate',
 | 
			
		||||
      'command': 'SchemaInfoCommand',
 | 
			
		||||
      'event': 'SchemaInfoEvent' } }
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @SchemaInfoBuiltin
 | 
			
		||||
#
 | 
			
		||||
# Additional SchemaInfo members for meta-type 'builtin'.
 | 
			
		||||
#
 | 
			
		||||
# @json-type: the JSON type used for this type on the wire.
 | 
			
		||||
#
 | 
			
		||||
# Since: 2.5
 | 
			
		||||
##
 | 
			
		||||
{ 'struct': 'SchemaInfoBuiltin',
 | 
			
		||||
  'data': { 'json-type': 'JSONType' } }
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @JSONType
 | 
			
		||||
#
 | 
			
		||||
# The four primitive and two structured types according to RFC 7159
 | 
			
		||||
# section 1, plus 'int' (split off 'number'), plus the obvious top
 | 
			
		||||
# type 'value'.
 | 
			
		||||
#
 | 
			
		||||
# Since: 2.5
 | 
			
		||||
##
 | 
			
		||||
{ 'enum': 'JSONType',
 | 
			
		||||
  'data': [ 'string', 'number', 'int', 'boolean', 'null',
 | 
			
		||||
            'object', 'array', 'value' ] }
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @SchemaInfoEnum
 | 
			
		||||
#
 | 
			
		||||
# Additional SchemaInfo members for meta-type 'enum'.
 | 
			
		||||
#
 | 
			
		||||
# @values: the enumeration type's values.
 | 
			
		||||
#
 | 
			
		||||
# Values of this type are JSON string on the wire.
 | 
			
		||||
#
 | 
			
		||||
# Since: 2.5
 | 
			
		||||
##
 | 
			
		||||
{ 'struct': 'SchemaInfoEnum',
 | 
			
		||||
  'data': { 'values': ['str'] } }
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @SchemaInfoArray
 | 
			
		||||
#
 | 
			
		||||
# Additional SchemaInfo members for meta-type 'array'.
 | 
			
		||||
#
 | 
			
		||||
# @element-type: the array type's element type.
 | 
			
		||||
#
 | 
			
		||||
# Values of this type are JSON array on the wire.
 | 
			
		||||
#
 | 
			
		||||
# Since: 2.5
 | 
			
		||||
##
 | 
			
		||||
{ 'struct': 'SchemaInfoArray',
 | 
			
		||||
  'data': { 'element-type': 'str' } }
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @SchemaInfoObject
 | 
			
		||||
#
 | 
			
		||||
# Additional SchemaInfo members for meta-type 'object'.
 | 
			
		||||
#
 | 
			
		||||
# @members: the object type's (non-variant) members.
 | 
			
		||||
#
 | 
			
		||||
# @tag: #optional the name of the member serving as type tag.
 | 
			
		||||
#       An element of @members with this name must exist.
 | 
			
		||||
#
 | 
			
		||||
# @variants: #optional variant members, i.e. additional members that
 | 
			
		||||
#            depend on the type tag's value.  Present exactly when
 | 
			
		||||
#            @tag is present.
 | 
			
		||||
#
 | 
			
		||||
# Values of this type are JSON object on the wire.
 | 
			
		||||
#
 | 
			
		||||
# Since: 2.5
 | 
			
		||||
##
 | 
			
		||||
{ 'struct': 'SchemaInfoObject',
 | 
			
		||||
  'data': { 'members': [ 'SchemaInfoObjectMember' ],
 | 
			
		||||
            '*tag': 'str',
 | 
			
		||||
            '*variants': [ 'SchemaInfoObjectVariant' ] } }
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @SchemaInfoObjectMember
 | 
			
		||||
#
 | 
			
		||||
# An object member.
 | 
			
		||||
#
 | 
			
		||||
# @name: the member's name, as defined in the QAPI schema.
 | 
			
		||||
#
 | 
			
		||||
# @type: the name of the member's type.
 | 
			
		||||
#
 | 
			
		||||
# @default: #optional default when used as command parameter.
 | 
			
		||||
#           If absent, the parameter is mandatory.
 | 
			
		||||
#           If present, the value must be null.  The parameter is
 | 
			
		||||
#           optional, and behavior when it's missing is not specified
 | 
			
		||||
#           here.
 | 
			
		||||
#           Future extension: if present and non-null, the parameter
 | 
			
		||||
#           is optional, and defaults to this value.
 | 
			
		||||
#
 | 
			
		||||
# Since: 2.5
 | 
			
		||||
##
 | 
			
		||||
{ 'struct': 'SchemaInfoObjectMember',
 | 
			
		||||
  'data': { 'name': 'str', 'type': 'str', '*default': 'any' } }
 | 
			
		||||
# @default's type must be null or match @type
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @SchemaInfoObjectVariant
 | 
			
		||||
#
 | 
			
		||||
# The variant members for a value of the type tag.
 | 
			
		||||
#
 | 
			
		||||
# @case: a value of the type tag.
 | 
			
		||||
#
 | 
			
		||||
# @type: the name of the object type that provides the variant members
 | 
			
		||||
#        when the type tag has value @case.
 | 
			
		||||
#
 | 
			
		||||
# Since: 2.5
 | 
			
		||||
##
 | 
			
		||||
{ 'struct': 'SchemaInfoObjectVariant',
 | 
			
		||||
  'data': { 'case': 'str', 'type': 'str' } }
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @SchemaInfoAlternate
 | 
			
		||||
#
 | 
			
		||||
# Additional SchemaInfo members for meta-type 'alternate'.
 | 
			
		||||
#
 | 
			
		||||
# @members: the alternate type's members.
 | 
			
		||||
#           The members' wire encoding is distinct, see
 | 
			
		||||
#           docs/qapi-code-gen.txt section Alternate types.
 | 
			
		||||
#
 | 
			
		||||
# On the wire, this can be any of the members.
 | 
			
		||||
#
 | 
			
		||||
# Since: 2.5
 | 
			
		||||
##
 | 
			
		||||
{ 'struct': 'SchemaInfoAlternate',
 | 
			
		||||
  'data': { 'members': [ 'SchemaInfoAlternateMember' ] } }
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @SchemaInfoAlternateMember
 | 
			
		||||
#
 | 
			
		||||
# An alternate member.
 | 
			
		||||
#
 | 
			
		||||
# @type: the name of the member's type.
 | 
			
		||||
#
 | 
			
		||||
# Since: 2.5
 | 
			
		||||
##
 | 
			
		||||
{ 'struct': 'SchemaInfoAlternateMember',
 | 
			
		||||
  'data': { 'type': 'str' } }
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @SchemaInfoCommand
 | 
			
		||||
#
 | 
			
		||||
# Additional SchemaInfo members for meta-type 'command'.
 | 
			
		||||
#
 | 
			
		||||
# @arg-type: the name of the object type that provides the command's
 | 
			
		||||
#            parameters.
 | 
			
		||||
#
 | 
			
		||||
# @ret-type: the name of the command's result type.
 | 
			
		||||
#
 | 
			
		||||
# TODO @success-response (currently irrelevant, because it's QGA, not QMP)
 | 
			
		||||
#
 | 
			
		||||
# Since: 2.5
 | 
			
		||||
##
 | 
			
		||||
{ 'struct': 'SchemaInfoCommand',
 | 
			
		||||
  'data': { 'arg-type': 'str', 'ret-type': 'str' } }
 | 
			
		||||
 | 
			
		||||
##
 | 
			
		||||
# @SchemaInfoEvent
 | 
			
		||||
#
 | 
			
		||||
# Additional SchemaInfo members for meta-type 'event'.
 | 
			
		||||
#
 | 
			
		||||
# @arg-type: the name of the object type that provides the event's
 | 
			
		||||
#            parameters.
 | 
			
		||||
#
 | 
			
		||||
# Since: 2.5
 | 
			
		||||
##
 | 
			
		||||
{ 'struct': 'SchemaInfoEvent',
 | 
			
		||||
  'data': { 'arg-type': 'str' } }
 | 
			
		||||
@ -151,6 +151,14 @@ static void qapi_dealloc_type_number(Visitor *v, double *obj, const char *name,
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void qapi_dealloc_type_anything(Visitor *v, QObject **obj,
 | 
			
		||||
                                       const char *name, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    if (obj) {
 | 
			
		||||
        qobject_decref(*obj);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void qapi_dealloc_type_size(Visitor *v, uint64_t *obj, const char *name,
 | 
			
		||||
                                   Error **errp)
 | 
			
		||||
{
 | 
			
		||||
@ -216,6 +224,7 @@ QapiDeallocVisitor *qapi_dealloc_visitor_new(void)
 | 
			
		||||
    v->visitor.type_bool = qapi_dealloc_type_bool;
 | 
			
		||||
    v->visitor.type_str = qapi_dealloc_type_str;
 | 
			
		||||
    v->visitor.type_number = qapi_dealloc_type_number;
 | 
			
		||||
    v->visitor.type_any = qapi_dealloc_type_anything;
 | 
			
		||||
    v->visitor.type_size = qapi_dealloc_type_size;
 | 
			
		||||
    v->visitor.start_union = qapi_dealloc_start_union;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -260,6 +260,12 @@ void visit_type_number(Visitor *v, double *obj, const char *name, Error **errp)
 | 
			
		||||
    v->type_number(v, obj, name, errp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void visit_type_any(Visitor *v, QObject **obj, const char *name,
 | 
			
		||||
                    Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    v->type_any(v, obj, name, errp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void output_type_enum(Visitor *v, int *obj, const char * const strings[],
 | 
			
		||||
                      const char *kind, const char *name,
 | 
			
		||||
                      Error **errp)
 | 
			
		||||
 | 
			
		||||
@ -286,6 +286,16 @@ static void qmp_input_type_number(Visitor *v, double *obj, const char *name,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void qmp_input_type_any(Visitor *v, QObject **obj, const char *name,
 | 
			
		||||
                               Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    QmpInputVisitor *qiv = to_qiv(v);
 | 
			
		||||
    QObject *qobj = qmp_input_get_object(qiv, name, true);
 | 
			
		||||
 | 
			
		||||
    qobject_incref(qobj);
 | 
			
		||||
    *obj = qobj;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void qmp_input_optional(Visitor *v, bool *present, const char *name,
 | 
			
		||||
                               Error **errp)
 | 
			
		||||
{
 | 
			
		||||
@ -329,6 +339,7 @@ QmpInputVisitor *qmp_input_visitor_new(QObject *obj)
 | 
			
		||||
    v->visitor.type_bool = qmp_input_type_bool;
 | 
			
		||||
    v->visitor.type_str = qmp_input_type_str;
 | 
			
		||||
    v->visitor.type_number = qmp_input_type_number;
 | 
			
		||||
    v->visitor.type_any = qmp_input_type_any;
 | 
			
		||||
    v->visitor.optional = qmp_input_optional;
 | 
			
		||||
    v->visitor.get_next_type = qmp_input_get_next_type;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -66,9 +66,13 @@ static QObject *qmp_output_first(QmpOutputVisitor *qov)
 | 
			
		||||
{
 | 
			
		||||
    QStackEntry *e = QTAILQ_LAST(&qov->stack, QStack);
 | 
			
		||||
 | 
			
		||||
    /* FIXME - find a better way to deal with NULL values */
 | 
			
		||||
    /*
 | 
			
		||||
     * FIXME Wrong, because qmp_output_get_qobject() will increment
 | 
			
		||||
     * the refcnt *again*.  We need to think through how visitors
 | 
			
		||||
     * handle null.
 | 
			
		||||
     */
 | 
			
		||||
    if (!e) {
 | 
			
		||||
        return NULL;
 | 
			
		||||
        return qnull();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return e->value;
 | 
			
		||||
@ -186,6 +190,14 @@ static void qmp_output_type_number(Visitor *v, double *obj, const char *name,
 | 
			
		||||
    qmp_output_add(qov, name, qfloat_from_double(*obj));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void qmp_output_type_any(Visitor *v, QObject **obj, const char *name,
 | 
			
		||||
                                Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    QmpOutputVisitor *qov = to_qov(v);
 | 
			
		||||
    qobject_incref(*obj);
 | 
			
		||||
    qmp_output_add_obj(qov, name, *obj);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QObject *qmp_output_get_qobject(QmpOutputVisitor *qov)
 | 
			
		||||
{
 | 
			
		||||
    QObject *obj = qmp_output_first(qov);
 | 
			
		||||
@ -233,6 +245,7 @@ QmpOutputVisitor *qmp_output_visitor_new(void)
 | 
			
		||||
    v->visitor.type_bool = qmp_output_type_bool;
 | 
			
		||||
    v->visitor.type_str = qmp_output_type_str;
 | 
			
		||||
    v->visitor.type_number = qmp_output_type_number;
 | 
			
		||||
    v->visitor.type_any = qmp_output_type_any;
 | 
			
		||||
 | 
			
		||||
    QTAILQ_INIT(&v->stack);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										269
									
								
								qmp-commands.hx
									
									
									
									
									
								
							
							
						
						
									
										269
									
								
								qmp-commands.hx
									
									
									
									
									
								
							@ -63,7 +63,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "quit",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_quit,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_quit,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -84,7 +84,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "eject",
 | 
			
		||||
        .args_type  = "force:-f,device:B",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_eject,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_eject,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -110,7 +110,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "change",
 | 
			
		||||
        .args_type  = "device:B,target:F,arg:s?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_change,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_change,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -146,7 +146,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "screendump",
 | 
			
		||||
        .args_type  = "filename:F",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_screendump,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_screendump,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -169,7 +169,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "stop",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_stop,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_stop,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -190,7 +190,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "cont",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_cont,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_cont,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -211,7 +211,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "system_wakeup",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_system_wakeup,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_system_wakeup,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -232,7 +232,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "system_reset",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_system_reset,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_system_reset,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -253,7 +253,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "system_powerdown",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_system_powerdown,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_system_powerdown,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -310,7 +310,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "device_del",
 | 
			
		||||
        .args_type  = "id:s",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_device_del,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_device_del,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -333,7 +333,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "send-key",
 | 
			
		||||
        .args_type  = "keys:q,hold-time:i?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_send_key,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_send_key,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -364,7 +364,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "cpu",
 | 
			
		||||
        .args_type  = "index:i",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_cpu,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_cpu,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -389,7 +389,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "cpu-add",
 | 
			
		||||
        .args_type  = "id:i",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_cpu_add,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_cpu_add,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -412,7 +412,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "memsave",
 | 
			
		||||
        .args_type  = "val:l,size:i,filename:s,cpu:i?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_memsave,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_memsave,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -441,7 +441,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "pmemsave",
 | 
			
		||||
        .args_type  = "val:l,size:i,filename:s",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_pmemsave,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_pmemsave,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -469,7 +469,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "inject-nmi",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_inject_nmi,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_inject_nmi,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -492,7 +492,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "ringbuf-write",
 | 
			
		||||
        .args_type  = "device:s,data:s,format:s?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_ringbuf_write,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_ringbuf_write,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -523,7 +523,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "ringbuf-read",
 | 
			
		||||
        .args_type  = "device:s,size:i,format:s?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_ringbuf_read,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_ringbuf_read,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -559,7 +559,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "xen-save-devices-state",
 | 
			
		||||
        .args_type  = "filename:F",
 | 
			
		||||
    .mhandler.cmd_new = qmp_marshal_input_xen_save_devices_state,
 | 
			
		||||
    .mhandler.cmd_new = qmp_marshal_xen_save_devices_state,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -586,7 +586,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "xen-set-global-dirty-log",
 | 
			
		||||
        .args_type  = "enable:b",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_xen_set_global_dirty_log,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_xen_set_global_dirty_log,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -610,7 +610,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "migrate",
 | 
			
		||||
        .args_type  = "detach:-d,blk:-b,inc:-i,uri:s",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_migrate,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_migrate,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -643,7 +643,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "migrate_cancel",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_migrate_cancel,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_migrate_cancel,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -664,7 +664,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "migrate-incoming",
 | 
			
		||||
        .args_type  = "uri:s",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_migrate_incoming,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_migrate_incoming,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -692,7 +692,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "migrate-set-cache-size",
 | 
			
		||||
        .args_type  = "value:o",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_migrate_set_cache_size,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_migrate_set_cache_size,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -715,7 +715,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-migrate-cache-size",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_migrate_cache_size,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_migrate_cache_size,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -737,7 +737,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "migrate_set_speed",
 | 
			
		||||
        .args_type  = "value:o",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_migrate_set_speed,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_migrate_set_speed,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -760,7 +760,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "migrate_set_downtime",
 | 
			
		||||
        .args_type  = "value:T",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_migrate_set_downtime,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_migrate_set_downtime,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -785,7 +785,7 @@ EQMP
 | 
			
		||||
        .args_type  = "protocol:s,hostname:s,port:i?,tls-port:i?,cert-subject:s?",
 | 
			
		||||
        .params     = "protocol hostname port tls-port cert-subject",
 | 
			
		||||
        .help       = "set migration information for remote display",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_client_migrate_info,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_client_migrate_info,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -819,7 +819,7 @@ EQMP
 | 
			
		||||
        .args_type  = "paging:b,protocol:s,begin:i?,end:i?,format:s?",
 | 
			
		||||
        .params     = "-p protocol [begin] [length] [format]",
 | 
			
		||||
        .help       = "dump guest memory to file",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_dump_guest_memory,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_dump_guest_memory,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -855,7 +855,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-dump-guest-memory-capability",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
    .mhandler.cmd_new = qmp_marshal_input_query_dump_guest_memory_capability,
 | 
			
		||||
    .mhandler.cmd_new = qmp_marshal_query_dump_guest_memory_capability,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -876,7 +876,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "dump-skeys",
 | 
			
		||||
        .args_type  = "filename:F",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_dump_skeys,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_dump_skeys,
 | 
			
		||||
    },
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -917,7 +917,9 @@ Arguments:
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
-> { "execute": "netdev_add", "arguments": { "type": "user", "id": "netdev1" } }
 | 
			
		||||
-> { "execute": "netdev_add",
 | 
			
		||||
     "arguments": { "type": "user", "id": "netdev1",
 | 
			
		||||
                    "dnssearch": "example.org" } }
 | 
			
		||||
<- { "return": {} }
 | 
			
		||||
 | 
			
		||||
Note: The supported device options are the same ones supported by the '-netdev'
 | 
			
		||||
@ -929,7 +931,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "netdev_del",
 | 
			
		||||
        .args_type  = "id:s",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_netdev_del,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_netdev_del,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -953,7 +955,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "object-add",
 | 
			
		||||
        .args_type  = "qom-type:s,id:s,props:q?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_object_add,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_object_add,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -979,7 +981,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "object-del",
 | 
			
		||||
        .args_type  = "id:s",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_object_del,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_object_del,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -1004,7 +1006,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "block_resize",
 | 
			
		||||
        .args_type  = "device:s?,node-name:s?,size:o",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_block_resize,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_block_resize,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -1029,7 +1031,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "block-stream",
 | 
			
		||||
        .args_type  = "device:B,base:s?,speed:o?,backing-file:s?,on-error:s?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_block_stream,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_block_stream,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -1072,7 +1074,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "block-commit",
 | 
			
		||||
        .args_type  = "device:B,base:s?,top:s?,backing-file:s?,speed:o?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_block_commit,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_block_commit,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -1136,7 +1138,7 @@ EQMP
 | 
			
		||||
        .name       = "drive-backup",
 | 
			
		||||
        .args_type  = "sync:s,device:B,target:s,speed:i?,mode:s?,format:s?,"
 | 
			
		||||
                      "bitmap:s?,on-source-error:s?,on-target-error:s?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_drive_backup,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_drive_backup,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -1190,7 +1192,7 @@ EQMP
 | 
			
		||||
        .name       = "blockdev-backup",
 | 
			
		||||
        .args_type  = "sync:s,device:B,target:B,speed:i?,"
 | 
			
		||||
                      "on-source-error:s?,on-target-error:s?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_blockdev_backup,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_blockdev_backup,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -1230,33 +1232,33 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "block-job-set-speed",
 | 
			
		||||
        .args_type  = "device:B,speed:o",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_block_job_set_speed,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_block_job_set_speed,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "block-job-cancel",
 | 
			
		||||
        .args_type  = "device:B,force:b?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_block_job_cancel,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_block_job_cancel,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "block-job-pause",
 | 
			
		||||
        .args_type  = "device:B",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_block_job_pause,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_block_job_pause,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "block-job-resume",
 | 
			
		||||
        .args_type  = "device:B",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_block_job_resume,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_block_job_resume,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "block-job-complete",
 | 
			
		||||
        .args_type  = "device:B",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_block_job_complete,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_block_job_complete,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "transaction",
 | 
			
		||||
        .args_type  = "actions:q",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_transaction,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_transaction,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -1335,7 +1337,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "block-dirty-bitmap-add",
 | 
			
		||||
        .args_type  = "node:B,name:s,granularity:i?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_block_dirty_bitmap_add,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_block_dirty_bitmap_add,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -1363,7 +1365,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "block-dirty-bitmap-remove",
 | 
			
		||||
        .args_type  = "node:B,name:s",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_block_dirty_bitmap_remove,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_block_dirty_bitmap_remove,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -1391,7 +1393,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "block-dirty-bitmap-clear",
 | 
			
		||||
        .args_type  = "node:B,name:s",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_block_dirty_bitmap_clear,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_block_dirty_bitmap_clear,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -1420,7 +1422,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "blockdev-snapshot-sync",
 | 
			
		||||
        .args_type  = "device:s?,node-name:s?,snapshot-file:s,snapshot-node-name:s?,format:s?,mode:s?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_blockdev_snapshot_sync,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_blockdev_snapshot_sync,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -1456,7 +1458,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "blockdev-snapshot-internal-sync",
 | 
			
		||||
        .args_type  = "device:B,name:s",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_blockdev_snapshot_internal_sync,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_blockdev_snapshot_internal_sync,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -1486,7 +1488,7 @@ EQMP
 | 
			
		||||
        .name       = "blockdev-snapshot-delete-internal-sync",
 | 
			
		||||
        .args_type  = "device:B,id:s?,name:s?",
 | 
			
		||||
        .mhandler.cmd_new =
 | 
			
		||||
                      qmp_marshal_input_blockdev_snapshot_delete_internal_sync,
 | 
			
		||||
                      qmp_marshal_blockdev_snapshot_delete_internal_sync,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -1530,7 +1532,7 @@ EQMP
 | 
			
		||||
                      "on-source-error:s?,on-target-error:s?,"
 | 
			
		||||
                      "unmap:b?,"
 | 
			
		||||
                      "granularity:i?,buf-size:i?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_drive_mirror,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_drive_mirror,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -1590,7 +1592,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "change-backing-file",
 | 
			
		||||
        .args_type  = "device:s,image-node-name:s,backing-file:s",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_change_backing_file,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_change_backing_file,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -1629,7 +1631,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "balloon",
 | 
			
		||||
        .args_type  = "value:M",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_balloon,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_balloon,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -1652,7 +1654,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "set_link",
 | 
			
		||||
        .args_type  = "name:s,up:b",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_set_link,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_set_link,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -1678,7 +1680,7 @@ EQMP
 | 
			
		||||
        .args_type  = "fdname:s",
 | 
			
		||||
        .params     = "getfd name",
 | 
			
		||||
        .help       = "receive a file descriptor via SCM rights and assign it a name",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_getfd,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_getfd,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -1711,7 +1713,7 @@ EQMP
 | 
			
		||||
        .args_type  = "fdname:s",
 | 
			
		||||
        .params     = "closefd name",
 | 
			
		||||
        .help       = "close a file descriptor previously passed via SCM rights",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_closefd,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_closefd,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -1736,7 +1738,7 @@ EQMP
 | 
			
		||||
        .args_type  = "fdset-id:i?,opaque:s?",
 | 
			
		||||
        .params     = "add-fd fdset-id opaque",
 | 
			
		||||
        .help       = "Add a file descriptor, that was passed via SCM rights, to an fd set",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_add_fd,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_add_fd,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -1775,7 +1777,7 @@ EQMP
 | 
			
		||||
        .args_type  = "fdset-id:i,fd:i?",
 | 
			
		||||
        .params     = "remove-fd fdset-id fd",
 | 
			
		||||
        .help       = "Remove a file descriptor from an fd set",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_remove_fd,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_remove_fd,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -1807,7 +1809,7 @@ EQMP
 | 
			
		||||
        .name       = "query-fdsets",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .help       = "Return information describing all fd sets",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_fdsets,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_fdsets,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -1856,7 +1858,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "block_passwd",
 | 
			
		||||
        .args_type  = "device:s?,node-name:s?,password:s",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_block_passwd,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_block_passwd,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -1882,7 +1884,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "block_set_io_throttle",
 | 
			
		||||
        .args_type  = "device:B,bps:l,bps_rd:l,bps_wr:l,iops:l,iops_rd:l,iops_wr:l,bps_max:l?,bps_rd_max:l?,bps_wr_max:l?,iops_max:l?,iops_rd_max:l?,iops_wr_max:l?,iops_size:l?,group:s?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_block_set_io_throttle,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_block_set_io_throttle,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -1932,7 +1934,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "set_password",
 | 
			
		||||
        .args_type  = "protocol:s,password:s,connected:s?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_set_password,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_set_password,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -1958,7 +1960,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "expire_password",
 | 
			
		||||
        .args_type  = "protocol:s,time:s",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_expire_password,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_expire_password,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -1983,7 +1985,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "add_client",
 | 
			
		||||
        .args_type  = "protocol:s,fdname:s,skipauth:b?,tls:b?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_add_client,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_add_client,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -2034,7 +2036,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "human-monitor-command",
 | 
			
		||||
        .args_type  = "command-line:s,cpu-index:i?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_human_monitor_command,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_human_monitor_command,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -2113,7 +2115,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-version",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_version,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_version,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -2150,7 +2152,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-commands",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_commands,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_commands,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -2187,7 +2189,24 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-events",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_events,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_events,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
query-qmp-schema
 | 
			
		||||
----------------
 | 
			
		||||
 | 
			
		||||
Return the QMP wire schema.  The returned value is a json-array of
 | 
			
		||||
named schema entities.  Entities are commands, events and various
 | 
			
		||||
types.  See docs/qapi-code-gen.txt for information on their structure
 | 
			
		||||
and intended use.
 | 
			
		||||
 | 
			
		||||
EQMP
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-qmp-schema",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_query_qmp_schema,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -2232,7 +2251,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-chardev",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_chardev,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_chardev,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -2273,7 +2292,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-chardev-backends",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_chardev_backends,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_chardev_backends,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -2457,7 +2476,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-block",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_block,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_block,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -2584,7 +2603,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-blockstats",
 | 
			
		||||
        .args_type  = "query-nodes:b?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_blockstats,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_blockstats,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -2635,7 +2654,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-cpus",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_cpus,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_cpus,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -2674,7 +2693,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-iothreads",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_iothreads,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_iothreads,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -2891,7 +2910,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-pci",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_pci,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_pci,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -2915,7 +2934,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-kvm",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_kvm,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_kvm,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -2955,7 +2974,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-status",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_status,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_status,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -2999,7 +3018,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-mice",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_mice,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_mice,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -3062,12 +3081,12 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-vnc",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_vnc,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_vnc,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-vnc-servers",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_vnc_servers,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_vnc_servers,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -3144,7 +3163,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-spice",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_spice,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_spice,
 | 
			
		||||
    },
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -3168,7 +3187,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-name",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_name,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_name,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -3191,7 +3210,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-uuid",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_uuid,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_uuid,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -3240,7 +3259,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-command-line-options",
 | 
			
		||||
        .args_type  = "option:s?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_command_line_options,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_command_line_options,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -3418,7 +3437,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-migrate",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_migrate,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_migrate,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -3446,7 +3465,7 @@ EQMP
 | 
			
		||||
        .name       = "migrate-set-capabilities",
 | 
			
		||||
        .args_type  = "capabilities:q",
 | 
			
		||||
        .params     = "capability:s,state:b",
 | 
			
		||||
	.mhandler.cmd_new = qmp_marshal_input_migrate_set_capabilities,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_migrate_set_capabilities,
 | 
			
		||||
    },
 | 
			
		||||
SQMP
 | 
			
		||||
query-migrate-capabilities
 | 
			
		||||
@ -3472,7 +3491,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-migrate-capabilities",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_migrate_capabilities,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_migrate_capabilities,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -3498,7 +3517,7 @@ EQMP
 | 
			
		||||
        .name       = "migrate-set-parameters",
 | 
			
		||||
        .args_type  =
 | 
			
		||||
            "compress-level:i?,compress-threads:i?,decompress-threads:i?",
 | 
			
		||||
	.mhandler.cmd_new = qmp_marshal_input_migrate_set_parameters,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_migrate_set_parameters,
 | 
			
		||||
    },
 | 
			
		||||
SQMP
 | 
			
		||||
query-migrate-parameters
 | 
			
		||||
@ -3529,7 +3548,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-migrate-parameters",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_migrate_parameters,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_migrate_parameters,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -3557,88 +3576,88 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-balloon",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_balloon,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_balloon,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-block-jobs",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_block_jobs,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_block_jobs,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "qom-list",
 | 
			
		||||
        .args_type  = "path:s",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_qom_list,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_qom_list,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "qom-set",
 | 
			
		||||
	.args_type  = "path:s,property:s,value:q",
 | 
			
		||||
	.mhandler.cmd_new = qmp_qom_set,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_qom_set,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "qom-get",
 | 
			
		||||
	.args_type  = "path:s,property:s",
 | 
			
		||||
	.mhandler.cmd_new = qmp_qom_get,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_qom_get,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "nbd-server-start",
 | 
			
		||||
        .args_type  = "addr:q",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_nbd_server_start,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_nbd_server_start,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "nbd-server-add",
 | 
			
		||||
        .args_type  = "device:B,writable:b?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_nbd_server_add,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_nbd_server_add,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "nbd-server-stop",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_nbd_server_stop,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_nbd_server_stop,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "change-vnc-password",
 | 
			
		||||
        .args_type  = "password:s",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_change_vnc_password,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_change_vnc_password,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "qom-list-types",
 | 
			
		||||
        .args_type  = "implements:s?,abstract:b?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_qom_list_types,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_qom_list_types,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "device-list-properties",
 | 
			
		||||
        .args_type  = "typename:s",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_device_list_properties,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_device_list_properties,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-machines",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_machines,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_machines,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-cpu-definitions",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_cpu_definitions,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_cpu_definitions,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-target",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_target,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_target,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-tpm",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_tpm,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_tpm,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -3672,7 +3691,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-tpm-models",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_tpm_models,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_tpm_models,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -3693,7 +3712,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-tpm-types",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_tpm_types,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_tpm_types,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -3714,7 +3733,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "chardev-add",
 | 
			
		||||
        .args_type  = "id:s,backend:q",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_chardev_add,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_chardev_add,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -3751,7 +3770,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "chardev-remove",
 | 
			
		||||
        .args_type  = "id:s",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_chardev_remove,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_chardev_remove,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -3774,7 +3793,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-rx-filter",
 | 
			
		||||
        .args_type  = "name:s?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_rx_filter,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_rx_filter,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -3840,7 +3859,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "blockdev-add",
 | 
			
		||||
        .args_type  = "options:q",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_blockdev_add,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_blockdev_add,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -3899,7 +3918,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-named-block-nodes",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_named_block_nodes,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_named_block_nodes,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -3961,7 +3980,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-memdev",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_memdev,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_memdev,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -3999,7 +4018,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-memory-devices",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_memory_devices,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_memory_devices,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -4026,7 +4045,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-acpi-ospm-status",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_acpi_ospm_status,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_acpi_ospm_status,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -4049,7 +4068,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "rtc-reset-reinjection",
 | 
			
		||||
        .args_type  = "",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_rtc_reset_reinjection,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_rtc_reset_reinjection,
 | 
			
		||||
    },
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -4070,7 +4089,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "trace-event-get-state",
 | 
			
		||||
        .args_type  = "name:s",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_trace_event_get_state,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_trace_event_get_state,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -4088,7 +4107,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "trace-event-set-state",
 | 
			
		||||
        .args_type  = "name:s,enable:b,ignore-unavailable:b?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_trace_event_set_state,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_trace_event_set_state,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -4106,7 +4125,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "x-input-send-event",
 | 
			
		||||
        .args_type  = "console:i?,events:q",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_x_input_send_event,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_x_input_send_event,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -4171,7 +4190,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "block-set-write-threshold",
 | 
			
		||||
        .args_type  = "node-name:s,write-threshold:l",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_block_set_write_threshold,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_block_set_write_threshold,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -4199,7 +4218,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-rocker",
 | 
			
		||||
        .args_type  = "name:s",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_rocker,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_rocker,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -4220,7 +4239,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-rocker-ports",
 | 
			
		||||
        .args_type  = "name:s",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_rocker_ports,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_rocker_ports,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -4245,7 +4264,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-rocker-of-dpa-flows",
 | 
			
		||||
        .args_type  = "name:s,tbl-id:i?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_rocker_of_dpa_flows,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_rocker_of_dpa_flows,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
@ -4274,7 +4293,7 @@ EQMP
 | 
			
		||||
    {
 | 
			
		||||
        .name       = "query-rocker-of-dpa-groups",
 | 
			
		||||
        .args_type  = "name:s,type:i?",
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_input_query_rocker_of_dpa_groups,
 | 
			
		||||
        .mhandler.cmd_new = qmp_marshal_query_rocker_of_dpa_groups,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
SQMP
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										27
									
								
								qmp.c
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								qmp.c
									
									
									
									
									
								
							@ -157,9 +157,9 @@ VncInfo2List *qmp_query_vnc_servers(Error **errp)
 | 
			
		||||
 * #ifdef CONFIG_SPICE.  Necessary for an accurate query-commands
 | 
			
		||||
 * result.  However, the QAPI schema is blissfully unaware of that,
 | 
			
		||||
 * and the QAPI code generator happily generates a dead
 | 
			
		||||
 * qmp_marshal_input_query_spice() that calls qmp_query_spice().
 | 
			
		||||
 * Provide it one, or else linking fails.
 | 
			
		||||
 * FIXME Educate the QAPI schema on CONFIG_SPICE.
 | 
			
		||||
 * qmp_marshal_query_spice() that calls qmp_query_spice().  Provide it
 | 
			
		||||
 * one, or else linking fails.  FIXME Educate the QAPI schema on
 | 
			
		||||
 * CONFIG_SPICE.
 | 
			
		||||
 */
 | 
			
		||||
SpiceInfo *qmp_query_spice(Error **errp)
 | 
			
		||||
{
 | 
			
		||||
@ -234,12 +234,9 @@ ObjectPropertyInfoList *qmp_qom_list(const char *path, Error **errp)
 | 
			
		||||
    return props;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* FIXME: teach qapi about how to pass through Visitors */
 | 
			
		||||
void qmp_qom_set(QDict *qdict, QObject **ret, Error **errp)
 | 
			
		||||
void qmp_qom_set(const char *path, const char *property, QObject *value,
 | 
			
		||||
                 Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    const char *path = qdict_get_str(qdict, "path");
 | 
			
		||||
    const char *property = qdict_get_str(qdict, "property");
 | 
			
		||||
    QObject *value = qdict_get(qdict, "value");
 | 
			
		||||
    Object *obj;
 | 
			
		||||
 | 
			
		||||
    obj = object_resolve_path(path, NULL);
 | 
			
		||||
@ -252,20 +249,18 @@ void qmp_qom_set(QDict *qdict, QObject **ret, Error **errp)
 | 
			
		||||
    object_property_set_qobject(obj, value, property, errp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qmp_qom_get(QDict *qdict, QObject **ret, Error **errp)
 | 
			
		||||
QObject *qmp_qom_get(const char *path, const char *property, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    const char *path = qdict_get_str(qdict, "path");
 | 
			
		||||
    const char *property = qdict_get_str(qdict, "property");
 | 
			
		||||
    Object *obj;
 | 
			
		||||
 | 
			
		||||
    obj = object_resolve_path(path, NULL);
 | 
			
		||||
    if (!obj) {
 | 
			
		||||
        error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
 | 
			
		||||
                  "Device '%s' not found", path);
 | 
			
		||||
        return;
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *ret = object_property_get_qobject(obj, property, errp);
 | 
			
		||||
    return object_property_get_qobject(obj, property, errp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qmp_set_password(const char *protocol, const char *password,
 | 
			
		||||
@ -661,11 +656,9 @@ out:
 | 
			
		||||
    object_unref(obj);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void qmp_object_add(QDict *qdict, QObject **ret, Error **errp)
 | 
			
		||||
void qmp_object_add(const char *type, const char *id,
 | 
			
		||||
                    bool has_props, QObject *props, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    const char *type = qdict_get_str(qdict, "qom-type");
 | 
			
		||||
    const char *id = qdict_get_str(qdict, "id");
 | 
			
		||||
    QObject *props = qdict_get(qdict, "props");
 | 
			
		||||
    const QDict *pdict = NULL;
 | 
			
		||||
    QmpInputVisitor *qiv;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -12,22 +12,18 @@
 | 
			
		||||
# This work is licensed under the terms of the GNU GPL, version 2.
 | 
			
		||||
# See the COPYING file in the top-level directory.
 | 
			
		||||
 | 
			
		||||
from ordereddict import OrderedDict
 | 
			
		||||
from qapi import *
 | 
			
		||||
import re
 | 
			
		||||
 | 
			
		||||
def generate_command_decl(name, args, ret_type):
 | 
			
		||||
    arglist=""
 | 
			
		||||
    for argname, argtype, optional in parse_args(args):
 | 
			
		||||
        argtype = c_type(argtype, is_param=True)
 | 
			
		||||
        if optional:
 | 
			
		||||
            arglist += "bool has_%s, " % c_name(argname)
 | 
			
		||||
        arglist += "%s %s, " % (argtype, c_name(argname))
 | 
			
		||||
 | 
			
		||||
def gen_command_decl(name, arg_type, ret_type):
 | 
			
		||||
    return mcgen('''
 | 
			
		||||
%(ret_type)s qmp_%(name)s(%(args)sError **errp);
 | 
			
		||||
%(c_type)s qmp_%(c_name)s(%(params)s);
 | 
			
		||||
''',
 | 
			
		||||
                 ret_type=c_type(ret_type), name=c_name(name),
 | 
			
		||||
                 args=arglist)
 | 
			
		||||
                 c_type=(ret_type and ret_type.c_type()) or 'void',
 | 
			
		||||
                 c_name=c_name(name),
 | 
			
		||||
                 params=gen_params(arg_type, 'Error **errp'))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def gen_err_check(err):
 | 
			
		||||
    if not err:
 | 
			
		||||
@ -39,110 +35,124 @@ if (%(err)s) {
 | 
			
		||||
''',
 | 
			
		||||
                 err=err)
 | 
			
		||||
 | 
			
		||||
def gen_sync_call(name, args, ret_type):
 | 
			
		||||
    ret = ""
 | 
			
		||||
    arglist=""
 | 
			
		||||
    retval=""
 | 
			
		||||
 | 
			
		||||
def gen_call(name, arg_type, ret_type):
 | 
			
		||||
    ret = ''
 | 
			
		||||
 | 
			
		||||
    argstr = ''
 | 
			
		||||
    if arg_type:
 | 
			
		||||
        for memb in arg_type.members:
 | 
			
		||||
            if memb.optional:
 | 
			
		||||
                argstr += 'has_%s, ' % c_name(memb.name)
 | 
			
		||||
            argstr += '%s, ' % c_name(memb.name)
 | 
			
		||||
 | 
			
		||||
    lhs = ''
 | 
			
		||||
    if ret_type:
 | 
			
		||||
        retval = "retval = "
 | 
			
		||||
    for argname, argtype, optional in parse_args(args):
 | 
			
		||||
        if optional:
 | 
			
		||||
            arglist += "has_%s, " % c_name(argname)
 | 
			
		||||
        arglist += "%s, " % (c_name(argname))
 | 
			
		||||
        lhs = 'retval = '
 | 
			
		||||
 | 
			
		||||
    push_indent()
 | 
			
		||||
    ret = mcgen('''
 | 
			
		||||
%(retval)sqmp_%(name)s(%(args)s&local_err);
 | 
			
		||||
 | 
			
		||||
%(lhs)sqmp_%(c_name)s(%(args)s&local_err);
 | 
			
		||||
''',
 | 
			
		||||
                name=c_name(name), args=arglist, retval=retval)
 | 
			
		||||
                c_name=c_name(name), args=argstr, lhs=lhs)
 | 
			
		||||
    if ret_type:
 | 
			
		||||
        ret += gen_err_check('local_err')
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
 | 
			
		||||
qmp_marshal_output_%(c_name)s(retval, ret, &local_err);
 | 
			
		||||
''',
 | 
			
		||||
                            c_name=c_name(name))
 | 
			
		||||
                     c_name=ret_type.c_name())
 | 
			
		||||
    pop_indent()
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
def gen_visitor_input_containers_decl(args):
 | 
			
		||||
    ret = ""
 | 
			
		||||
 | 
			
		||||
def gen_marshal_vars(arg_type, ret_type):
 | 
			
		||||
    ret = mcgen('''
 | 
			
		||||
    Error *local_err = NULL;
 | 
			
		||||
''')
 | 
			
		||||
 | 
			
		||||
    push_indent()
 | 
			
		||||
    if len(args) > 0:
 | 
			
		||||
 | 
			
		||||
    if ret_type:
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
%(c_type)s retval;
 | 
			
		||||
''',
 | 
			
		||||
                     c_type=ret_type.c_type())
 | 
			
		||||
 | 
			
		||||
    if arg_type:
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
QmpInputVisitor *mi = qmp_input_visitor_new_strict(QOBJECT(args));
 | 
			
		||||
QapiDeallocVisitor *md;
 | 
			
		||||
Visitor *v;
 | 
			
		||||
''')
 | 
			
		||||
    pop_indent()
 | 
			
		||||
 | 
			
		||||
    return ret
 | 
			
		||||
        for memb in arg_type.members:
 | 
			
		||||
            if memb.optional:
 | 
			
		||||
                ret += mcgen('''
 | 
			
		||||
bool has_%(c_name)s = false;
 | 
			
		||||
''',
 | 
			
		||||
                             c_name=c_name(memb.name))
 | 
			
		||||
            ret += mcgen('''
 | 
			
		||||
%(c_type)s %(c_name)s = %(c_null)s;
 | 
			
		||||
''',
 | 
			
		||||
                         c_name=c_name(memb.name),
 | 
			
		||||
                         c_type=memb.type.c_type(),
 | 
			
		||||
                         c_null=memb.type.c_null())
 | 
			
		||||
        ret += '\n'
 | 
			
		||||
    else:
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
 | 
			
		||||
def gen_visitor_input_vars_decl(args):
 | 
			
		||||
    ret = ""
 | 
			
		||||
    push_indent()
 | 
			
		||||
    for argname, argtype, optional in parse_args(args):
 | 
			
		||||
        if optional:
 | 
			
		||||
            ret += mcgen('''
 | 
			
		||||
bool has_%(argname)s = false;
 | 
			
		||||
''',
 | 
			
		||||
                         argname=c_name(argname))
 | 
			
		||||
        if is_c_ptr(argtype):
 | 
			
		||||
            ret += mcgen('''
 | 
			
		||||
%(argtype)s %(argname)s = NULL;
 | 
			
		||||
''',
 | 
			
		||||
                         argname=c_name(argname), argtype=c_type(argtype))
 | 
			
		||||
        else:
 | 
			
		||||
            ret += mcgen('''
 | 
			
		||||
%(argtype)s %(argname)s = {0};
 | 
			
		||||
''',
 | 
			
		||||
                         argname=c_name(argname), argtype=c_type(argtype))
 | 
			
		||||
(void)args;
 | 
			
		||||
''')
 | 
			
		||||
 | 
			
		||||
    pop_indent()
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
def gen_visitor_input_block(args, dealloc=False):
 | 
			
		||||
    ret = ""
 | 
			
		||||
    errparg = '&local_err'
 | 
			
		||||
    errarg = 'local_err'
 | 
			
		||||
 | 
			
		||||
    if len(args) == 0:
 | 
			
		||||
def gen_marshal_input_visit(arg_type, dealloc=False):
 | 
			
		||||
    ret = ''
 | 
			
		||||
 | 
			
		||||
    if not arg_type:
 | 
			
		||||
        return ret
 | 
			
		||||
 | 
			
		||||
    push_indent()
 | 
			
		||||
 | 
			
		||||
    if dealloc:
 | 
			
		||||
        errparg = 'NULL'
 | 
			
		||||
        errarg = None;
 | 
			
		||||
        errarg = None
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
qmp_input_visitor_cleanup(mi);
 | 
			
		||||
md = qapi_dealloc_visitor_new();
 | 
			
		||||
v = qapi_dealloc_get_visitor(md);
 | 
			
		||||
''')
 | 
			
		||||
    else:
 | 
			
		||||
        errparg = '&local_err'
 | 
			
		||||
        errarg = 'local_err'
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
v = qmp_input_get_visitor(mi);
 | 
			
		||||
''')
 | 
			
		||||
 | 
			
		||||
    for argname, argtype, optional in parse_args(args):
 | 
			
		||||
        if optional:
 | 
			
		||||
    for memb in arg_type.members:
 | 
			
		||||
        if memb.optional:
 | 
			
		||||
            ret += mcgen('''
 | 
			
		||||
visit_optional(v, &has_%(c_name)s, "%(name)s", %(errp)s);
 | 
			
		||||
''',
 | 
			
		||||
                         c_name=c_name(argname), name=argname, errp=errparg)
 | 
			
		||||
                         c_name=c_name(memb.name), name=memb.name,
 | 
			
		||||
                         errp=errparg)
 | 
			
		||||
            ret += gen_err_check(errarg)
 | 
			
		||||
            ret += mcgen('''
 | 
			
		||||
if (has_%(c_name)s) {
 | 
			
		||||
''',
 | 
			
		||||
                         c_name=c_name(argname))
 | 
			
		||||
                         c_name=c_name(memb.name))
 | 
			
		||||
            push_indent()
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
visit_type_%(visitor)s(v, &%(c_name)s, "%(name)s", %(errp)s);
 | 
			
		||||
visit_type_%(c_type)s(v, &%(c_name)s, "%(name)s", %(errp)s);
 | 
			
		||||
''',
 | 
			
		||||
                     c_name=c_name(argname), name=argname, argtype=argtype,
 | 
			
		||||
                     visitor=type_name(argtype), errp=errparg)
 | 
			
		||||
                     c_name=c_name(memb.name), name=memb.name,
 | 
			
		||||
                     c_type=memb.type.c_name(), errp=errparg)
 | 
			
		||||
        ret += gen_err_check(errarg)
 | 
			
		||||
        if optional:
 | 
			
		||||
        if memb.optional:
 | 
			
		||||
            pop_indent()
 | 
			
		||||
            ret += mcgen('''
 | 
			
		||||
}
 | 
			
		||||
@ -155,12 +165,11 @@ qapi_dealloc_visitor_cleanup(md);
 | 
			
		||||
    pop_indent()
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
def gen_marshal_output(name, ret_type):
 | 
			
		||||
    if not ret_type:
 | 
			
		||||
        return ""
 | 
			
		||||
 | 
			
		||||
    ret = mcgen('''
 | 
			
		||||
static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_out, Error **errp)
 | 
			
		||||
def gen_marshal_output(ret_type):
 | 
			
		||||
    return mcgen('''
 | 
			
		||||
 | 
			
		||||
static void qmp_marshal_output_%(c_name)s(%(c_type)s ret_in, QObject **ret_out, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    Error *local_err = NULL;
 | 
			
		||||
    QmpOutputVisitor *mo = qmp_output_visitor_new();
 | 
			
		||||
@ -168,7 +177,7 @@ static void qmp_marshal_output_%(c_name)s(%(c_ret_type)s ret_in, QObject **ret_o
 | 
			
		||||
    Visitor *v;
 | 
			
		||||
 | 
			
		||||
    v = qmp_output_get_visitor(mo);
 | 
			
		||||
    visit_type_%(visitor)s(v, &ret_in, "unused", &local_err);
 | 
			
		||||
    visit_type_%(c_name)s(v, &ret_in, "unused", &local_err);
 | 
			
		||||
    if (local_err) {
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
@ -179,51 +188,40 @@ out:
 | 
			
		||||
    qmp_output_visitor_cleanup(mo);
 | 
			
		||||
    md = qapi_dealloc_visitor_new();
 | 
			
		||||
    v = qapi_dealloc_get_visitor(md);
 | 
			
		||||
    visit_type_%(visitor)s(v, &ret_in, "unused", NULL);
 | 
			
		||||
    visit_type_%(c_name)s(v, &ret_in, "unused", NULL);
 | 
			
		||||
    qapi_dealloc_visitor_cleanup(md);
 | 
			
		||||
}
 | 
			
		||||
''',
 | 
			
		||||
                c_ret_type=c_type(ret_type), c_name=c_name(name),
 | 
			
		||||
                visitor=type_name(ret_type))
 | 
			
		||||
                 c_type=ret_type.c_type(), c_name=ret_type.c_name())
 | 
			
		||||
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
def gen_marshal_input_decl(name, middle_mode):
 | 
			
		||||
    ret = 'void qmp_marshal_input_%s(QDict *args, QObject **ret, Error **errp)' % c_name(name)
 | 
			
		||||
def gen_marshal_proto(name):
 | 
			
		||||
    ret = 'void qmp_marshal_%s(QDict *args, QObject **ret, Error **errp)' % c_name(name)
 | 
			
		||||
    if not middle_mode:
 | 
			
		||||
        ret = "static " + ret
 | 
			
		||||
        ret = 'static ' + ret
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
def gen_marshal_input(name, args, ret_type, middle_mode):
 | 
			
		||||
    hdr = gen_marshal_input_decl(name, middle_mode)
 | 
			
		||||
 | 
			
		||||
def gen_marshal_decl(name):
 | 
			
		||||
    return mcgen('''
 | 
			
		||||
%(proto)s;
 | 
			
		||||
''',
 | 
			
		||||
                 proto=gen_marshal_proto(name))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def gen_marshal(name, arg_type, ret_type):
 | 
			
		||||
    ret = mcgen('''
 | 
			
		||||
%(header)s
 | 
			
		||||
 | 
			
		||||
%(proto)s
 | 
			
		||||
{
 | 
			
		||||
    Error *local_err = NULL;
 | 
			
		||||
''',
 | 
			
		||||
                header=hdr)
 | 
			
		||||
                proto=gen_marshal_proto(name))
 | 
			
		||||
 | 
			
		||||
    if ret_type:
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
    %(c_type)s retval;
 | 
			
		||||
''',
 | 
			
		||||
                     c_type=c_type(ret_type))
 | 
			
		||||
    ret += gen_marshal_vars(arg_type, ret_type)
 | 
			
		||||
    ret += gen_marshal_input_visit(arg_type)
 | 
			
		||||
    ret += gen_call(name, arg_type, ret_type)
 | 
			
		||||
 | 
			
		||||
    if len(args) > 0:
 | 
			
		||||
        ret += gen_visitor_input_containers_decl(args)
 | 
			
		||||
        ret += gen_visitor_input_vars_decl(args) + '\n'
 | 
			
		||||
        ret += gen_visitor_input_block(args) + '\n'
 | 
			
		||||
    else:
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
 | 
			
		||||
    (void)args;
 | 
			
		||||
 | 
			
		||||
''')
 | 
			
		||||
 | 
			
		||||
    ret += gen_sync_call(name, args, ret_type)
 | 
			
		||||
 | 
			
		||||
    if re.search('^ *goto out\\;', ret, re.MULTILINE):
 | 
			
		||||
    if re.search('^ *goto out;', ret, re.MULTILINE):
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
@ -231,27 +229,31 @@ out:
 | 
			
		||||
    ret += mcgen('''
 | 
			
		||||
    error_propagate(errp, local_err);
 | 
			
		||||
''')
 | 
			
		||||
    ret += gen_visitor_input_block(args, dealloc=True)
 | 
			
		||||
    ret += gen_marshal_input_visit(arg_type, dealloc=True)
 | 
			
		||||
    ret += mcgen('''
 | 
			
		||||
}
 | 
			
		||||
''')
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
def gen_registry(commands):
 | 
			
		||||
    registry=""
 | 
			
		||||
    push_indent()
 | 
			
		||||
    for cmd in commands:
 | 
			
		||||
        options = 'QCO_NO_OPTIONS'
 | 
			
		||||
        if not cmd.get('success-response', True):
 | 
			
		||||
            options = 'QCO_NO_SUCCESS_RESP'
 | 
			
		||||
 | 
			
		||||
        registry += mcgen('''
 | 
			
		||||
qmp_register_command("%(name)s", qmp_marshal_input_%(c_name)s, %(opts)s);
 | 
			
		||||
''',
 | 
			
		||||
                     name=cmd['command'], c_name=c_name(cmd['command']),
 | 
			
		||||
                     opts=options)
 | 
			
		||||
    pop_indent()
 | 
			
		||||
def gen_register_command(name, success_response):
 | 
			
		||||
    push_indent()
 | 
			
		||||
    options = 'QCO_NO_OPTIONS'
 | 
			
		||||
    if not success_response:
 | 
			
		||||
        options = 'QCO_NO_SUCCESS_RESP'
 | 
			
		||||
 | 
			
		||||
    ret = mcgen('''
 | 
			
		||||
qmp_register_command("%(name)s", qmp_marshal_%(c_name)s, %(opts)s);
 | 
			
		||||
''',
 | 
			
		||||
                name=name, c_name=c_name(name),
 | 
			
		||||
                opts=options)
 | 
			
		||||
    pop_indent()
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def gen_registry(registry):
 | 
			
		||||
    ret = mcgen('''
 | 
			
		||||
 | 
			
		||||
static void qmp_init_marshal(void)
 | 
			
		||||
{
 | 
			
		||||
''')
 | 
			
		||||
@ -263,6 +265,41 @@ qapi_init(qmp_init_marshal);
 | 
			
		||||
''')
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class QAPISchemaGenCommandVisitor(QAPISchemaVisitor):
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        self.decl = None
 | 
			
		||||
        self.defn = None
 | 
			
		||||
        self._regy = None
 | 
			
		||||
        self._visited_ret_types = None
 | 
			
		||||
 | 
			
		||||
    def visit_begin(self, schema):
 | 
			
		||||
        self.decl = ''
 | 
			
		||||
        self.defn = ''
 | 
			
		||||
        self._regy = ''
 | 
			
		||||
        self._visited_ret_types = set()
 | 
			
		||||
 | 
			
		||||
    def visit_end(self):
 | 
			
		||||
        if not middle_mode:
 | 
			
		||||
            self.defn += gen_registry(self._regy)
 | 
			
		||||
        self._regy = None
 | 
			
		||||
        self._visited_ret_types = None
 | 
			
		||||
 | 
			
		||||
    def visit_command(self, name, info, arg_type, ret_type,
 | 
			
		||||
                      gen, success_response):
 | 
			
		||||
        if not gen:
 | 
			
		||||
            return
 | 
			
		||||
        self.decl += gen_command_decl(name, arg_type, ret_type)
 | 
			
		||||
        if ret_type and ret_type not in self._visited_ret_types:
 | 
			
		||||
            self._visited_ret_types.add(ret_type)
 | 
			
		||||
            self.defn += gen_marshal_output(ret_type)
 | 
			
		||||
        if middle_mode:
 | 
			
		||||
            self.decl += gen_marshal_decl(name)
 | 
			
		||||
        self.defn += gen_marshal(name, arg_type, ret_type)
 | 
			
		||||
        if not middle_mode:
 | 
			
		||||
            self._regy += gen_register_command(name, success_response)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
middle_mode = False
 | 
			
		||||
 | 
			
		||||
(input_file, output_dir, do_c, do_h, prefix, opts) = \
 | 
			
		||||
@ -272,10 +309,6 @@ for o, a in opts:
 | 
			
		||||
    if o in ("-m", "--middle"):
 | 
			
		||||
        middle_mode = True
 | 
			
		||||
 | 
			
		||||
exprs = parse_schema(input_file)
 | 
			
		||||
commands = filter(lambda expr: expr.has_key('command'), exprs)
 | 
			
		||||
commands = filter(lambda expr: not expr.has_key('gen'), commands)
 | 
			
		||||
 | 
			
		||||
c_comment = '''
 | 
			
		||||
/*
 | 
			
		||||
 * schema-defined QMP->QAPI command dispatch
 | 
			
		||||
@ -323,7 +356,7 @@ fdef.write(mcgen('''
 | 
			
		||||
#include "%(prefix)sqmp-commands.h"
 | 
			
		||||
 | 
			
		||||
''',
 | 
			
		||||
                prefix=prefix))
 | 
			
		||||
                 prefix=prefix))
 | 
			
		||||
 | 
			
		||||
fdecl.write(mcgen('''
 | 
			
		||||
#include "%(prefix)sqapi-types.h"
 | 
			
		||||
@ -331,29 +364,12 @@ fdecl.write(mcgen('''
 | 
			
		||||
#include "qapi/error.h"
 | 
			
		||||
 | 
			
		||||
''',
 | 
			
		||||
                 prefix=prefix))
 | 
			
		||||
                  prefix=prefix))
 | 
			
		||||
 | 
			
		||||
for cmd in commands:
 | 
			
		||||
    arglist = []
 | 
			
		||||
    ret_type = None
 | 
			
		||||
    if cmd.has_key('data'):
 | 
			
		||||
        arglist = cmd['data']
 | 
			
		||||
    if cmd.has_key('returns'):
 | 
			
		||||
        ret_type = cmd['returns']
 | 
			
		||||
    ret = generate_command_decl(cmd['command'], arglist, ret_type)
 | 
			
		||||
    fdecl.write(ret)
 | 
			
		||||
    if ret_type:
 | 
			
		||||
        ret = gen_marshal_output(cmd['command'], ret_type) + "\n"
 | 
			
		||||
        fdef.write(ret)
 | 
			
		||||
 | 
			
		||||
    if middle_mode:
 | 
			
		||||
        fdecl.write('%s;\n' % gen_marshal_input_decl(cmd['command'], middle_mode))
 | 
			
		||||
 | 
			
		||||
    ret = gen_marshal_input(cmd['command'], arglist, ret_type, middle_mode) + "\n"
 | 
			
		||||
    fdef.write(ret)
 | 
			
		||||
 | 
			
		||||
if not middle_mode:
 | 
			
		||||
    ret = gen_registry(commands)
 | 
			
		||||
    fdef.write(ret)
 | 
			
		||||
schema = QAPISchema(input_file)
 | 
			
		||||
gen = QAPISchemaGenCommandVisitor()
 | 
			
		||||
schema.visit(gen)
 | 
			
		||||
fdef.write(gen.defn)
 | 
			
		||||
fdecl.write(gen.decl)
 | 
			
		||||
 | 
			
		||||
close_output(fdef, fdecl)
 | 
			
		||||
 | 
			
		||||
@ -2,78 +2,64 @@
 | 
			
		||||
# QAPI event generator
 | 
			
		||||
#
 | 
			
		||||
# Copyright (c) 2014 Wenchao Xia
 | 
			
		||||
# Copyright (c) 2015 Red Hat Inc.
 | 
			
		||||
#
 | 
			
		||||
# Authors:
 | 
			
		||||
#  Wenchao Xia <wenchaoqemu@gmail.com>
 | 
			
		||||
#  Markus Armbruster <armbru@redhat.com>
 | 
			
		||||
#
 | 
			
		||||
# This work is licensed under the terms of the GNU GPL, version 2.
 | 
			
		||||
# See the COPYING file in the top-level directory.
 | 
			
		||||
 | 
			
		||||
from ordereddict import OrderedDict
 | 
			
		||||
from qapi import *
 | 
			
		||||
 | 
			
		||||
def _generate_event_api_name(event_name, params):
 | 
			
		||||
    api_name = "void qapi_event_send_%s(" % c_name(event_name).lower();
 | 
			
		||||
    l = len(api_name)
 | 
			
		||||
 | 
			
		||||
    if params:
 | 
			
		||||
        for argname, argentry, optional in parse_args(params):
 | 
			
		||||
            if optional:
 | 
			
		||||
                api_name += "bool has_%s,\n" % c_name(argname)
 | 
			
		||||
                api_name += "".ljust(l)
 | 
			
		||||
 | 
			
		||||
            api_name += "%s %s,\n" % (c_type(argentry, is_param=True),
 | 
			
		||||
                                      c_name(argname))
 | 
			
		||||
            api_name += "".ljust(l)
 | 
			
		||||
 | 
			
		||||
    api_name += "Error **errp)"
 | 
			
		||||
    return api_name;
 | 
			
		||||
def gen_event_send_proto(name, arg_type):
 | 
			
		||||
    return 'void qapi_event_send_%(c_name)s(%(param)s)' % {
 | 
			
		||||
        'c_name': c_name(name.lower()),
 | 
			
		||||
        'param': gen_params(arg_type, 'Error **errp')}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Following are the core functions that generate C APIs to emit event.
 | 
			
		||||
 | 
			
		||||
def generate_event_declaration(api_name):
 | 
			
		||||
def gen_event_send_decl(name, arg_type):
 | 
			
		||||
    return mcgen('''
 | 
			
		||||
 | 
			
		||||
%(api_name)s;
 | 
			
		||||
%(proto)s;
 | 
			
		||||
''',
 | 
			
		||||
                 api_name = api_name)
 | 
			
		||||
                 proto=gen_event_send_proto(name, arg_type))
 | 
			
		||||
 | 
			
		||||
def generate_event_implement(api_name, event_name, params):
 | 
			
		||||
    # step 1: declare any variables
 | 
			
		||||
    ret = mcgen("""
 | 
			
		||||
 | 
			
		||||
%(api_name)s
 | 
			
		||||
def gen_event_send(name, arg_type):
 | 
			
		||||
    ret = mcgen('''
 | 
			
		||||
 | 
			
		||||
%(proto)s
 | 
			
		||||
{
 | 
			
		||||
    QDict *qmp;
 | 
			
		||||
    Error *local_err = NULL;
 | 
			
		||||
    QMPEventFuncEmit emit;
 | 
			
		||||
""",
 | 
			
		||||
                api_name = api_name)
 | 
			
		||||
''',
 | 
			
		||||
                proto=gen_event_send_proto(name, arg_type))
 | 
			
		||||
 | 
			
		||||
    if params:
 | 
			
		||||
        ret += mcgen("""
 | 
			
		||||
    if arg_type and arg_type.members:
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
    QmpOutputVisitor *qov;
 | 
			
		||||
    Visitor *v;
 | 
			
		||||
    QObject *obj;
 | 
			
		||||
 | 
			
		||||
""")
 | 
			
		||||
''')
 | 
			
		||||
 | 
			
		||||
    # step 2: check emit function, create a dict
 | 
			
		||||
    ret += mcgen("""
 | 
			
		||||
    ret += mcgen('''
 | 
			
		||||
    emit = qmp_event_get_func_emit();
 | 
			
		||||
    if (!emit) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    qmp = qmp_event_build_dict("%(event_name)s");
 | 
			
		||||
    qmp = qmp_event_build_dict("%(name)s");
 | 
			
		||||
 | 
			
		||||
""",
 | 
			
		||||
                 event_name = event_name)
 | 
			
		||||
''',
 | 
			
		||||
                 name=name)
 | 
			
		||||
 | 
			
		||||
    # step 3: visit the params if params != None
 | 
			
		||||
    if params:
 | 
			
		||||
        ret += mcgen("""
 | 
			
		||||
    if arg_type and arg_type.members:
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
    qov = qmp_output_visitor_new();
 | 
			
		||||
    g_assert(qov);
 | 
			
		||||
 | 
			
		||||
@ -81,45 +67,46 @@ def generate_event_implement(api_name, event_name, params):
 | 
			
		||||
    g_assert(v);
 | 
			
		||||
 | 
			
		||||
    /* Fake visit, as if all members are under a structure */
 | 
			
		||||
    visit_start_struct(v, NULL, "", "%(event_name)s", 0, &local_err);
 | 
			
		||||
    visit_start_struct(v, NULL, "", "%(name)s", 0, &local_err);
 | 
			
		||||
    if (local_err) {
 | 
			
		||||
        goto clean;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
""",
 | 
			
		||||
                event_name = event_name)
 | 
			
		||||
''',
 | 
			
		||||
                     name=name)
 | 
			
		||||
 | 
			
		||||
        for argname, argentry, optional in parse_args(params):
 | 
			
		||||
            if optional:
 | 
			
		||||
                ret += mcgen("""
 | 
			
		||||
    if (has_%(var)s) {
 | 
			
		||||
""",
 | 
			
		||||
                             var = c_name(argname))
 | 
			
		||||
        for memb in arg_type.members:
 | 
			
		||||
            if memb.optional:
 | 
			
		||||
                ret += mcgen('''
 | 
			
		||||
    if (has_%(c_name)s) {
 | 
			
		||||
''',
 | 
			
		||||
                             c_name=c_name(memb.name))
 | 
			
		||||
                push_indent()
 | 
			
		||||
 | 
			
		||||
            if argentry == "str":
 | 
			
		||||
                var_type = "(char **)"
 | 
			
		||||
            # Ugly: need to cast away the const
 | 
			
		||||
            if memb.type.name == "str":
 | 
			
		||||
                cast = '(char **)'
 | 
			
		||||
            else:
 | 
			
		||||
                var_type = ""
 | 
			
		||||
                cast = ''
 | 
			
		||||
 | 
			
		||||
            ret += mcgen("""
 | 
			
		||||
    visit_type_%(type)s(v, %(var_type)s&%(var)s, "%(name)s", &local_err);
 | 
			
		||||
            ret += mcgen('''
 | 
			
		||||
    visit_type_%(c_type)s(v, %(cast)s&%(c_name)s, "%(name)s", &local_err);
 | 
			
		||||
    if (local_err) {
 | 
			
		||||
        goto clean;
 | 
			
		||||
    }
 | 
			
		||||
""",
 | 
			
		||||
                         var_type = var_type,
 | 
			
		||||
                         var = c_name(argname),
 | 
			
		||||
                         type = type_name(argentry),
 | 
			
		||||
                         name = argname)
 | 
			
		||||
''',
 | 
			
		||||
                         cast=cast,
 | 
			
		||||
                         c_name=c_name(memb.name),
 | 
			
		||||
                         c_type=memb.type.c_name(),
 | 
			
		||||
                         name=memb.name)
 | 
			
		||||
 | 
			
		||||
            if optional:
 | 
			
		||||
            if memb.optional:
 | 
			
		||||
                pop_indent()
 | 
			
		||||
                ret += mcgen("""
 | 
			
		||||
                ret += mcgen('''
 | 
			
		||||
    }
 | 
			
		||||
""")
 | 
			
		||||
''')
 | 
			
		||||
 | 
			
		||||
        ret += mcgen("""
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
 | 
			
		||||
    visit_end_struct(v, &local_err);
 | 
			
		||||
    if (local_err) {
 | 
			
		||||
@ -130,86 +117,49 @@ def generate_event_implement(api_name, event_name, params):
 | 
			
		||||
    g_assert(obj != NULL);
 | 
			
		||||
 | 
			
		||||
    qdict_put_obj(qmp, "data", obj);
 | 
			
		||||
""")
 | 
			
		||||
''')
 | 
			
		||||
 | 
			
		||||
    # step 4: call qmp event api
 | 
			
		||||
    ret += mcgen("""
 | 
			
		||||
    emit(%(event_enum_value)s, qmp, &local_err);
 | 
			
		||||
    ret += mcgen('''
 | 
			
		||||
    emit(%(c_enum)s, qmp, &local_err);
 | 
			
		||||
 | 
			
		||||
""",
 | 
			
		||||
                 event_enum_value = event_enum_value)
 | 
			
		||||
''',
 | 
			
		||||
                 c_enum=c_enum_const(event_enum_name, name))
 | 
			
		||||
 | 
			
		||||
    # step 5: clean up
 | 
			
		||||
    if params:
 | 
			
		||||
        ret += mcgen("""
 | 
			
		||||
    if arg_type and arg_type.members:
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
 clean:
 | 
			
		||||
    qmp_output_visitor_cleanup(qov);
 | 
			
		||||
""")
 | 
			
		||||
    ret += mcgen("""
 | 
			
		||||
''')
 | 
			
		||||
    ret += mcgen('''
 | 
			
		||||
    error_propagate(errp, local_err);
 | 
			
		||||
    QDECREF(qmp);
 | 
			
		||||
}
 | 
			
		||||
""")
 | 
			
		||||
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Following are the functions that generate an enum type for all defined
 | 
			
		||||
# events, similar to qapi-types.py. Here we already have enum name and
 | 
			
		||||
# values which were generated before and recorded in event_enum_*. It also
 | 
			
		||||
# works around the issue that "import qapi-types" can't work.
 | 
			
		||||
 | 
			
		||||
def generate_event_enum_decl(event_enum_name, event_enum_values):
 | 
			
		||||
    lookup_decl = mcgen('''
 | 
			
		||||
 | 
			
		||||
extern const char *%(event_enum_name)s_lookup[];
 | 
			
		||||
''',
 | 
			
		||||
                        event_enum_name = event_enum_name)
 | 
			
		||||
 | 
			
		||||
    enum_decl = mcgen('''
 | 
			
		||||
typedef enum %(event_enum_name)s {
 | 
			
		||||
''',
 | 
			
		||||
                      event_enum_name = event_enum_name)
 | 
			
		||||
 | 
			
		||||
    # append automatically generated _MAX value
 | 
			
		||||
    enum_max_value = c_enum_const(event_enum_name, "MAX")
 | 
			
		||||
    enum_values = event_enum_values + [ enum_max_value ]
 | 
			
		||||
 | 
			
		||||
    i = 0
 | 
			
		||||
    for value in enum_values:
 | 
			
		||||
        enum_decl += mcgen('''
 | 
			
		||||
    %(value)s = %(i)d,
 | 
			
		||||
''',
 | 
			
		||||
                     value = value,
 | 
			
		||||
                     i = i)
 | 
			
		||||
        i += 1
 | 
			
		||||
 | 
			
		||||
    enum_decl += mcgen('''
 | 
			
		||||
} %(event_enum_name)s;
 | 
			
		||||
''',
 | 
			
		||||
                       event_enum_name = event_enum_name)
 | 
			
		||||
 | 
			
		||||
    return lookup_decl + enum_decl
 | 
			
		||||
 | 
			
		||||
def generate_event_enum_lookup(event_enum_name, event_enum_strings):
 | 
			
		||||
    ret = mcgen('''
 | 
			
		||||
 | 
			
		||||
const char *%(event_enum_name)s_lookup[] = {
 | 
			
		||||
''',
 | 
			
		||||
                event_enum_name = event_enum_name)
 | 
			
		||||
 | 
			
		||||
    for string in event_enum_strings:
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
    "%(string)s",
 | 
			
		||||
''',
 | 
			
		||||
                     string = string)
 | 
			
		||||
 | 
			
		||||
    ret += mcgen('''
 | 
			
		||||
    NULL,
 | 
			
		||||
};
 | 
			
		||||
''')
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class QAPISchemaGenEventVisitor(QAPISchemaVisitor):
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        self.decl = None
 | 
			
		||||
        self.defn = None
 | 
			
		||||
        self._event_names = None
 | 
			
		||||
 | 
			
		||||
    def visit_begin(self, schema):
 | 
			
		||||
        self.decl = ''
 | 
			
		||||
        self.defn = ''
 | 
			
		||||
        self._event_names = []
 | 
			
		||||
 | 
			
		||||
    def visit_end(self):
 | 
			
		||||
        self.decl += gen_enum(event_enum_name, self._event_names)
 | 
			
		||||
        self.defn += gen_enum_lookup(event_enum_name, self._event_names)
 | 
			
		||||
        self._event_names = None
 | 
			
		||||
 | 
			
		||||
    def visit_event(self, name, info, arg_type):
 | 
			
		||||
        self.decl += gen_event_send_decl(name, arg_type)
 | 
			
		||||
        self.defn += gen_event_send(name, arg_type)
 | 
			
		||||
        self._event_names.append(name)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
(input_file, output_dir, do_c, do_h, prefix, dummy) = parse_command_line()
 | 
			
		||||
 | 
			
		||||
c_comment = '''
 | 
			
		||||
@ -263,35 +213,12 @@ fdecl.write(mcgen('''
 | 
			
		||||
''',
 | 
			
		||||
                  prefix=prefix))
 | 
			
		||||
 | 
			
		||||
exprs = parse_schema(input_file)
 | 
			
		||||
 | 
			
		||||
event_enum_name = c_name(prefix + "QAPIEvent", protect=False)
 | 
			
		||||
event_enum_values = []
 | 
			
		||||
event_enum_strings = []
 | 
			
		||||
 | 
			
		||||
for expr in exprs:
 | 
			
		||||
    if expr.has_key('event'):
 | 
			
		||||
        event_name = expr['event']
 | 
			
		||||
        params = expr.get('data')
 | 
			
		||||
        if params and len(params) == 0:
 | 
			
		||||
            params = None
 | 
			
		||||
 | 
			
		||||
        api_name = _generate_event_api_name(event_name, params)
 | 
			
		||||
        ret = generate_event_declaration(api_name)
 | 
			
		||||
        fdecl.write(ret)
 | 
			
		||||
 | 
			
		||||
        # We need an enum value per event
 | 
			
		||||
        event_enum_value = c_enum_const(event_enum_name, event_name)
 | 
			
		||||
        ret = generate_event_implement(api_name, event_name, params)
 | 
			
		||||
        fdef.write(ret)
 | 
			
		||||
 | 
			
		||||
        # Record it, and generate enum later
 | 
			
		||||
        event_enum_values.append(event_enum_value)
 | 
			
		||||
        event_enum_strings.append(event_name)
 | 
			
		||||
 | 
			
		||||
ret = generate_event_enum_decl(event_enum_name, event_enum_values)
 | 
			
		||||
fdecl.write(ret)
 | 
			
		||||
ret = generate_event_enum_lookup(event_enum_name, event_enum_strings)
 | 
			
		||||
fdef.write(ret)
 | 
			
		||||
schema = QAPISchema(input_file)
 | 
			
		||||
gen = QAPISchemaGenEventVisitor()
 | 
			
		||||
schema.visit(gen)
 | 
			
		||||
fdef.write(gen.defn)
 | 
			
		||||
fdecl.write(gen.decl)
 | 
			
		||||
 | 
			
		||||
close_output(fdef, fdecl)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										213
									
								
								scripts/qapi-introspect.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								scripts/qapi-introspect.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,213 @@
 | 
			
		||||
#
 | 
			
		||||
# QAPI introspection generator
 | 
			
		||||
#
 | 
			
		||||
# Copyright (C) 2015 Red Hat, Inc.
 | 
			
		||||
#
 | 
			
		||||
# Authors:
 | 
			
		||||
#  Markus Armbruster <armbru@redhat.com>
 | 
			
		||||
#
 | 
			
		||||
# This work is licensed under the terms of the GNU GPL, version 2.
 | 
			
		||||
# See the COPYING file in the top-level directory.
 | 
			
		||||
 | 
			
		||||
from qapi import *
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Caveman's json.dumps() replacement (we're stuck at Python 2.4)
 | 
			
		||||
# TODO try to use json.dumps() once we get unstuck
 | 
			
		||||
def to_json(obj, level=0):
 | 
			
		||||
    if obj is None:
 | 
			
		||||
        ret = 'null'
 | 
			
		||||
    elif isinstance(obj, str):
 | 
			
		||||
        ret = '"' + obj.replace('"', r'\"') + '"'
 | 
			
		||||
    elif isinstance(obj, list):
 | 
			
		||||
        elts = [to_json(elt, level + 1)
 | 
			
		||||
                for elt in obj]
 | 
			
		||||
        ret = '[' + ', '.join(elts) + ']'
 | 
			
		||||
    elif isinstance(obj, dict):
 | 
			
		||||
        elts = ['"%s": %s' % (key.replace('"', r'\"'),
 | 
			
		||||
                              to_json(obj[key], level + 1))
 | 
			
		||||
                for key in sorted(obj.keys())]
 | 
			
		||||
        ret = '{' + ', '.join(elts) + '}'
 | 
			
		||||
    else:
 | 
			
		||||
        assert False                # not implemented
 | 
			
		||||
    if level == 1:
 | 
			
		||||
        ret = '\n' + ret
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def to_c_string(string):
 | 
			
		||||
    return '"' + string.replace('\\', r'\\').replace('"', r'\"') + '"'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class QAPISchemaGenIntrospectVisitor(QAPISchemaVisitor):
 | 
			
		||||
    def __init__(self, unmask):
 | 
			
		||||
        self._unmask = unmask
 | 
			
		||||
        self.defn = None
 | 
			
		||||
        self.decl = None
 | 
			
		||||
        self._schema = None
 | 
			
		||||
        self._jsons = None
 | 
			
		||||
        self._used_types = None
 | 
			
		||||
        self._name_map = None
 | 
			
		||||
 | 
			
		||||
    def visit_begin(self, schema):
 | 
			
		||||
        self._schema = schema
 | 
			
		||||
        self._jsons = []
 | 
			
		||||
        self._used_types = []
 | 
			
		||||
        self._name_map = {}
 | 
			
		||||
        return QAPISchemaType   # don't visit types for now
 | 
			
		||||
 | 
			
		||||
    def visit_end(self):
 | 
			
		||||
        # visit the types that are actually used
 | 
			
		||||
        jsons = self._jsons
 | 
			
		||||
        self._jsons = []
 | 
			
		||||
        for typ in self._used_types:
 | 
			
		||||
            typ.visit(self)
 | 
			
		||||
        # generate C
 | 
			
		||||
        # TODO can generate awfully long lines
 | 
			
		||||
        jsons.extend(self._jsons)
 | 
			
		||||
        name = prefix + 'qmp_schema_json'
 | 
			
		||||
        self.decl = mcgen('''
 | 
			
		||||
extern const char %(c_name)s[];
 | 
			
		||||
''',
 | 
			
		||||
                          c_name=c_name(name))
 | 
			
		||||
        lines = to_json(jsons).split('\n')
 | 
			
		||||
        c_string = '\n    '.join([to_c_string(line) for line in lines])
 | 
			
		||||
        self.defn = mcgen('''
 | 
			
		||||
const char %(c_name)s[] = %(c_string)s;
 | 
			
		||||
''',
 | 
			
		||||
                          c_name=c_name(name),
 | 
			
		||||
                          c_string=c_string)
 | 
			
		||||
        self._schema = None
 | 
			
		||||
        self._jsons = None
 | 
			
		||||
        self._used_types = None
 | 
			
		||||
        self._name_map = None
 | 
			
		||||
 | 
			
		||||
    def _name(self, name):
 | 
			
		||||
        if self._unmask:
 | 
			
		||||
            return name
 | 
			
		||||
        if name not in self._name_map:
 | 
			
		||||
            self._name_map[name] = '%d' % len(self._name_map)
 | 
			
		||||
        return self._name_map[name]
 | 
			
		||||
 | 
			
		||||
    def _use_type(self, typ):
 | 
			
		||||
        # Map the various integer types to plain int
 | 
			
		||||
        if typ.json_type() == 'int':
 | 
			
		||||
            typ = self._schema.lookup_type('int')
 | 
			
		||||
        elif (isinstance(typ, QAPISchemaArrayType) and
 | 
			
		||||
              typ.element_type.json_type() == 'int'):
 | 
			
		||||
            typ = self._schema.lookup_type('intList')
 | 
			
		||||
        # Add type to work queue if new
 | 
			
		||||
        if typ not in self._used_types:
 | 
			
		||||
            self._used_types.append(typ)
 | 
			
		||||
        # Clients should examine commands and events, not types.  Hide
 | 
			
		||||
        # type names to reduce the temptation.  Also saves a few
 | 
			
		||||
        # characters.
 | 
			
		||||
        if isinstance(typ, QAPISchemaBuiltinType):
 | 
			
		||||
            return typ.name
 | 
			
		||||
        return self._name(typ.name)
 | 
			
		||||
 | 
			
		||||
    def _gen_json(self, name, mtype, obj):
 | 
			
		||||
        if mtype != 'command' and mtype != 'event' and mtype != 'builtin':
 | 
			
		||||
            name = self._name(name)
 | 
			
		||||
        obj['name'] = name
 | 
			
		||||
        obj['meta-type'] = mtype
 | 
			
		||||
        self._jsons.append(obj)
 | 
			
		||||
 | 
			
		||||
    def _gen_member(self, member):
 | 
			
		||||
        ret = {'name': member.name, 'type': self._use_type(member.type)}
 | 
			
		||||
        if member.optional:
 | 
			
		||||
            ret['default'] = None
 | 
			
		||||
        return ret
 | 
			
		||||
 | 
			
		||||
    def _gen_variants(self, tag_name, variants):
 | 
			
		||||
        return {'tag': tag_name,
 | 
			
		||||
                'variants': [self._gen_variant(v) for v in variants]}
 | 
			
		||||
 | 
			
		||||
    def _gen_variant(self, variant):
 | 
			
		||||
        return {'case': variant.name, 'type': self._use_type(variant.type)}
 | 
			
		||||
 | 
			
		||||
    def visit_builtin_type(self, name, info, json_type):
 | 
			
		||||
        self._gen_json(name, 'builtin', {'json-type': json_type})
 | 
			
		||||
 | 
			
		||||
    def visit_enum_type(self, name, info, values, prefix):
 | 
			
		||||
        self._gen_json(name, 'enum', {'values': values})
 | 
			
		||||
 | 
			
		||||
    def visit_array_type(self, name, info, element_type):
 | 
			
		||||
        self._gen_json(name, 'array',
 | 
			
		||||
                       {'element-type': self._use_type(element_type)})
 | 
			
		||||
 | 
			
		||||
    def visit_object_type_flat(self, name, info, members, variants):
 | 
			
		||||
        obj = {'members': [self._gen_member(m) for m in members]}
 | 
			
		||||
        if variants:
 | 
			
		||||
            obj.update(self._gen_variants(variants.tag_member.name,
 | 
			
		||||
                                          variants.variants))
 | 
			
		||||
        self._gen_json(name, 'object', obj)
 | 
			
		||||
 | 
			
		||||
    def visit_alternate_type(self, name, info, variants):
 | 
			
		||||
        self._gen_json(name, 'alternate',
 | 
			
		||||
                       {'members': [{'type': self._use_type(m.type)}
 | 
			
		||||
                                    for m in variants.variants]})
 | 
			
		||||
 | 
			
		||||
    def visit_command(self, name, info, arg_type, ret_type,
 | 
			
		||||
                      gen, success_response):
 | 
			
		||||
        arg_type = arg_type or self._schema.the_empty_object_type
 | 
			
		||||
        ret_type = ret_type or self._schema.the_empty_object_type
 | 
			
		||||
        self._gen_json(name, 'command',
 | 
			
		||||
                       {'arg-type': self._use_type(arg_type),
 | 
			
		||||
                        'ret-type': self._use_type(ret_type)})
 | 
			
		||||
 | 
			
		||||
    def visit_event(self, name, info, arg_type):
 | 
			
		||||
        arg_type = arg_type or self._schema.the_empty_object_type
 | 
			
		||||
        self._gen_json(name, 'event', {'arg-type': self._use_type(arg_type)})
 | 
			
		||||
 | 
			
		||||
# Debugging aid: unmask QAPI schema's type names
 | 
			
		||||
# We normally mask them, because they're not QMP wire ABI
 | 
			
		||||
opt_unmask = False
 | 
			
		||||
 | 
			
		||||
(input_file, output_dir, do_c, do_h, prefix, opts) = \
 | 
			
		||||
    parse_command_line("u", ["unmask-non-abi-names"])
 | 
			
		||||
 | 
			
		||||
for o, a in opts:
 | 
			
		||||
    if o in ("-u", "--unmask-non-abi-names"):
 | 
			
		||||
        opt_unmask = True
 | 
			
		||||
 | 
			
		||||
c_comment = '''
 | 
			
		||||
/*
 | 
			
		||||
 * QAPI/QMP schema introspection
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2015 Red Hat, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 | 
			
		||||
 * See the COPYING.LIB file in the top-level directory.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
'''
 | 
			
		||||
h_comment = '''
 | 
			
		||||
/*
 | 
			
		||||
 * QAPI/QMP schema introspection
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2015 Red Hat, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
 | 
			
		||||
 * See the COPYING.LIB file in the top-level directory.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
'''
 | 
			
		||||
 | 
			
		||||
(fdef, fdecl) = open_output(output_dir, do_c, do_h, prefix,
 | 
			
		||||
                            'qmp-introspect.c', 'qmp-introspect.h',
 | 
			
		||||
                            c_comment, h_comment)
 | 
			
		||||
 | 
			
		||||
fdef.write(mcgen('''
 | 
			
		||||
#include "%(prefix)sqmp-introspect.h"
 | 
			
		||||
 | 
			
		||||
''',
 | 
			
		||||
                 prefix=prefix))
 | 
			
		||||
 | 
			
		||||
schema = QAPISchema(input_file)
 | 
			
		||||
gen = QAPISchemaGenIntrospectVisitor(opt_unmask)
 | 
			
		||||
schema.visit(gen)
 | 
			
		||||
fdef.write(gen.defn)
 | 
			
		||||
fdecl.write(gen.decl)
 | 
			
		||||
 | 
			
		||||
close_output(fdef, fdecl)
 | 
			
		||||
@ -2,96 +2,81 @@
 | 
			
		||||
# QAPI types generator
 | 
			
		||||
#
 | 
			
		||||
# Copyright IBM, Corp. 2011
 | 
			
		||||
# Copyright (c) 2013-2015 Red Hat Inc.
 | 
			
		||||
#
 | 
			
		||||
# Authors:
 | 
			
		||||
#  Anthony Liguori <aliguori@us.ibm.com>
 | 
			
		||||
#  Markus Armbruster <armbru@redhat.com>
 | 
			
		||||
#
 | 
			
		||||
# This work is licensed under the terms of the GNU GPL, version 2.
 | 
			
		||||
# See the COPYING file in the top-level directory.
 | 
			
		||||
 | 
			
		||||
from ordereddict import OrderedDict
 | 
			
		||||
from qapi import *
 | 
			
		||||
 | 
			
		||||
def generate_fwd_builtin(name):
 | 
			
		||||
 | 
			
		||||
def gen_fwd_object_or_array(name):
 | 
			
		||||
    return mcgen('''
 | 
			
		||||
 | 
			
		||||
typedef struct %(name)sList {
 | 
			
		||||
    union {
 | 
			
		||||
        %(type)s value;
 | 
			
		||||
        uint64_t padding;
 | 
			
		||||
    };
 | 
			
		||||
    struct %(name)sList *next;
 | 
			
		||||
} %(name)sList;
 | 
			
		||||
typedef struct %(c_name)s %(c_name)s;
 | 
			
		||||
''',
 | 
			
		||||
                 type=c_type(name),
 | 
			
		||||
                 name=name)
 | 
			
		||||
                 c_name=c_name(name))
 | 
			
		||||
 | 
			
		||||
def generate_fwd_struct(name):
 | 
			
		||||
 | 
			
		||||
def gen_array(name, element_type):
 | 
			
		||||
    return mcgen('''
 | 
			
		||||
 | 
			
		||||
typedef struct %(name)s %(name)s;
 | 
			
		||||
 | 
			
		||||
typedef struct %(name)sList {
 | 
			
		||||
struct %(c_name)s {
 | 
			
		||||
    union {
 | 
			
		||||
        %(name)s *value;
 | 
			
		||||
        %(c_type)s value;
 | 
			
		||||
        uint64_t padding;
 | 
			
		||||
    };
 | 
			
		||||
    struct %(name)sList *next;
 | 
			
		||||
} %(name)sList;
 | 
			
		||||
    %(c_name)s *next;
 | 
			
		||||
};
 | 
			
		||||
''',
 | 
			
		||||
                 name=c_name(name))
 | 
			
		||||
                 c_name=c_name(name), c_type=element_type.c_type())
 | 
			
		||||
 | 
			
		||||
def generate_fwd_enum_struct(name):
 | 
			
		||||
    return mcgen('''
 | 
			
		||||
 | 
			
		||||
typedef struct %(name)sList {
 | 
			
		||||
    union {
 | 
			
		||||
        %(name)s value;
 | 
			
		||||
        uint64_t padding;
 | 
			
		||||
    };
 | 
			
		||||
    struct %(name)sList *next;
 | 
			
		||||
} %(name)sList;
 | 
			
		||||
''',
 | 
			
		||||
                 name=c_name(name))
 | 
			
		||||
 | 
			
		||||
def generate_struct_fields(members):
 | 
			
		||||
def gen_struct_field(name, typ, optional):
 | 
			
		||||
    ret = ''
 | 
			
		||||
 | 
			
		||||
    for argname, argentry, optional in parse_args(members):
 | 
			
		||||
        if optional:
 | 
			
		||||
            ret += mcgen('''
 | 
			
		||||
    if optional:
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
    bool has_%(c_name)s;
 | 
			
		||||
''',
 | 
			
		||||
                         c_name=c_name(argname))
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
                     c_name=c_name(name))
 | 
			
		||||
    ret += mcgen('''
 | 
			
		||||
    %(c_type)s %(c_name)s;
 | 
			
		||||
''',
 | 
			
		||||
                     c_type=c_type(argentry), c_name=c_name(argname))
 | 
			
		||||
 | 
			
		||||
                 c_type=typ.c_type(), c_name=c_name(name))
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
def generate_struct(expr):
 | 
			
		||||
 | 
			
		||||
    structname = expr.get('struct', "")
 | 
			
		||||
    members = expr['data']
 | 
			
		||||
    base = expr.get('base')
 | 
			
		||||
def gen_struct_fields(members):
 | 
			
		||||
    ret = ''
 | 
			
		||||
 | 
			
		||||
    for memb in members:
 | 
			
		||||
        ret += gen_struct_field(memb.name, memb.type, memb.optional)
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def gen_struct(name, base, members):
 | 
			
		||||
    ret = mcgen('''
 | 
			
		||||
 | 
			
		||||
struct %(name)s {
 | 
			
		||||
struct %(c_name)s {
 | 
			
		||||
''',
 | 
			
		||||
          name=c_name(structname))
 | 
			
		||||
                c_name=c_name(name))
 | 
			
		||||
 | 
			
		||||
    if base:
 | 
			
		||||
        ret += generate_struct_fields({'base': base})
 | 
			
		||||
        ret += gen_struct_field('base', base, False)
 | 
			
		||||
 | 
			
		||||
    ret += generate_struct_fields(members)
 | 
			
		||||
    ret += gen_struct_fields(members)
 | 
			
		||||
 | 
			
		||||
    # Make sure that all structs have at least one field; this avoids
 | 
			
		||||
    # potential issues with attempting to malloc space for zero-length structs
 | 
			
		||||
    # in C, and also incompatibility with C++ (where an empty struct is size 1).
 | 
			
		||||
    # potential issues with attempting to malloc space for zero-length
 | 
			
		||||
    # structs in C, and also incompatibility with C++ (where an empty
 | 
			
		||||
    # struct is size 1).
 | 
			
		||||
    if not base and not members:
 | 
			
		||||
            ret += mcgen('''
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
    char qapi_dummy_field_for_empty_struct;
 | 
			
		||||
''')
 | 
			
		||||
 | 
			
		||||
@ -101,81 +86,32 @@ struct %(name)s {
 | 
			
		||||
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
def generate_enum_lookup(name, values, prefix=None):
 | 
			
		||||
 | 
			
		||||
def gen_alternate_qtypes_decl(name):
 | 
			
		||||
    return mcgen('''
 | 
			
		||||
 | 
			
		||||
extern const int %(c_name)s_qtypes[];
 | 
			
		||||
''',
 | 
			
		||||
                 c_name=c_name(name))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def gen_alternate_qtypes(name, variants):
 | 
			
		||||
    ret = mcgen('''
 | 
			
		||||
 | 
			
		||||
const char *const %(name)s_lookup[] = {
 | 
			
		||||
const int %(c_name)s_qtypes[QTYPE_MAX] = {
 | 
			
		||||
''',
 | 
			
		||||
                name=c_name(name))
 | 
			
		||||
    for value in values:
 | 
			
		||||
        index = c_enum_const(name, value, prefix)
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
    [%(index)s] = "%(value)s",
 | 
			
		||||
''',
 | 
			
		||||
                     index = index, value = value)
 | 
			
		||||
                c_name=c_name(name))
 | 
			
		||||
 | 
			
		||||
    max_index = c_enum_const(name, 'MAX', prefix)
 | 
			
		||||
    ret += mcgen('''
 | 
			
		||||
    [%(max_index)s] = NULL,
 | 
			
		||||
};
 | 
			
		||||
''',
 | 
			
		||||
        max_index=max_index)
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
def generate_enum(name, values, prefix=None):
 | 
			
		||||
    name = c_name(name)
 | 
			
		||||
    lookup_decl = mcgen('''
 | 
			
		||||
 | 
			
		||||
extern const char *const %(name)s_lookup[];
 | 
			
		||||
''',
 | 
			
		||||
                name=name)
 | 
			
		||||
 | 
			
		||||
    enum_decl = mcgen('''
 | 
			
		||||
 | 
			
		||||
typedef enum %(name)s {
 | 
			
		||||
''',
 | 
			
		||||
                name=name)
 | 
			
		||||
 | 
			
		||||
    # append automatically generated _MAX value
 | 
			
		||||
    enum_values = values + [ 'MAX' ]
 | 
			
		||||
 | 
			
		||||
    i = 0
 | 
			
		||||
    for value in enum_values:
 | 
			
		||||
        enum_full_value = c_enum_const(name, value, prefix)
 | 
			
		||||
        enum_decl += mcgen('''
 | 
			
		||||
    %(enum_full_value)s = %(i)d,
 | 
			
		||||
''',
 | 
			
		||||
                     enum_full_value = enum_full_value,
 | 
			
		||||
                     i=i)
 | 
			
		||||
        i += 1
 | 
			
		||||
 | 
			
		||||
    enum_decl += mcgen('''
 | 
			
		||||
} %(name)s;
 | 
			
		||||
''',
 | 
			
		||||
                 name=name)
 | 
			
		||||
 | 
			
		||||
    return enum_decl + lookup_decl
 | 
			
		||||
 | 
			
		||||
def generate_alternate_qtypes(expr):
 | 
			
		||||
 | 
			
		||||
    name = expr['alternate']
 | 
			
		||||
    members = expr['data']
 | 
			
		||||
 | 
			
		||||
    ret = mcgen('''
 | 
			
		||||
 | 
			
		||||
const int %(name)s_qtypes[QTYPE_MAX] = {
 | 
			
		||||
''',
 | 
			
		||||
                name=c_name(name))
 | 
			
		||||
 | 
			
		||||
    for key in members:
 | 
			
		||||
        qtype = find_alternate_member_qtype(members[key])
 | 
			
		||||
        assert qtype, "Invalid alternate member"
 | 
			
		||||
    for var in variants.variants:
 | 
			
		||||
        qtype = var.type.alternate_qtype()
 | 
			
		||||
        assert qtype
 | 
			
		||||
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
    [%(qtype)s] = %(enum_const)s,
 | 
			
		||||
''',
 | 
			
		||||
                     qtype = qtype,
 | 
			
		||||
                     enum_const = c_enum_const(name + 'Kind', key))
 | 
			
		||||
                     qtype=qtype,
 | 
			
		||||
                     enum_const=c_enum_const(variants.tag_member.type.name,
 | 
			
		||||
                                             var.name))
 | 
			
		||||
 | 
			
		||||
    ret += mcgen('''
 | 
			
		||||
};
 | 
			
		||||
@ -183,41 +119,26 @@ const int %(name)s_qtypes[QTYPE_MAX] = {
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def generate_union(expr, meta):
 | 
			
		||||
 | 
			
		||||
    name = c_name(expr[meta])
 | 
			
		||||
    typeinfo = expr['data']
 | 
			
		||||
 | 
			
		||||
    base = expr.get('base')
 | 
			
		||||
    discriminator = expr.get('discriminator')
 | 
			
		||||
 | 
			
		||||
    enum_define = discriminator_find_enum_define(expr)
 | 
			
		||||
    if enum_define:
 | 
			
		||||
        discriminator_type_name = enum_define['enum_name']
 | 
			
		||||
    else:
 | 
			
		||||
        discriminator_type_name = '%sKind' % (name)
 | 
			
		||||
 | 
			
		||||
def gen_union(name, base, variants):
 | 
			
		||||
    ret = mcgen('''
 | 
			
		||||
 | 
			
		||||
struct %(name)s {
 | 
			
		||||
struct %(c_name)s {
 | 
			
		||||
''',
 | 
			
		||||
                name=name)
 | 
			
		||||
                c_name=c_name(name))
 | 
			
		||||
    if base:
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
    /* Members inherited from %(c_name)s: */
 | 
			
		||||
''',
 | 
			
		||||
                     c_name=c_name(base))
 | 
			
		||||
        base_fields = find_struct(base)['data']
 | 
			
		||||
        ret += generate_struct_fields(base_fields)
 | 
			
		||||
                     c_name=c_name(base.name))
 | 
			
		||||
        ret += gen_struct_fields(base.members)
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
    /* Own members: */
 | 
			
		||||
''')
 | 
			
		||||
    else:
 | 
			
		||||
        assert not discriminator
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
    %(discriminator_type_name)s kind;
 | 
			
		||||
    %(c_type)s kind;
 | 
			
		||||
''',
 | 
			
		||||
                     discriminator_type_name=c_name(discriminator_type_name))
 | 
			
		||||
                     c_type=c_name(variants.tag_member.type.name))
 | 
			
		||||
 | 
			
		||||
    # FIXME: What purpose does data serve, besides preventing a union that
 | 
			
		||||
    # has a branch named 'data'? We use it in qapi-visit.py to decide
 | 
			
		||||
@ -231,39 +152,41 @@ struct %(name)s {
 | 
			
		||||
    union { /* union tag is @%(c_name)s */
 | 
			
		||||
        void *data;
 | 
			
		||||
''',
 | 
			
		||||
                 c_name=c_name(discriminator or 'kind'))
 | 
			
		||||
                 # TODO ugly special case for simple union
 | 
			
		||||
                 # Use same tag name in C as on the wire to get rid of
 | 
			
		||||
                 # it, then: c_name=c_name(variants.tag_member.name)
 | 
			
		||||
                 c_name=c_name(variants.tag_name or 'kind'))
 | 
			
		||||
 | 
			
		||||
    for key in typeinfo:
 | 
			
		||||
    for var in variants.variants:
 | 
			
		||||
        # Ugly special case for simple union TODO get rid of it
 | 
			
		||||
        typ = var.simple_union_type() or var.type
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
        %(c_type)s %(c_name)s;
 | 
			
		||||
''',
 | 
			
		||||
                     c_type=c_type(typeinfo[key]),
 | 
			
		||||
                     c_name=c_name(key))
 | 
			
		||||
                     c_type=typ.c_type(),
 | 
			
		||||
                     c_name=c_name(var.name))
 | 
			
		||||
 | 
			
		||||
    ret += mcgen('''
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
''')
 | 
			
		||||
    if meta == 'alternate':
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
extern const int %(name)s_qtypes[];
 | 
			
		||||
''',
 | 
			
		||||
            name=name)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
def generate_type_cleanup_decl(name):
 | 
			
		||||
 | 
			
		||||
def gen_type_cleanup_decl(name):
 | 
			
		||||
    ret = mcgen('''
 | 
			
		||||
void qapi_free_%(name)s(%(c_type)s obj);
 | 
			
		||||
 | 
			
		||||
void qapi_free_%(c_name)s(%(c_name)s *obj);
 | 
			
		||||
''',
 | 
			
		||||
                c_type=c_type(name), name=c_name(name))
 | 
			
		||||
                c_name=c_name(name))
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
def generate_type_cleanup(name):
 | 
			
		||||
 | 
			
		||||
def gen_type_cleanup(name):
 | 
			
		||||
    ret = mcgen('''
 | 
			
		||||
 | 
			
		||||
void qapi_free_%(name)s(%(c_type)s obj)
 | 
			
		||||
void qapi_free_%(c_name)s(%(c_name)s *obj)
 | 
			
		||||
{
 | 
			
		||||
    QapiDeallocVisitor *md;
 | 
			
		||||
    Visitor *v;
 | 
			
		||||
@ -274,13 +197,83 @@ void qapi_free_%(name)s(%(c_type)s obj)
 | 
			
		||||
 | 
			
		||||
    md = qapi_dealloc_visitor_new();
 | 
			
		||||
    v = qapi_dealloc_get_visitor(md);
 | 
			
		||||
    visit_type_%(name)s(v, &obj, NULL, NULL);
 | 
			
		||||
    visit_type_%(c_name)s(v, &obj, NULL, NULL);
 | 
			
		||||
    qapi_dealloc_visitor_cleanup(md);
 | 
			
		||||
}
 | 
			
		||||
''',
 | 
			
		||||
                c_type=c_type(name), name=c_name(name))
 | 
			
		||||
                c_name=c_name(name))
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class QAPISchemaGenTypeVisitor(QAPISchemaVisitor):
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        self.decl = None
 | 
			
		||||
        self.defn = None
 | 
			
		||||
        self._fwdecl = None
 | 
			
		||||
        self._fwdefn = None
 | 
			
		||||
        self._btin = None
 | 
			
		||||
 | 
			
		||||
    def visit_begin(self, schema):
 | 
			
		||||
        self.decl = ''
 | 
			
		||||
        self.defn = ''
 | 
			
		||||
        self._fwdecl = ''
 | 
			
		||||
        self._fwdefn = ''
 | 
			
		||||
        self._btin = guardstart('QAPI_TYPES_BUILTIN')
 | 
			
		||||
 | 
			
		||||
    def visit_end(self):
 | 
			
		||||
        self.decl = self._fwdecl + self.decl
 | 
			
		||||
        self._fwdecl = None
 | 
			
		||||
        self.defn = self._fwdefn + self.defn
 | 
			
		||||
        self._fwdefn = None
 | 
			
		||||
        # To avoid header dependency hell, we always generate
 | 
			
		||||
        # declarations for built-in types in our header files and
 | 
			
		||||
        # simply guard them.  See also do_builtins (command line
 | 
			
		||||
        # option -b).
 | 
			
		||||
        self._btin += guardend('QAPI_TYPES_BUILTIN')
 | 
			
		||||
        self.decl = self._btin + self.decl
 | 
			
		||||
        self._btin = None
 | 
			
		||||
 | 
			
		||||
    def _gen_type_cleanup(self, name):
 | 
			
		||||
        self.decl += gen_type_cleanup_decl(name)
 | 
			
		||||
        self.defn += gen_type_cleanup(name)
 | 
			
		||||
 | 
			
		||||
    def visit_enum_type(self, name, info, values, prefix):
 | 
			
		||||
        self._fwdecl += gen_enum(name, values, prefix)
 | 
			
		||||
        self._fwdefn += gen_enum_lookup(name, values, prefix)
 | 
			
		||||
 | 
			
		||||
    def visit_array_type(self, name, info, element_type):
 | 
			
		||||
        if isinstance(element_type, QAPISchemaBuiltinType):
 | 
			
		||||
            self._btin += gen_fwd_object_or_array(name)
 | 
			
		||||
            self._btin += gen_array(name, element_type)
 | 
			
		||||
            self._btin += gen_type_cleanup_decl(name)
 | 
			
		||||
            if do_builtins:
 | 
			
		||||
                self.defn += gen_type_cleanup(name)
 | 
			
		||||
        else:
 | 
			
		||||
            self._fwdecl += gen_fwd_object_or_array(name)
 | 
			
		||||
            self.decl += gen_array(name, element_type)
 | 
			
		||||
            self._gen_type_cleanup(name)
 | 
			
		||||
 | 
			
		||||
    def visit_object_type(self, name, info, base, members, variants):
 | 
			
		||||
        if info:
 | 
			
		||||
            self._fwdecl += gen_fwd_object_or_array(name)
 | 
			
		||||
            if variants:
 | 
			
		||||
                assert not members      # not implemented
 | 
			
		||||
                self.decl += gen_union(name, base, variants)
 | 
			
		||||
            else:
 | 
			
		||||
                self.decl += gen_struct(name, base, members)
 | 
			
		||||
            self._gen_type_cleanup(name)
 | 
			
		||||
 | 
			
		||||
    def visit_alternate_type(self, name, info, variants):
 | 
			
		||||
        self._fwdecl += gen_fwd_object_or_array(name)
 | 
			
		||||
        self._fwdefn += gen_alternate_qtypes(name, variants)
 | 
			
		||||
        self.decl += gen_union(name, None, variants)
 | 
			
		||||
        self.decl += gen_alternate_qtypes_decl(name)
 | 
			
		||||
        self._gen_type_cleanup(name)
 | 
			
		||||
 | 
			
		||||
# If you link code generated from multiple schemata, you want only one
 | 
			
		||||
# instance of the code for built-in types.  Generate it only when
 | 
			
		||||
# do_builtins, enabled by command line option -b.  See also
 | 
			
		||||
# QAPISchemaGenTypeVisitor.visit_end().
 | 
			
		||||
do_builtins = False
 | 
			
		||||
 | 
			
		||||
(input_file, output_dir, do_c, do_h, prefix, opts) = \
 | 
			
		||||
@ -334,81 +327,13 @@ fdef.write(mcgen('''
 | 
			
		||||
fdecl.write(mcgen('''
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include "qapi/qmp/qobject.h"
 | 
			
		||||
'''))
 | 
			
		||||
 | 
			
		||||
exprs = parse_schema(input_file)
 | 
			
		||||
 | 
			
		||||
fdecl.write(guardstart("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
 | 
			
		||||
for typename in builtin_types.keys():
 | 
			
		||||
    fdecl.write(generate_fwd_builtin(typename))
 | 
			
		||||
fdecl.write(guardend("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
 | 
			
		||||
 | 
			
		||||
for expr in exprs:
 | 
			
		||||
    ret = ""
 | 
			
		||||
    if expr.has_key('struct'):
 | 
			
		||||
        ret += generate_fwd_struct(expr['struct'])
 | 
			
		||||
    elif expr.has_key('enum'):
 | 
			
		||||
        ret += generate_enum(expr['enum'], expr['data'],
 | 
			
		||||
                             expr.get('prefix'))
 | 
			
		||||
        ret += generate_fwd_enum_struct(expr['enum'])
 | 
			
		||||
        fdef.write(generate_enum_lookup(expr['enum'], expr['data'],
 | 
			
		||||
                                        expr.get('prefix')))
 | 
			
		||||
    elif expr.has_key('union'):
 | 
			
		||||
        ret += generate_fwd_struct(expr['union'])
 | 
			
		||||
        enum_define = discriminator_find_enum_define(expr)
 | 
			
		||||
        if not enum_define:
 | 
			
		||||
            ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
 | 
			
		||||
            fdef.write(generate_enum_lookup('%sKind' % expr['union'],
 | 
			
		||||
                                            expr['data'].keys()))
 | 
			
		||||
    elif expr.has_key('alternate'):
 | 
			
		||||
        ret += generate_fwd_struct(expr['alternate'])
 | 
			
		||||
        ret += generate_enum('%sKind' % expr['alternate'], expr['data'].keys())
 | 
			
		||||
        fdef.write(generate_enum_lookup('%sKind' % expr['alternate'],
 | 
			
		||||
                                        expr['data'].keys()))
 | 
			
		||||
        fdef.write(generate_alternate_qtypes(expr))
 | 
			
		||||
    else:
 | 
			
		||||
        continue
 | 
			
		||||
    fdecl.write(ret)
 | 
			
		||||
 | 
			
		||||
# to avoid header dependency hell, we always generate declarations
 | 
			
		||||
# for built-in types in our header files and simply guard them
 | 
			
		||||
fdecl.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
 | 
			
		||||
for typename in builtin_types.keys():
 | 
			
		||||
    fdecl.write(generate_type_cleanup_decl(typename + "List"))
 | 
			
		||||
fdecl.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
 | 
			
		||||
 | 
			
		||||
# ...this doesn't work for cases where we link in multiple objects that
 | 
			
		||||
# have the functions defined, so we use -b option to provide control
 | 
			
		||||
# over these cases
 | 
			
		||||
if do_builtins:
 | 
			
		||||
    for typename in builtin_types.keys():
 | 
			
		||||
        fdef.write(generate_type_cleanup(typename + "List"))
 | 
			
		||||
 | 
			
		||||
for expr in exprs:
 | 
			
		||||
    ret = ""
 | 
			
		||||
    if expr.has_key('struct'):
 | 
			
		||||
        ret += generate_struct(expr) + "\n"
 | 
			
		||||
        ret += generate_type_cleanup_decl(expr['struct'] + "List")
 | 
			
		||||
        fdef.write(generate_type_cleanup(expr['struct'] + "List"))
 | 
			
		||||
        ret += generate_type_cleanup_decl(expr['struct'])
 | 
			
		||||
        fdef.write(generate_type_cleanup(expr['struct']))
 | 
			
		||||
    elif expr.has_key('union'):
 | 
			
		||||
        ret += generate_union(expr, 'union') + "\n"
 | 
			
		||||
        ret += generate_type_cleanup_decl(expr['union'] + "List")
 | 
			
		||||
        fdef.write(generate_type_cleanup(expr['union'] + "List"))
 | 
			
		||||
        ret += generate_type_cleanup_decl(expr['union'])
 | 
			
		||||
        fdef.write(generate_type_cleanup(expr['union']))
 | 
			
		||||
    elif expr.has_key('alternate'):
 | 
			
		||||
        ret += generate_union(expr, 'alternate') + "\n"
 | 
			
		||||
        ret += generate_type_cleanup_decl(expr['alternate'] + "List")
 | 
			
		||||
        fdef.write(generate_type_cleanup(expr['alternate'] + "List"))
 | 
			
		||||
        ret += generate_type_cleanup_decl(expr['alternate'])
 | 
			
		||||
        fdef.write(generate_type_cleanup(expr['alternate']))
 | 
			
		||||
    elif expr.has_key('enum'):
 | 
			
		||||
        ret += "\n" + generate_type_cleanup_decl(expr['enum'] + "List")
 | 
			
		||||
        fdef.write(generate_type_cleanup(expr['enum'] + "List"))
 | 
			
		||||
    else:
 | 
			
		||||
        continue
 | 
			
		||||
    fdecl.write(ret)
 | 
			
		||||
schema = QAPISchema(input_file)
 | 
			
		||||
gen = QAPISchemaGenTypeVisitor()
 | 
			
		||||
schema.visit(gen)
 | 
			
		||||
fdef.write(gen.defn)
 | 
			
		||||
fdecl.write(gen.decl)
 | 
			
		||||
 | 
			
		||||
close_output(fdef, fdecl)
 | 
			
		||||
 | 
			
		||||
@ -12,25 +12,36 @@
 | 
			
		||||
# This work is licensed under the terms of the GNU GPL, version 2.
 | 
			
		||||
# See the COPYING file in the top-level directory.
 | 
			
		||||
 | 
			
		||||
from ordereddict import OrderedDict
 | 
			
		||||
from qapi import *
 | 
			
		||||
import re
 | 
			
		||||
 | 
			
		||||
implicit_structs_seen = set()
 | 
			
		||||
struct_fields_seen = set()
 | 
			
		||||
 | 
			
		||||
def generate_visit_implicit_struct(type):
 | 
			
		||||
    if type in implicit_structs_seen:
 | 
			
		||||
 | 
			
		||||
def gen_visit_decl(name, scalar=False):
 | 
			
		||||
    c_type = c_name(name) + ' *'
 | 
			
		||||
    if not scalar:
 | 
			
		||||
        c_type += '*'
 | 
			
		||||
    return mcgen('''
 | 
			
		||||
void visit_type_%(c_name)s(Visitor *m, %(c_type)sobj, const char *name, Error **errp);
 | 
			
		||||
''',
 | 
			
		||||
                 c_name=c_name(name), c_type=c_type)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def gen_visit_implicit_struct(typ):
 | 
			
		||||
    if typ in implicit_structs_seen:
 | 
			
		||||
        return ''
 | 
			
		||||
    implicit_structs_seen.add(type)
 | 
			
		||||
    implicit_structs_seen.add(typ)
 | 
			
		||||
 | 
			
		||||
    ret = ''
 | 
			
		||||
    if type not in struct_fields_seen:
 | 
			
		||||
    if typ.name not in struct_fields_seen:
 | 
			
		||||
        # Need a forward declaration
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
 | 
			
		||||
static void visit_type_%(c_type)s_fields(Visitor *m, %(c_type)s **obj, Error **errp);
 | 
			
		||||
''',
 | 
			
		||||
                     c_type=type_name(type))
 | 
			
		||||
                     c_type=typ.c_name())
 | 
			
		||||
 | 
			
		||||
    ret += mcgen('''
 | 
			
		||||
 | 
			
		||||
@ -46,52 +57,53 @@ static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error *
 | 
			
		||||
    error_propagate(errp, err);
 | 
			
		||||
}
 | 
			
		||||
''',
 | 
			
		||||
                 c_type=type_name(type))
 | 
			
		||||
                 c_type=typ.c_name())
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
def generate_visit_struct_fields(name, members, base = None):
 | 
			
		||||
 | 
			
		||||
def gen_visit_struct_fields(name, base, members):
 | 
			
		||||
    struct_fields_seen.add(name)
 | 
			
		||||
 | 
			
		||||
    ret = ''
 | 
			
		||||
 | 
			
		||||
    if base:
 | 
			
		||||
        ret += generate_visit_implicit_struct(base)
 | 
			
		||||
        ret += gen_visit_implicit_struct(base)
 | 
			
		||||
 | 
			
		||||
    ret += mcgen('''
 | 
			
		||||
 | 
			
		||||
static void visit_type_%(name)s_fields(Visitor *m, %(name)s **obj, Error **errp)
 | 
			
		||||
static void visit_type_%(c_name)s_fields(Visitor *m, %(c_name)s **obj, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    Error *err = NULL;
 | 
			
		||||
 | 
			
		||||
''',
 | 
			
		||||
                 name=c_name(name))
 | 
			
		||||
                 c_name=c_name(name))
 | 
			
		||||
    push_indent()
 | 
			
		||||
 | 
			
		||||
    if base:
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
visit_type_implicit_%(type)s(m, &(*obj)->%(c_name)s, &err);
 | 
			
		||||
visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);
 | 
			
		||||
if (err) {
 | 
			
		||||
    goto out;
 | 
			
		||||
}
 | 
			
		||||
''',
 | 
			
		||||
                     type=type_name(base), c_name=c_name('base'))
 | 
			
		||||
                     c_type=base.c_name(), c_name=c_name('base'))
 | 
			
		||||
 | 
			
		||||
    for argname, argentry, optional in parse_args(members):
 | 
			
		||||
        if optional:
 | 
			
		||||
    for memb in members:
 | 
			
		||||
        if memb.optional:
 | 
			
		||||
            ret += mcgen('''
 | 
			
		||||
visit_optional(m, &(*obj)->has_%(c_name)s, "%(name)s", &err);
 | 
			
		||||
if (!err && (*obj)->has_%(c_name)s) {
 | 
			
		||||
''',
 | 
			
		||||
                         c_name=c_name(argname), name=argname)
 | 
			
		||||
                         c_name=c_name(memb.name), name=memb.name)
 | 
			
		||||
            push_indent()
 | 
			
		||||
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
visit_type_%(type)s(m, &(*obj)->%(c_name)s, "%(name)s", &err);
 | 
			
		||||
visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "%(name)s", &err);
 | 
			
		||||
''',
 | 
			
		||||
                     type=type_name(argentry), c_name=c_name(argname),
 | 
			
		||||
                     name=argname)
 | 
			
		||||
                     c_type=memb.type.c_name(), c_name=c_name(memb.name),
 | 
			
		||||
                     name=memb.name)
 | 
			
		||||
 | 
			
		||||
        if optional:
 | 
			
		||||
        if memb.optional:
 | 
			
		||||
            pop_indent()
 | 
			
		||||
            ret += mcgen('''
 | 
			
		||||
}
 | 
			
		||||
@ -103,7 +115,7 @@ if (err) {
 | 
			
		||||
''')
 | 
			
		||||
 | 
			
		||||
    pop_indent()
 | 
			
		||||
    if re.search('^ *goto out\\;', ret, re.MULTILINE):
 | 
			
		||||
    if re.search('^ *goto out;', ret, re.MULTILINE):
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
@ -115,12 +127,17 @@ out:
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def generate_visit_struct_body(name):
 | 
			
		||||
def gen_visit_struct(name, base, members):
 | 
			
		||||
    ret = gen_visit_struct_fields(name, base, members)
 | 
			
		||||
 | 
			
		||||
    # FIXME: if *obj is NULL on entry, and visit_start_struct() assigns to
 | 
			
		||||
    # *obj, but then visit_type_FOO_fields() fails, we should clean up *obj
 | 
			
		||||
    # rather than leaving it non-NULL. As currently written, the caller must
 | 
			
		||||
    # call qapi_free_FOO() to avoid a memory leak of the partial FOO.
 | 
			
		||||
    ret = mcgen('''
 | 
			
		||||
    ret += mcgen('''
 | 
			
		||||
 | 
			
		||||
void visit_type_%(c_name)s(Visitor *m, %(c_name)s **obj, const char *name, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    Error *err = NULL;
 | 
			
		||||
 | 
			
		||||
    visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(c_name)s), &err);
 | 
			
		||||
@ -131,37 +148,17 @@ def generate_visit_struct_body(name):
 | 
			
		||||
        visit_end_struct(m, &err);
 | 
			
		||||
    }
 | 
			
		||||
    error_propagate(errp, err);
 | 
			
		||||
''',
 | 
			
		||||
                name=name, c_name=c_name(name))
 | 
			
		||||
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
def generate_visit_struct(expr):
 | 
			
		||||
 | 
			
		||||
    name = expr['struct']
 | 
			
		||||
    members = expr['data']
 | 
			
		||||
    base = expr.get('base')
 | 
			
		||||
 | 
			
		||||
    ret = generate_visit_struct_fields(name, members, base)
 | 
			
		||||
 | 
			
		||||
    ret += mcgen('''
 | 
			
		||||
 | 
			
		||||
void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
''',
 | 
			
		||||
                 name=c_name(name))
 | 
			
		||||
 | 
			
		||||
    ret += generate_visit_struct_body(name)
 | 
			
		||||
 | 
			
		||||
    ret += mcgen('''
 | 
			
		||||
}
 | 
			
		||||
''')
 | 
			
		||||
''',
 | 
			
		||||
                 name=name, c_name=c_name(name))
 | 
			
		||||
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
def generate_visit_list(name):
 | 
			
		||||
 | 
			
		||||
def gen_visit_list(name, element_type):
 | 
			
		||||
    return mcgen('''
 | 
			
		||||
 | 
			
		||||
void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp)
 | 
			
		||||
void visit_type_%(c_name)s(Visitor *m, %(c_name)s **obj, const char *name, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    Error *err = NULL;
 | 
			
		||||
    GenericList *i, **prev;
 | 
			
		||||
@ -174,8 +171,8 @@ void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, E
 | 
			
		||||
    for (prev = (GenericList **)obj;
 | 
			
		||||
         !err && (i = visit_next_list(m, prev, &err)) != NULL;
 | 
			
		||||
         prev = &i) {
 | 
			
		||||
        %(name)sList *native_i = (%(name)sList *)i;
 | 
			
		||||
        visit_type_%(name)s(m, &native_i->value, NULL, &err);
 | 
			
		||||
        %(c_name)s *native_i = (%(c_name)s *)i;
 | 
			
		||||
        visit_type_%(c_elt_type)s(m, &native_i->value, NULL, &err);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    error_propagate(errp, err);
 | 
			
		||||
@ -185,9 +182,10 @@ out:
 | 
			
		||||
    error_propagate(errp, err);
 | 
			
		||||
}
 | 
			
		||||
''',
 | 
			
		||||
                name=type_name(name))
 | 
			
		||||
                 c_name=c_name(name), c_elt_type=element_type.c_name())
 | 
			
		||||
 | 
			
		||||
def generate_visit_enum(name):
 | 
			
		||||
 | 
			
		||||
def gen_visit_enum(name):
 | 
			
		||||
    return mcgen('''
 | 
			
		||||
 | 
			
		||||
void visit_type_%(c_name)s(Visitor *m, %(c_name)s *obj, const char *name, Error **errp)
 | 
			
		||||
@ -197,44 +195,36 @@ void visit_type_%(c_name)s(Visitor *m, %(c_name)s *obj, const char *name, Error
 | 
			
		||||
''',
 | 
			
		||||
                 c_name=c_name(name), name=name)
 | 
			
		||||
 | 
			
		||||
def generate_visit_alternate(name, members):
 | 
			
		||||
 | 
			
		||||
def gen_visit_alternate(name, variants):
 | 
			
		||||
    ret = mcgen('''
 | 
			
		||||
 | 
			
		||||
void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
 | 
			
		||||
void visit_type_%(c_name)s(Visitor *m, %(c_name)s **obj, const char *name, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    Error *err = NULL;
 | 
			
		||||
 | 
			
		||||
    visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err);
 | 
			
		||||
    visit_start_implicit_struct(m, (void**) obj, sizeof(%(c_name)s), &err);
 | 
			
		||||
    if (err) {
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
    visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err);
 | 
			
		||||
    visit_get_next_type(m, (int*) &(*obj)->kind, %(c_name)s_qtypes, name, &err);
 | 
			
		||||
    if (err) {
 | 
			
		||||
        goto out_end;
 | 
			
		||||
    }
 | 
			
		||||
    switch ((*obj)->kind) {
 | 
			
		||||
''',
 | 
			
		||||
                name=c_name(name))
 | 
			
		||||
                c_name=c_name(name))
 | 
			
		||||
 | 
			
		||||
    # For alternate, always use the default enum type automatically generated
 | 
			
		||||
    # as name + 'Kind'
 | 
			
		||||
    disc_type = c_name(name) + 'Kind'
 | 
			
		||||
 | 
			
		||||
    for key in members:
 | 
			
		||||
        assert (members[key] in builtin_types.keys()
 | 
			
		||||
            or find_struct(members[key])
 | 
			
		||||
            or find_union(members[key])
 | 
			
		||||
            or find_enum(members[key])), "Invalid alternate member"
 | 
			
		||||
 | 
			
		||||
        enum_full_value = c_enum_const(disc_type, key)
 | 
			
		||||
    for var in variants.variants:
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
    case %(enum_full_value)s:
 | 
			
		||||
    case %(case)s:
 | 
			
		||||
        visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err);
 | 
			
		||||
        break;
 | 
			
		||||
''',
 | 
			
		||||
                enum_full_value = enum_full_value,
 | 
			
		||||
                c_type = type_name(members[key]),
 | 
			
		||||
                c_name = c_name(key))
 | 
			
		||||
                     case=c_enum_const(variants.tag_member.type.name,
 | 
			
		||||
                                       var.name),
 | 
			
		||||
                     c_type=var.type.c_name(),
 | 
			
		||||
                     c_name=c_name(var.name))
 | 
			
		||||
 | 
			
		||||
    ret += mcgen('''
 | 
			
		||||
    default:
 | 
			
		||||
@ -252,34 +242,17 @@ out:
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def generate_visit_union(expr):
 | 
			
		||||
 | 
			
		||||
    name = expr['union']
 | 
			
		||||
    members = expr['data']
 | 
			
		||||
 | 
			
		||||
    base = expr.get('base')
 | 
			
		||||
    discriminator = expr.get('discriminator')
 | 
			
		||||
 | 
			
		||||
    enum_define = discriminator_find_enum_define(expr)
 | 
			
		||||
    if enum_define:
 | 
			
		||||
        # Use the enum type as discriminator
 | 
			
		||||
        ret = ""
 | 
			
		||||
        disc_type = c_name(enum_define['enum_name'])
 | 
			
		||||
    else:
 | 
			
		||||
        # There will always be a discriminator in the C switch code, by default
 | 
			
		||||
        # it is an enum type generated silently
 | 
			
		||||
        ret = generate_visit_enum(name + 'Kind')
 | 
			
		||||
        disc_type = c_name(name) + 'Kind'
 | 
			
		||||
def gen_visit_union(name, base, variants):
 | 
			
		||||
    ret = ''
 | 
			
		||||
 | 
			
		||||
    if base:
 | 
			
		||||
        assert discriminator
 | 
			
		||||
        base_fields = find_struct(base)['data'].copy()
 | 
			
		||||
        del base_fields[discriminator]
 | 
			
		||||
        ret += generate_visit_struct_fields(name, base_fields)
 | 
			
		||||
        members = [m for m in base.members if m != variants.tag_member]
 | 
			
		||||
        ret += gen_visit_struct_fields(name, None, members)
 | 
			
		||||
 | 
			
		||||
    if discriminator:
 | 
			
		||||
        for key in members:
 | 
			
		||||
            ret += generate_visit_implicit_struct(members[key])
 | 
			
		||||
    for var in variants.variants:
 | 
			
		||||
        # Ugly special case for simple union TODO get rid of it
 | 
			
		||||
        if not var.simple_union_type():
 | 
			
		||||
            ret += gen_visit_implicit_struct(var.type)
 | 
			
		||||
 | 
			
		||||
    ret += mcgen('''
 | 
			
		||||
 | 
			
		||||
@ -297,48 +270,57 @@ void visit_type_%(c_name)s(Visitor *m, %(c_name)s **obj, const char *name, Error
 | 
			
		||||
 | 
			
		||||
    if base:
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
        visit_type_%(name)s_fields(m, obj, &err);
 | 
			
		||||
        visit_type_%(c_name)s_fields(m, obj, &err);
 | 
			
		||||
        if (err) {
 | 
			
		||||
            goto out_obj;
 | 
			
		||||
        }
 | 
			
		||||
''',
 | 
			
		||||
                     name=c_name(name))
 | 
			
		||||
                     c_name=c_name(name))
 | 
			
		||||
 | 
			
		||||
    if not discriminator:
 | 
			
		||||
        tag = 'kind'
 | 
			
		||||
        disc_key = "type"
 | 
			
		||||
    else:
 | 
			
		||||
        tag = discriminator
 | 
			
		||||
        disc_key = discriminator
 | 
			
		||||
    tag_key = variants.tag_member.name
 | 
			
		||||
    if not variants.tag_name:
 | 
			
		||||
        # we pointlessly use a different key for simple unions
 | 
			
		||||
        tag_key = 'type'
 | 
			
		||||
    ret += mcgen('''
 | 
			
		||||
        visit_type_%(disc_type)s(m, &(*obj)->%(c_tag)s, "%(disc_key)s", &err);
 | 
			
		||||
        visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "%(name)s", &err);
 | 
			
		||||
        if (err) {
 | 
			
		||||
            goto out_obj;
 | 
			
		||||
        }
 | 
			
		||||
        if (!visit_start_union(m, !!(*obj)->data, &err) || err) {
 | 
			
		||||
            goto out_obj;
 | 
			
		||||
        }
 | 
			
		||||
        switch ((*obj)->%(c_tag)s) {
 | 
			
		||||
        switch ((*obj)->%(c_name)s) {
 | 
			
		||||
''',
 | 
			
		||||
                 disc_type = disc_type,
 | 
			
		||||
                 c_tag=c_name(tag),
 | 
			
		||||
                 disc_key = disc_key)
 | 
			
		||||
                 c_type=variants.tag_member.type.c_name(),
 | 
			
		||||
                 # TODO ugly special case for simple union
 | 
			
		||||
                 # Use same tag name in C as on the wire to get rid of
 | 
			
		||||
                 # it, then: c_name=c_name(variants.tag_member.name)
 | 
			
		||||
                 c_name=c_name(variants.tag_name or 'kind'),
 | 
			
		||||
                 name=tag_key)
 | 
			
		||||
 | 
			
		||||
    for key in members:
 | 
			
		||||
        if not discriminator:
 | 
			
		||||
            fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);'
 | 
			
		||||
        else:
 | 
			
		||||
            fmt = 'visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);'
 | 
			
		||||
 | 
			
		||||
        enum_full_value = c_enum_const(disc_type, key)
 | 
			
		||||
    for var in variants.variants:
 | 
			
		||||
        # TODO ugly special case for simple union
 | 
			
		||||
        simple_union_type = var.simple_union_type()
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
        case %(enum_full_value)s:
 | 
			
		||||
            ''' + fmt + '''
 | 
			
		||||
            break;
 | 
			
		||||
        case %(case)s:
 | 
			
		||||
''',
 | 
			
		||||
                enum_full_value = enum_full_value,
 | 
			
		||||
                c_type=type_name(members[key]),
 | 
			
		||||
                c_name=c_name(key))
 | 
			
		||||
                     case=c_enum_const(variants.tag_member.type.name,
 | 
			
		||||
                                       var.name))
 | 
			
		||||
        if simple_union_type:
 | 
			
		||||
            ret += mcgen('''
 | 
			
		||||
            visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);
 | 
			
		||||
''',
 | 
			
		||||
                         c_type=simple_union_type.c_name(),
 | 
			
		||||
                         c_name=c_name(var.name))
 | 
			
		||||
        else:
 | 
			
		||||
            ret += mcgen('''
 | 
			
		||||
            visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);
 | 
			
		||||
''',
 | 
			
		||||
                         c_type=var.type.c_name(),
 | 
			
		||||
                         c_name=c_name(var.name))
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
            break;
 | 
			
		||||
''')
 | 
			
		||||
 | 
			
		||||
    ret += mcgen('''
 | 
			
		||||
        default:
 | 
			
		||||
@ -359,38 +341,59 @@ out:
 | 
			
		||||
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
def generate_declaration(name, builtin_type=False):
 | 
			
		||||
    ret = ""
 | 
			
		||||
    if not builtin_type:
 | 
			
		||||
        name = c_name(name)
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
 | 
			
		||||
void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp);
 | 
			
		||||
''',
 | 
			
		||||
                     name=name)
 | 
			
		||||
class QAPISchemaGenVisitVisitor(QAPISchemaVisitor):
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        self.decl = None
 | 
			
		||||
        self.defn = None
 | 
			
		||||
        self._btin = None
 | 
			
		||||
 | 
			
		||||
    ret += mcgen('''
 | 
			
		||||
void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
 | 
			
		||||
''',
 | 
			
		||||
                 name=name)
 | 
			
		||||
    def visit_begin(self, schema):
 | 
			
		||||
        self.decl = ''
 | 
			
		||||
        self.defn = ''
 | 
			
		||||
        self._btin = guardstart('QAPI_VISIT_BUILTIN')
 | 
			
		||||
 | 
			
		||||
    return ret
 | 
			
		||||
    def visit_end(self):
 | 
			
		||||
        # To avoid header dependency hell, we always generate
 | 
			
		||||
        # declarations for built-in types in our header files and
 | 
			
		||||
        # simply guard them.  See also do_builtins (command line
 | 
			
		||||
        # option -b).
 | 
			
		||||
        self._btin += guardend('QAPI_VISIT_BUILTIN')
 | 
			
		||||
        self.decl = self._btin + self.decl
 | 
			
		||||
        self._btin = None
 | 
			
		||||
 | 
			
		||||
def generate_enum_declaration(name):
 | 
			
		||||
    ret = mcgen('''
 | 
			
		||||
void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
 | 
			
		||||
''',
 | 
			
		||||
                name=c_name(name))
 | 
			
		||||
    def visit_enum_type(self, name, info, values, prefix):
 | 
			
		||||
        self.decl += gen_visit_decl(name, scalar=True)
 | 
			
		||||
        self.defn += gen_visit_enum(name)
 | 
			
		||||
 | 
			
		||||
    return ret
 | 
			
		||||
    def visit_array_type(self, name, info, element_type):
 | 
			
		||||
        decl = gen_visit_decl(name)
 | 
			
		||||
        defn = gen_visit_list(name, element_type)
 | 
			
		||||
        if isinstance(element_type, QAPISchemaBuiltinType):
 | 
			
		||||
            self._btin += decl
 | 
			
		||||
            if do_builtins:
 | 
			
		||||
                self.defn += defn
 | 
			
		||||
        else:
 | 
			
		||||
            self.decl += decl
 | 
			
		||||
            self.defn += defn
 | 
			
		||||
 | 
			
		||||
def generate_decl_enum(name):
 | 
			
		||||
    return mcgen('''
 | 
			
		||||
    def visit_object_type(self, name, info, base, members, variants):
 | 
			
		||||
        if info:
 | 
			
		||||
            self.decl += gen_visit_decl(name)
 | 
			
		||||
            if variants:
 | 
			
		||||
                assert not members      # not implemented
 | 
			
		||||
                self.defn += gen_visit_union(name, base, variants)
 | 
			
		||||
            else:
 | 
			
		||||
                self.defn += gen_visit_struct(name, base, members)
 | 
			
		||||
 | 
			
		||||
void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp);
 | 
			
		||||
''',
 | 
			
		||||
                 name=c_name(name))
 | 
			
		||||
    def visit_alternate_type(self, name, info, variants):
 | 
			
		||||
        self.decl += gen_visit_decl(name)
 | 
			
		||||
        self.defn += gen_visit_alternate(name, variants)
 | 
			
		||||
 | 
			
		||||
# If you link code generated from multiple schemata, you want only one
 | 
			
		||||
# instance of the code for built-in types.  Generate it only when
 | 
			
		||||
# do_builtins, enabled by command line option -b.  See also
 | 
			
		||||
# QAPISchemaGenVisitVisitor.visit_end().
 | 
			
		||||
do_builtins = False
 | 
			
		||||
 | 
			
		||||
(input_file, output_dir, do_c, do_h, prefix, opts) = \
 | 
			
		||||
@ -437,7 +440,7 @@ fdef.write(mcgen('''
 | 
			
		||||
#include "qemu-common.h"
 | 
			
		||||
#include "%(prefix)sqapi-visit.h"
 | 
			
		||||
''',
 | 
			
		||||
                 prefix = prefix))
 | 
			
		||||
                 prefix=prefix))
 | 
			
		||||
 | 
			
		||||
fdecl.write(mcgen('''
 | 
			
		||||
#include "qapi/visitor.h"
 | 
			
		||||
@ -446,56 +449,10 @@ fdecl.write(mcgen('''
 | 
			
		||||
''',
 | 
			
		||||
                  prefix=prefix))
 | 
			
		||||
 | 
			
		||||
exprs = parse_schema(input_file)
 | 
			
		||||
 | 
			
		||||
# to avoid header dependency hell, we always generate declarations
 | 
			
		||||
# for built-in types in our header files and simply guard them
 | 
			
		||||
fdecl.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
 | 
			
		||||
for typename in builtin_types.keys():
 | 
			
		||||
    fdecl.write(generate_declaration(typename, builtin_type=True))
 | 
			
		||||
fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
 | 
			
		||||
 | 
			
		||||
# ...this doesn't work for cases where we link in multiple objects that
 | 
			
		||||
# have the functions defined, so we use -b option to provide control
 | 
			
		||||
# over these cases
 | 
			
		||||
if do_builtins:
 | 
			
		||||
    for typename in builtin_types.keys():
 | 
			
		||||
        fdef.write(generate_visit_list(typename))
 | 
			
		||||
 | 
			
		||||
for expr in exprs:
 | 
			
		||||
    if expr.has_key('struct'):
 | 
			
		||||
        ret = generate_visit_struct(expr)
 | 
			
		||||
        ret += generate_visit_list(expr['struct'])
 | 
			
		||||
        fdef.write(ret)
 | 
			
		||||
 | 
			
		||||
        ret = generate_declaration(expr['struct'])
 | 
			
		||||
        fdecl.write(ret)
 | 
			
		||||
    elif expr.has_key('union'):
 | 
			
		||||
        ret = generate_visit_union(expr)
 | 
			
		||||
        ret += generate_visit_list(expr['union'])
 | 
			
		||||
        fdef.write(ret)
 | 
			
		||||
 | 
			
		||||
        enum_define = discriminator_find_enum_define(expr)
 | 
			
		||||
        ret = ""
 | 
			
		||||
        if not enum_define:
 | 
			
		||||
            ret = generate_decl_enum('%sKind' % expr['union'])
 | 
			
		||||
        ret += generate_declaration(expr['union'])
 | 
			
		||||
        fdecl.write(ret)
 | 
			
		||||
    elif expr.has_key('alternate'):
 | 
			
		||||
        ret = generate_visit_alternate(expr['alternate'], expr['data'])
 | 
			
		||||
        ret += generate_visit_list(expr['alternate'])
 | 
			
		||||
        fdef.write(ret)
 | 
			
		||||
 | 
			
		||||
        ret = generate_decl_enum('%sKind' % expr['alternate'])
 | 
			
		||||
        ret += generate_declaration(expr['alternate'])
 | 
			
		||||
        fdecl.write(ret)
 | 
			
		||||
    elif expr.has_key('enum'):
 | 
			
		||||
        ret = generate_visit_list(expr['enum'])
 | 
			
		||||
        ret += generate_visit_enum(expr['enum'])
 | 
			
		||||
        fdef.write(ret)
 | 
			
		||||
 | 
			
		||||
        ret = generate_decl_enum(expr['enum'])
 | 
			
		||||
        ret += generate_enum_declaration(expr['enum'])
 | 
			
		||||
        fdecl.write(ret)
 | 
			
		||||
schema = QAPISchema(input_file)
 | 
			
		||||
gen = QAPISchemaGenVisitVisitor()
 | 
			
		||||
schema.visit(gen)
 | 
			
		||||
fdef.write(gen.defn)
 | 
			
		||||
fdecl.write(gen.decl)
 | 
			
		||||
 | 
			
		||||
close_output(fdef, fdecl)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										708
									
								
								scripts/qapi.py
									
									
									
									
									
								
							
							
						
						
									
										708
									
								
								scripts/qapi.py
									
									
									
									
									
								
							@ -33,12 +33,14 @@ builtin_types = {
 | 
			
		||||
    'uint32':   'QTYPE_QINT',
 | 
			
		||||
    'uint64':   'QTYPE_QINT',
 | 
			
		||||
    'size':     'QTYPE_QINT',
 | 
			
		||||
    'any':      None,           # any qtype_code possible, actually
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Whitelist of commands allowed to return a non-dictionary
 | 
			
		||||
returns_whitelist = [
 | 
			
		||||
    # From QMP:
 | 
			
		||||
    'human-monitor-command',
 | 
			
		||||
    'qom-get',
 | 
			
		||||
    'query-migrate-cache-size',
 | 
			
		||||
    'query-tpm-models',
 | 
			
		||||
    'query-tpm-types',
 | 
			
		||||
@ -103,7 +105,7 @@ class QAPIExprError(Exception):
 | 
			
		||||
        return error_path(self.info['parent']) + \
 | 
			
		||||
            "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
 | 
			
		||||
 | 
			
		||||
class QAPISchema:
 | 
			
		||||
class QAPISchemaParser(object):
 | 
			
		||||
 | 
			
		||||
    def __init__(self, fp, previously_included = [], incl_info = None):
 | 
			
		||||
        abs_fname = os.path.abspath(fp.name)
 | 
			
		||||
@ -149,8 +151,8 @@ class QAPISchema:
 | 
			
		||||
                except IOError, e:
 | 
			
		||||
                    raise QAPIExprError(expr_info,
 | 
			
		||||
                                        '%s: %s' % (e.strerror, include))
 | 
			
		||||
                exprs_include = QAPISchema(fobj, previously_included,
 | 
			
		||||
                                           expr_info)
 | 
			
		||||
                exprs_include = QAPISchemaParser(fobj, previously_included,
 | 
			
		||||
                                                 expr_info)
 | 
			
		||||
                self.exprs.extend(exprs_include.exprs)
 | 
			
		||||
            else:
 | 
			
		||||
                expr_elem = {'expr': expr,
 | 
			
		||||
@ -302,6 +304,8 @@ class QAPISchema:
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Semantic analysis of schema expressions
 | 
			
		||||
# TODO fold into QAPISchema
 | 
			
		||||
# TODO catching name collisions in generated code would be nice
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
def find_base_fields(base):
 | 
			
		||||
@ -424,15 +428,12 @@ def is_enum(name):
 | 
			
		||||
 | 
			
		||||
def check_type(expr_info, source, value, allow_array = False,
 | 
			
		||||
               allow_dict = False, allow_optional = False,
 | 
			
		||||
               allow_star = False, allow_metas = []):
 | 
			
		||||
               allow_metas = []):
 | 
			
		||||
    global all_names
 | 
			
		||||
 | 
			
		||||
    if value is None:
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    if allow_star and value == '**':
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    # Check if array type for value is okay
 | 
			
		||||
    if isinstance(value, list):
 | 
			
		||||
        if not allow_array:
 | 
			
		||||
@ -446,10 +447,6 @@ def check_type(expr_info, source, value, allow_array = False,
 | 
			
		||||
 | 
			
		||||
    # Check if type name for value is okay
 | 
			
		||||
    if isinstance(value, str):
 | 
			
		||||
        if value == '**':
 | 
			
		||||
            raise QAPIExprError(expr_info,
 | 
			
		||||
                                "%s uses '**' but did not request 'gen':false"
 | 
			
		||||
                                % source)
 | 
			
		||||
        if not value in all_names:
 | 
			
		||||
            raise QAPIExprError(expr_info,
 | 
			
		||||
                                "%s uses unknown type '%s'"
 | 
			
		||||
@ -475,7 +472,7 @@ def check_type(expr_info, source, value, allow_array = False,
 | 
			
		||||
        # Todo: allow dictionaries to represent default values of
 | 
			
		||||
        # an optional argument.
 | 
			
		||||
        check_type(expr_info, "Member '%s' of %s" % (key, source), arg,
 | 
			
		||||
                   allow_array=True, allow_star=allow_star,
 | 
			
		||||
                   allow_array=True,
 | 
			
		||||
                   allow_metas=['built-in', 'union', 'alternate', 'struct',
 | 
			
		||||
                                'enum'])
 | 
			
		||||
 | 
			
		||||
@ -495,18 +492,16 @@ def check_member_clash(expr_info, base_name, data, source = ""):
 | 
			
		||||
 | 
			
		||||
def check_command(expr, expr_info):
 | 
			
		||||
    name = expr['command']
 | 
			
		||||
    allow_star = expr.has_key('gen')
 | 
			
		||||
 | 
			
		||||
    check_type(expr_info, "'data' for command '%s'" % name,
 | 
			
		||||
               expr.get('data'), allow_dict=True, allow_optional=True,
 | 
			
		||||
               allow_metas=['struct'], allow_star=allow_star)
 | 
			
		||||
               allow_metas=['struct'])
 | 
			
		||||
    returns_meta = ['union', 'struct']
 | 
			
		||||
    if name in returns_whitelist:
 | 
			
		||||
        returns_meta += ['built-in', 'alternate', 'enum']
 | 
			
		||||
    check_type(expr_info, "'returns' for command '%s'" % name,
 | 
			
		||||
               expr.get('returns'), allow_array=True,
 | 
			
		||||
               allow_optional=True, allow_metas=returns_meta,
 | 
			
		||||
               allow_star=allow_star)
 | 
			
		||||
               allow_optional=True, allow_metas=returns_meta)
 | 
			
		||||
 | 
			
		||||
def check_event(expr, expr_info):
 | 
			
		||||
    global events
 | 
			
		||||
@ -751,37 +746,539 @@ def check_exprs(exprs):
 | 
			
		||||
        else:
 | 
			
		||||
            assert False, 'unexpected meta type'
 | 
			
		||||
 | 
			
		||||
    return map(lambda expr_elem: expr_elem['expr'], exprs)
 | 
			
		||||
    return exprs
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Schema compiler frontend
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
class QAPISchemaEntity(object):
 | 
			
		||||
    def __init__(self, name, info):
 | 
			
		||||
        assert isinstance(name, str)
 | 
			
		||||
        self.name = name
 | 
			
		||||
        self.info = info
 | 
			
		||||
 | 
			
		||||
    def c_name(self):
 | 
			
		||||
        return c_name(self.name)
 | 
			
		||||
 | 
			
		||||
    def check(self, schema):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def visit(self, visitor):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class QAPISchemaVisitor(object):
 | 
			
		||||
    def visit_begin(self, schema):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def visit_end(self):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def visit_builtin_type(self, name, info, json_type):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def visit_enum_type(self, name, info, values, prefix):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def visit_array_type(self, name, info, element_type):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def visit_object_type(self, name, info, base, members, variants):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def visit_object_type_flat(self, name, info, members, variants):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def visit_alternate_type(self, name, info, variants):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def visit_command(self, name, info, arg_type, ret_type,
 | 
			
		||||
                      gen, success_response):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def visit_event(self, name, info, arg_type):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class QAPISchemaType(QAPISchemaEntity):
 | 
			
		||||
    def c_type(self, is_param=False):
 | 
			
		||||
        return c_name(self.name) + pointer_suffix
 | 
			
		||||
 | 
			
		||||
    def c_null(self):
 | 
			
		||||
        return 'NULL'
 | 
			
		||||
 | 
			
		||||
    def json_type(self):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def alternate_qtype(self):
 | 
			
		||||
        json2qtype = {
 | 
			
		||||
            'string':  'QTYPE_QSTRING',
 | 
			
		||||
            'number':  'QTYPE_QFLOAT',
 | 
			
		||||
            'int':     'QTYPE_QINT',
 | 
			
		||||
            'boolean': 'QTYPE_QBOOL',
 | 
			
		||||
            'object':  'QTYPE_QDICT'
 | 
			
		||||
        }
 | 
			
		||||
        return json2qtype.get(self.json_type())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class QAPISchemaBuiltinType(QAPISchemaType):
 | 
			
		||||
    def __init__(self, name, json_type, c_type, c_null):
 | 
			
		||||
        QAPISchemaType.__init__(self, name, None)
 | 
			
		||||
        assert not c_type or isinstance(c_type, str)
 | 
			
		||||
        assert json_type in ('string', 'number', 'int', 'boolean', 'null',
 | 
			
		||||
                             'value')
 | 
			
		||||
        self._json_type_name = json_type
 | 
			
		||||
        self._c_type_name = c_type
 | 
			
		||||
        self._c_null_val = c_null
 | 
			
		||||
 | 
			
		||||
    def c_name(self):
 | 
			
		||||
        return self.name
 | 
			
		||||
 | 
			
		||||
    def c_type(self, is_param=False):
 | 
			
		||||
        if is_param and self.name == 'str':
 | 
			
		||||
            return 'const ' + self._c_type_name
 | 
			
		||||
        return self._c_type_name
 | 
			
		||||
 | 
			
		||||
    def c_null(self):
 | 
			
		||||
        return self._c_null_val
 | 
			
		||||
 | 
			
		||||
    def json_type(self):
 | 
			
		||||
        return self._json_type_name
 | 
			
		||||
 | 
			
		||||
    def visit(self, visitor):
 | 
			
		||||
        visitor.visit_builtin_type(self.name, self.info, self.json_type())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class QAPISchemaEnumType(QAPISchemaType):
 | 
			
		||||
    def __init__(self, name, info, values, prefix):
 | 
			
		||||
        QAPISchemaType.__init__(self, name, info)
 | 
			
		||||
        for v in values:
 | 
			
		||||
            assert isinstance(v, str)
 | 
			
		||||
        assert prefix is None or isinstance(prefix, str)
 | 
			
		||||
        self.values = values
 | 
			
		||||
        self.prefix = prefix
 | 
			
		||||
 | 
			
		||||
    def check(self, schema):
 | 
			
		||||
        assert len(set(self.values)) == len(self.values)
 | 
			
		||||
 | 
			
		||||
    def c_type(self, is_param=False):
 | 
			
		||||
        return c_name(self.name)
 | 
			
		||||
 | 
			
		||||
    def c_null(self):
 | 
			
		||||
        return c_enum_const(self.name, (self.values + ['MAX'])[0],
 | 
			
		||||
                            self.prefix)
 | 
			
		||||
 | 
			
		||||
    def json_type(self):
 | 
			
		||||
        return 'string'
 | 
			
		||||
 | 
			
		||||
    def visit(self, visitor):
 | 
			
		||||
        visitor.visit_enum_type(self.name, self.info,
 | 
			
		||||
                                self.values, self.prefix)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class QAPISchemaArrayType(QAPISchemaType):
 | 
			
		||||
    def __init__(self, name, info, element_type):
 | 
			
		||||
        QAPISchemaType.__init__(self, name, info)
 | 
			
		||||
        assert isinstance(element_type, str)
 | 
			
		||||
        self._element_type_name = element_type
 | 
			
		||||
        self.element_type = None
 | 
			
		||||
 | 
			
		||||
    def check(self, schema):
 | 
			
		||||
        self.element_type = schema.lookup_type(self._element_type_name)
 | 
			
		||||
        assert self.element_type
 | 
			
		||||
 | 
			
		||||
    def json_type(self):
 | 
			
		||||
        return 'array'
 | 
			
		||||
 | 
			
		||||
    def visit(self, visitor):
 | 
			
		||||
        visitor.visit_array_type(self.name, self.info, self.element_type)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class QAPISchemaObjectType(QAPISchemaType):
 | 
			
		||||
    def __init__(self, name, info, base, local_members, variants):
 | 
			
		||||
        QAPISchemaType.__init__(self, name, info)
 | 
			
		||||
        assert base is None or isinstance(base, str)
 | 
			
		||||
        for m in local_members:
 | 
			
		||||
            assert isinstance(m, QAPISchemaObjectTypeMember)
 | 
			
		||||
        assert (variants is None or
 | 
			
		||||
                isinstance(variants, QAPISchemaObjectTypeVariants))
 | 
			
		||||
        self._base_name = base
 | 
			
		||||
        self.base = None
 | 
			
		||||
        self.local_members = local_members
 | 
			
		||||
        self.variants = variants
 | 
			
		||||
        self.members = None
 | 
			
		||||
 | 
			
		||||
    def check(self, schema):
 | 
			
		||||
        assert self.members is not False        # not running in cycles
 | 
			
		||||
        if self.members:
 | 
			
		||||
            return
 | 
			
		||||
        self.members = False                    # mark as being checked
 | 
			
		||||
        if self._base_name:
 | 
			
		||||
            self.base = schema.lookup_type(self._base_name)
 | 
			
		||||
            assert isinstance(self.base, QAPISchemaObjectType)
 | 
			
		||||
            assert not self.base.variants       # not implemented
 | 
			
		||||
            self.base.check(schema)
 | 
			
		||||
            members = list(self.base.members)
 | 
			
		||||
        else:
 | 
			
		||||
            members = []
 | 
			
		||||
        seen = {}
 | 
			
		||||
        for m in members:
 | 
			
		||||
            seen[m.name] = m
 | 
			
		||||
        for m in self.local_members:
 | 
			
		||||
            m.check(schema, members, seen)
 | 
			
		||||
        if self.variants:
 | 
			
		||||
            self.variants.check(schema, members, seen)
 | 
			
		||||
        self.members = members
 | 
			
		||||
 | 
			
		||||
    def c_name(self):
 | 
			
		||||
        assert self.info
 | 
			
		||||
        return QAPISchemaType.c_name(self)
 | 
			
		||||
 | 
			
		||||
    def c_type(self, is_param=False):
 | 
			
		||||
        assert self.info
 | 
			
		||||
        return QAPISchemaType.c_type(self)
 | 
			
		||||
 | 
			
		||||
    def json_type(self):
 | 
			
		||||
        return 'object'
 | 
			
		||||
 | 
			
		||||
    def visit(self, visitor):
 | 
			
		||||
        visitor.visit_object_type(self.name, self.info,
 | 
			
		||||
                                  self.base, self.local_members, self.variants)
 | 
			
		||||
        visitor.visit_object_type_flat(self.name, self.info,
 | 
			
		||||
                                       self.members, self.variants)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class QAPISchemaObjectTypeMember(object):
 | 
			
		||||
    def __init__(self, name, typ, optional):
 | 
			
		||||
        assert isinstance(name, str)
 | 
			
		||||
        assert isinstance(typ, str)
 | 
			
		||||
        assert isinstance(optional, bool)
 | 
			
		||||
        self.name = name
 | 
			
		||||
        self._type_name = typ
 | 
			
		||||
        self.type = None
 | 
			
		||||
        self.optional = optional
 | 
			
		||||
 | 
			
		||||
    def check(self, schema, all_members, seen):
 | 
			
		||||
        assert self.name not in seen
 | 
			
		||||
        self.type = schema.lookup_type(self._type_name)
 | 
			
		||||
        assert self.type
 | 
			
		||||
        all_members.append(self)
 | 
			
		||||
        seen[self.name] = self
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class QAPISchemaObjectTypeVariants(object):
 | 
			
		||||
    def __init__(self, tag_name, tag_enum, variants):
 | 
			
		||||
        assert tag_name is None or isinstance(tag_name, str)
 | 
			
		||||
        assert tag_enum is None or isinstance(tag_enum, str)
 | 
			
		||||
        for v in variants:
 | 
			
		||||
            assert isinstance(v, QAPISchemaObjectTypeVariant)
 | 
			
		||||
        self.tag_name = tag_name
 | 
			
		||||
        if tag_name:
 | 
			
		||||
            assert not tag_enum
 | 
			
		||||
            self.tag_member = None
 | 
			
		||||
        else:
 | 
			
		||||
            self.tag_member = QAPISchemaObjectTypeMember('type', tag_enum,
 | 
			
		||||
                                                         False)
 | 
			
		||||
        self.variants = variants
 | 
			
		||||
 | 
			
		||||
    def check(self, schema, members, seen):
 | 
			
		||||
        if self.tag_name:
 | 
			
		||||
            self.tag_member = seen[self.tag_name]
 | 
			
		||||
        else:
 | 
			
		||||
            self.tag_member.check(schema, members, seen)
 | 
			
		||||
        assert isinstance(self.tag_member.type, QAPISchemaEnumType)
 | 
			
		||||
        for v in self.variants:
 | 
			
		||||
            vseen = dict(seen)
 | 
			
		||||
            v.check(schema, self.tag_member.type, vseen)
 | 
			
		||||
 | 
			
		||||
class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
 | 
			
		||||
    def __init__(self, name, typ):
 | 
			
		||||
        QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
 | 
			
		||||
 | 
			
		||||
    def check(self, schema, tag_type, seen):
 | 
			
		||||
        QAPISchemaObjectTypeMember.check(self, schema, [], seen)
 | 
			
		||||
        assert self.name in tag_type.values
 | 
			
		||||
 | 
			
		||||
    # This function exists to support ugly simple union special cases
 | 
			
		||||
    # TODO get rid of them, and drop the function
 | 
			
		||||
    def simple_union_type(self):
 | 
			
		||||
        if isinstance(self.type, QAPISchemaObjectType) and not self.type.info:
 | 
			
		||||
            assert len(self.type.members) == 1
 | 
			
		||||
            assert not self.type.variants
 | 
			
		||||
            return self.type.members[0].type
 | 
			
		||||
        return None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class QAPISchemaAlternateType(QAPISchemaType):
 | 
			
		||||
    def __init__(self, name, info, variants):
 | 
			
		||||
        QAPISchemaType.__init__(self, name, info)
 | 
			
		||||
        assert isinstance(variants, QAPISchemaObjectTypeVariants)
 | 
			
		||||
        assert not variants.tag_name
 | 
			
		||||
        self.variants = variants
 | 
			
		||||
 | 
			
		||||
    def check(self, schema):
 | 
			
		||||
        self.variants.check(schema, [], {})
 | 
			
		||||
 | 
			
		||||
    def json_type(self):
 | 
			
		||||
        return 'value'
 | 
			
		||||
 | 
			
		||||
    def visit(self, visitor):
 | 
			
		||||
        visitor.visit_alternate_type(self.name, self.info, self.variants)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class QAPISchemaCommand(QAPISchemaEntity):
 | 
			
		||||
    def __init__(self, name, info, arg_type, ret_type, gen, success_response):
 | 
			
		||||
        QAPISchemaEntity.__init__(self, name, info)
 | 
			
		||||
        assert not arg_type or isinstance(arg_type, str)
 | 
			
		||||
        assert not ret_type or isinstance(ret_type, str)
 | 
			
		||||
        self._arg_type_name = arg_type
 | 
			
		||||
        self.arg_type = None
 | 
			
		||||
        self._ret_type_name = ret_type
 | 
			
		||||
        self.ret_type = None
 | 
			
		||||
        self.gen = gen
 | 
			
		||||
        self.success_response = success_response
 | 
			
		||||
 | 
			
		||||
    def check(self, schema):
 | 
			
		||||
        if self._arg_type_name:
 | 
			
		||||
            self.arg_type = schema.lookup_type(self._arg_type_name)
 | 
			
		||||
            assert isinstance(self.arg_type, QAPISchemaObjectType)
 | 
			
		||||
            assert not self.arg_type.variants   # not implemented
 | 
			
		||||
        if self._ret_type_name:
 | 
			
		||||
            self.ret_type = schema.lookup_type(self._ret_type_name)
 | 
			
		||||
            assert isinstance(self.ret_type, QAPISchemaType)
 | 
			
		||||
 | 
			
		||||
    def visit(self, visitor):
 | 
			
		||||
        visitor.visit_command(self.name, self.info,
 | 
			
		||||
                              self.arg_type, self.ret_type,
 | 
			
		||||
                              self.gen, self.success_response)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class QAPISchemaEvent(QAPISchemaEntity):
 | 
			
		||||
    def __init__(self, name, info, arg_type):
 | 
			
		||||
        QAPISchemaEntity.__init__(self, name, info)
 | 
			
		||||
        assert not arg_type or isinstance(arg_type, str)
 | 
			
		||||
        self._arg_type_name = arg_type
 | 
			
		||||
        self.arg_type = None
 | 
			
		||||
 | 
			
		||||
    def check(self, schema):
 | 
			
		||||
        if self._arg_type_name:
 | 
			
		||||
            self.arg_type = schema.lookup_type(self._arg_type_name)
 | 
			
		||||
            assert isinstance(self.arg_type, QAPISchemaObjectType)
 | 
			
		||||
            assert not self.arg_type.variants   # not implemented
 | 
			
		||||
 | 
			
		||||
    def visit(self, visitor):
 | 
			
		||||
        visitor.visit_event(self.name, self.info, self.arg_type)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class QAPISchema(object):
 | 
			
		||||
    def __init__(self, fname):
 | 
			
		||||
        try:
 | 
			
		||||
            self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
 | 
			
		||||
        except (QAPISchemaError, QAPIExprError), err:
 | 
			
		||||
            print >>sys.stderr, err
 | 
			
		||||
            exit(1)
 | 
			
		||||
        self._entity_dict = {}
 | 
			
		||||
        self._def_predefineds()
 | 
			
		||||
        self._def_exprs()
 | 
			
		||||
        self.check()
 | 
			
		||||
 | 
			
		||||
    def _def_entity(self, ent):
 | 
			
		||||
        assert ent.name not in self._entity_dict
 | 
			
		||||
        self._entity_dict[ent.name] = ent
 | 
			
		||||
 | 
			
		||||
    def lookup_entity(self, name, typ=None):
 | 
			
		||||
        ent = self._entity_dict.get(name)
 | 
			
		||||
        if typ and not isinstance(ent, typ):
 | 
			
		||||
            return None
 | 
			
		||||
        return ent
 | 
			
		||||
 | 
			
		||||
    def lookup_type(self, name):
 | 
			
		||||
        return self.lookup_entity(name, QAPISchemaType)
 | 
			
		||||
 | 
			
		||||
    def _def_builtin_type(self, name, json_type, c_type, c_null):
 | 
			
		||||
        self._def_entity(QAPISchemaBuiltinType(name, json_type,
 | 
			
		||||
                                               c_type, c_null))
 | 
			
		||||
        self._make_array_type(name)     # TODO really needed?
 | 
			
		||||
 | 
			
		||||
    def _def_predefineds(self):
 | 
			
		||||
        for t in [('str',    'string',  'char' + pointer_suffix, 'NULL'),
 | 
			
		||||
                  ('number', 'number',  'double',   '0'),
 | 
			
		||||
                  ('int',    'int',     'int64_t',  '0'),
 | 
			
		||||
                  ('int8',   'int',     'int8_t',   '0'),
 | 
			
		||||
                  ('int16',  'int',     'int16_t',  '0'),
 | 
			
		||||
                  ('int32',  'int',     'int32_t',  '0'),
 | 
			
		||||
                  ('int64',  'int',     'int64_t',  '0'),
 | 
			
		||||
                  ('uint8',  'int',     'uint8_t',  '0'),
 | 
			
		||||
                  ('uint16', 'int',     'uint16_t', '0'),
 | 
			
		||||
                  ('uint32', 'int',     'uint32_t', '0'),
 | 
			
		||||
                  ('uint64', 'int',     'uint64_t', '0'),
 | 
			
		||||
                  ('size',   'int',     'uint64_t', '0'),
 | 
			
		||||
                  ('bool',   'boolean', 'bool',     'false'),
 | 
			
		||||
                  ('any',    'value',   'QObject' + pointer_suffix, 'NULL')]:
 | 
			
		||||
            self._def_builtin_type(*t)
 | 
			
		||||
        self.the_empty_object_type = QAPISchemaObjectType(':empty', None, None,
 | 
			
		||||
                                                          [], None)
 | 
			
		||||
        self._def_entity(self.the_empty_object_type)
 | 
			
		||||
 | 
			
		||||
    def _make_implicit_enum_type(self, name, values):
 | 
			
		||||
        name = name + 'Kind'
 | 
			
		||||
        self._def_entity(QAPISchemaEnumType(name, None, values, None))
 | 
			
		||||
        return name
 | 
			
		||||
 | 
			
		||||
    def _make_array_type(self, element_type):
 | 
			
		||||
        name = element_type + 'List'
 | 
			
		||||
        if not self.lookup_type(name):
 | 
			
		||||
            self._def_entity(QAPISchemaArrayType(name, None, element_type))
 | 
			
		||||
        return name
 | 
			
		||||
 | 
			
		||||
    def _make_implicit_object_type(self, name, role, members):
 | 
			
		||||
        if not members:
 | 
			
		||||
            return None
 | 
			
		||||
        name = ':obj-%s-%s' % (name, role)
 | 
			
		||||
        if not self.lookup_entity(name, QAPISchemaObjectType):
 | 
			
		||||
            self._def_entity(QAPISchemaObjectType(name, None, None,
 | 
			
		||||
                                                  members, None))
 | 
			
		||||
        return name
 | 
			
		||||
 | 
			
		||||
    def _def_enum_type(self, expr, info):
 | 
			
		||||
        name = expr['enum']
 | 
			
		||||
        data = expr['data']
 | 
			
		||||
        prefix = expr.get('prefix')
 | 
			
		||||
        self._def_entity(QAPISchemaEnumType(name, info, data, prefix))
 | 
			
		||||
        self._make_array_type(name)     # TODO really needed?
 | 
			
		||||
 | 
			
		||||
    def _make_member(self, name, typ):
 | 
			
		||||
        optional = False
 | 
			
		||||
        if name.startswith('*'):
 | 
			
		||||
            name = name[1:]
 | 
			
		||||
            optional = True
 | 
			
		||||
        if isinstance(typ, list):
 | 
			
		||||
            assert len(typ) == 1
 | 
			
		||||
            typ = self._make_array_type(typ[0])
 | 
			
		||||
        return QAPISchemaObjectTypeMember(name, typ, optional)
 | 
			
		||||
 | 
			
		||||
    def _make_members(self, data):
 | 
			
		||||
        return [self._make_member(key, value)
 | 
			
		||||
                for (key, value) in data.iteritems()]
 | 
			
		||||
 | 
			
		||||
    def _def_struct_type(self, expr, info):
 | 
			
		||||
        name = expr['struct']
 | 
			
		||||
        base = expr.get('base')
 | 
			
		||||
        data = expr['data']
 | 
			
		||||
        self._def_entity(QAPISchemaObjectType(name, info, base,
 | 
			
		||||
                                              self._make_members(data),
 | 
			
		||||
                                              None))
 | 
			
		||||
        self._make_array_type(name)     # TODO really needed?
 | 
			
		||||
 | 
			
		||||
    def _make_variant(self, case, typ):
 | 
			
		||||
        return QAPISchemaObjectTypeVariant(case, typ)
 | 
			
		||||
 | 
			
		||||
    def _make_simple_variant(self, case, typ):
 | 
			
		||||
        if isinstance(typ, list):
 | 
			
		||||
            assert len(typ) == 1
 | 
			
		||||
            typ = self._make_array_type(typ[0])
 | 
			
		||||
        typ = self._make_implicit_object_type(typ, 'wrapper',
 | 
			
		||||
                                              [self._make_member('data', typ)])
 | 
			
		||||
        return QAPISchemaObjectTypeVariant(case, typ)
 | 
			
		||||
 | 
			
		||||
    def _make_tag_enum(self, type_name, variants):
 | 
			
		||||
        return self._make_implicit_enum_type(type_name,
 | 
			
		||||
                                             [v.name for v in variants])
 | 
			
		||||
 | 
			
		||||
    def _def_union_type(self, expr, info):
 | 
			
		||||
        name = expr['union']
 | 
			
		||||
        data = expr['data']
 | 
			
		||||
        base = expr.get('base')
 | 
			
		||||
        tag_name = expr.get('discriminator')
 | 
			
		||||
        tag_enum = None
 | 
			
		||||
        if tag_name:
 | 
			
		||||
            variants = [self._make_variant(key, value)
 | 
			
		||||
                        for (key, value) in data.iteritems()]
 | 
			
		||||
        else:
 | 
			
		||||
            variants = [self._make_simple_variant(key, value)
 | 
			
		||||
                        for (key, value) in data.iteritems()]
 | 
			
		||||
            tag_enum = self._make_tag_enum(name, variants)
 | 
			
		||||
        self._def_entity(
 | 
			
		||||
            QAPISchemaObjectType(name, info, base,
 | 
			
		||||
                                 self._make_members(OrderedDict()),
 | 
			
		||||
                                 QAPISchemaObjectTypeVariants(tag_name,
 | 
			
		||||
                                                              tag_enum,
 | 
			
		||||
                                                              variants)))
 | 
			
		||||
        self._make_array_type(name)     # TODO really needed?
 | 
			
		||||
 | 
			
		||||
    def _def_alternate_type(self, expr, info):
 | 
			
		||||
        name = expr['alternate']
 | 
			
		||||
        data = expr['data']
 | 
			
		||||
        variants = [self._make_variant(key, value)
 | 
			
		||||
                    for (key, value) in data.iteritems()]
 | 
			
		||||
        tag_enum = self._make_tag_enum(name, variants)
 | 
			
		||||
        self._def_entity(
 | 
			
		||||
            QAPISchemaAlternateType(name, info,
 | 
			
		||||
                                    QAPISchemaObjectTypeVariants(None,
 | 
			
		||||
                                                                 tag_enum,
 | 
			
		||||
                                                                 variants)))
 | 
			
		||||
        self._make_array_type(name)     # TODO really needed?
 | 
			
		||||
 | 
			
		||||
    def _def_command(self, expr, info):
 | 
			
		||||
        name = expr['command']
 | 
			
		||||
        data = expr.get('data')
 | 
			
		||||
        rets = expr.get('returns')
 | 
			
		||||
        gen = expr.get('gen', True)
 | 
			
		||||
        success_response = expr.get('success-response', True)
 | 
			
		||||
        if isinstance(data, OrderedDict):
 | 
			
		||||
            data = self._make_implicit_object_type(name, 'arg',
 | 
			
		||||
                                                   self._make_members(data))
 | 
			
		||||
        if isinstance(rets, list):
 | 
			
		||||
            assert len(rets) == 1
 | 
			
		||||
            rets = self._make_array_type(rets[0])
 | 
			
		||||
        self._def_entity(QAPISchemaCommand(name, info, data, rets, gen,
 | 
			
		||||
                                           success_response))
 | 
			
		||||
 | 
			
		||||
    def _def_event(self, expr, info):
 | 
			
		||||
        name = expr['event']
 | 
			
		||||
        data = expr.get('data')
 | 
			
		||||
        if isinstance(data, OrderedDict):
 | 
			
		||||
            data = self._make_implicit_object_type(name, 'arg',
 | 
			
		||||
                                                   self._make_members(data))
 | 
			
		||||
        self._def_entity(QAPISchemaEvent(name, info, data))
 | 
			
		||||
 | 
			
		||||
    def _def_exprs(self):
 | 
			
		||||
        for expr_elem in self.exprs:
 | 
			
		||||
            expr = expr_elem['expr']
 | 
			
		||||
            info = expr_elem['info']
 | 
			
		||||
            if 'enum' in expr:
 | 
			
		||||
                self._def_enum_type(expr, info)
 | 
			
		||||
            elif 'struct' in expr:
 | 
			
		||||
                self._def_struct_type(expr, info)
 | 
			
		||||
            elif 'union' in expr:
 | 
			
		||||
                self._def_union_type(expr, info)
 | 
			
		||||
            elif 'alternate' in expr:
 | 
			
		||||
                self._def_alternate_type(expr, info)
 | 
			
		||||
            elif 'command' in expr:
 | 
			
		||||
                self._def_command(expr, info)
 | 
			
		||||
            elif 'event' in expr:
 | 
			
		||||
                self._def_event(expr, info)
 | 
			
		||||
            else:
 | 
			
		||||
                assert False
 | 
			
		||||
 | 
			
		||||
    def check(self):
 | 
			
		||||
        for ent in self._entity_dict.values():
 | 
			
		||||
            ent.check(self)
 | 
			
		||||
 | 
			
		||||
    def visit(self, visitor):
 | 
			
		||||
        ignore = visitor.visit_begin(self)
 | 
			
		||||
        for name in sorted(self._entity_dict.keys()):
 | 
			
		||||
            if not ignore or not isinstance(self._entity_dict[name], ignore):
 | 
			
		||||
                self._entity_dict[name].visit(visitor)
 | 
			
		||||
        visitor.visit_end()
 | 
			
		||||
 | 
			
		||||
def parse_schema(fname):
 | 
			
		||||
    try:
 | 
			
		||||
        schema = QAPISchema(open(fname, "r"))
 | 
			
		||||
        return check_exprs(schema.exprs)
 | 
			
		||||
    except (QAPISchemaError, QAPIExprError), e:
 | 
			
		||||
        print >>sys.stderr, e
 | 
			
		||||
        exit(1)
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Code generation helpers
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
def parse_args(typeinfo):
 | 
			
		||||
    if isinstance(typeinfo, str):
 | 
			
		||||
        struct = find_struct(typeinfo)
 | 
			
		||||
        assert struct != None
 | 
			
		||||
        typeinfo = struct['data']
 | 
			
		||||
 | 
			
		||||
    for member in typeinfo:
 | 
			
		||||
        argname = member
 | 
			
		||||
        argentry = typeinfo[member]
 | 
			
		||||
        optional = False
 | 
			
		||||
        if member.startswith('*'):
 | 
			
		||||
            argname = member[1:]
 | 
			
		||||
            optional = True
 | 
			
		||||
        # Todo: allow argentry to be OrderedDict, for providing the
 | 
			
		||||
        # value of an optional argument.
 | 
			
		||||
        yield (argname, argentry, optional)
 | 
			
		||||
 | 
			
		||||
def camel_case(name):
 | 
			
		||||
    new_name = ''
 | 
			
		||||
    first = True
 | 
			
		||||
@ -864,70 +1361,9 @@ def c_name(name, protect=True):
 | 
			
		||||
        return "q_" + name
 | 
			
		||||
    return name.translate(c_name_trans)
 | 
			
		||||
 | 
			
		||||
# Map type @name to the C typedef name for the list form.
 | 
			
		||||
#
 | 
			
		||||
# ['Name'] -> 'NameList', ['x-Foo'] -> 'x_FooList', ['int'] -> 'intList'
 | 
			
		||||
def c_list_type(name):
 | 
			
		||||
    return type_name(name) + 'List'
 | 
			
		||||
 | 
			
		||||
# Map type @value to the C typedef form.
 | 
			
		||||
#
 | 
			
		||||
# Used for converting 'type' from a 'member':'type' qapi definition
 | 
			
		||||
# into the alphanumeric portion of the type for a generated C parameter,
 | 
			
		||||
# as well as generated C function names.  See c_type() for the rest of
 | 
			
		||||
# the conversion such as adding '*' on pointer types.
 | 
			
		||||
# 'int' -> 'int', '[x-Foo]' -> 'x_FooList', '__a.b_c' -> '__a_b_c'
 | 
			
		||||
def type_name(value):
 | 
			
		||||
    if type(value) == list:
 | 
			
		||||
        return c_list_type(value[0])
 | 
			
		||||
    if value in builtin_types.keys():
 | 
			
		||||
        return value
 | 
			
		||||
    return c_name(value)
 | 
			
		||||
 | 
			
		||||
eatspace = '\033EATSPACE.'
 | 
			
		||||
pointer_suffix = ' *' + eatspace
 | 
			
		||||
 | 
			
		||||
# Map type @name to its C type expression.
 | 
			
		||||
# If @is_param, const-qualify the string type.
 | 
			
		||||
#
 | 
			
		||||
# This function is used for computing the full C type of 'member':'name'.
 | 
			
		||||
# A special suffix is added in c_type() for pointer types, and it's
 | 
			
		||||
# stripped in mcgen(). So please notice this when you check the return
 | 
			
		||||
# value of c_type() outside mcgen().
 | 
			
		||||
def c_type(value, is_param=False):
 | 
			
		||||
    if value == 'str':
 | 
			
		||||
        if is_param:
 | 
			
		||||
            return 'const char' + pointer_suffix
 | 
			
		||||
        return 'char' + pointer_suffix
 | 
			
		||||
 | 
			
		||||
    elif value == 'int':
 | 
			
		||||
        return 'int64_t'
 | 
			
		||||
    elif (value == 'int8' or value == 'int16' or value == 'int32' or
 | 
			
		||||
          value == 'int64' or value == 'uint8' or value == 'uint16' or
 | 
			
		||||
          value == 'uint32' or value == 'uint64'):
 | 
			
		||||
        return value + '_t'
 | 
			
		||||
    elif value == 'size':
 | 
			
		||||
        return 'uint64_t'
 | 
			
		||||
    elif value == 'bool':
 | 
			
		||||
        return 'bool'
 | 
			
		||||
    elif value == 'number':
 | 
			
		||||
        return 'double'
 | 
			
		||||
    elif type(value) == list:
 | 
			
		||||
        return c_list_type(value[0]) + pointer_suffix
 | 
			
		||||
    elif is_enum(value):
 | 
			
		||||
        return c_name(value)
 | 
			
		||||
    elif value == None:
 | 
			
		||||
        return 'void'
 | 
			
		||||
    elif value in events:
 | 
			
		||||
        return camel_case(value) + 'Event' + pointer_suffix
 | 
			
		||||
    else:
 | 
			
		||||
        # complex type name
 | 
			
		||||
        assert isinstance(value, str) and value != ""
 | 
			
		||||
        return c_name(value) + pointer_suffix
 | 
			
		||||
 | 
			
		||||
def is_c_ptr(value):
 | 
			
		||||
    return c_type(value).endswith(pointer_suffix)
 | 
			
		||||
 | 
			
		||||
def genindent(count):
 | 
			
		||||
    ret = ""
 | 
			
		||||
    for i in range(count):
 | 
			
		||||
@ -982,6 +1418,74 @@ def guardend(name):
 | 
			
		||||
''',
 | 
			
		||||
                 name=guardname(name))
 | 
			
		||||
 | 
			
		||||
def gen_enum_lookup(name, values, prefix=None):
 | 
			
		||||
    ret = mcgen('''
 | 
			
		||||
 | 
			
		||||
const char *const %(c_name)s_lookup[] = {
 | 
			
		||||
''',
 | 
			
		||||
                c_name=c_name(name))
 | 
			
		||||
    for value in values:
 | 
			
		||||
        index = c_enum_const(name, value, prefix)
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
    [%(index)s] = "%(value)s",
 | 
			
		||||
''',
 | 
			
		||||
                     index=index, value=value)
 | 
			
		||||
 | 
			
		||||
    max_index = c_enum_const(name, 'MAX', prefix)
 | 
			
		||||
    ret += mcgen('''
 | 
			
		||||
    [%(max_index)s] = NULL,
 | 
			
		||||
};
 | 
			
		||||
''',
 | 
			
		||||
                 max_index=max_index)
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
def gen_enum(name, values, prefix=None):
 | 
			
		||||
    # append automatically generated _MAX value
 | 
			
		||||
    enum_values = values + ['MAX']
 | 
			
		||||
 | 
			
		||||
    ret = mcgen('''
 | 
			
		||||
 | 
			
		||||
typedef enum %(c_name)s {
 | 
			
		||||
''',
 | 
			
		||||
                c_name=c_name(name))
 | 
			
		||||
 | 
			
		||||
    i = 0
 | 
			
		||||
    for value in enum_values:
 | 
			
		||||
        ret += mcgen('''
 | 
			
		||||
    %(c_enum)s = %(i)d,
 | 
			
		||||
''',
 | 
			
		||||
                     c_enum=c_enum_const(name, value, prefix),
 | 
			
		||||
                     i=i)
 | 
			
		||||
        i += 1
 | 
			
		||||
 | 
			
		||||
    ret += mcgen('''
 | 
			
		||||
} %(c_name)s;
 | 
			
		||||
''',
 | 
			
		||||
                 c_name=c_name(name))
 | 
			
		||||
 | 
			
		||||
    ret += mcgen('''
 | 
			
		||||
 | 
			
		||||
extern const char *const %(c_name)s_lookup[];
 | 
			
		||||
''',
 | 
			
		||||
                 c_name=c_name(name))
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
def gen_params(arg_type, extra):
 | 
			
		||||
    if not arg_type:
 | 
			
		||||
        return extra
 | 
			
		||||
    assert not arg_type.variants
 | 
			
		||||
    ret = ''
 | 
			
		||||
    sep = ''
 | 
			
		||||
    for memb in arg_type.members:
 | 
			
		||||
        ret += sep
 | 
			
		||||
        sep = ', '
 | 
			
		||||
        if memb.optional:
 | 
			
		||||
            ret += 'bool has_%s, ' % c_name(memb.name)
 | 
			
		||||
        ret += '%s %s' % (memb.type.c_type(is_param=True), c_name(memb.name))
 | 
			
		||||
    if extra:
 | 
			
		||||
        ret += sep + extra
 | 
			
		||||
    return ret
 | 
			
		||||
 | 
			
		||||
#
 | 
			
		||||
# Common command line parsing
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								tests/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								tests/.gitignore
									
									
									
									
										vendored
									
									
								
							@ -35,6 +35,7 @@ test-qmp-commands.h
 | 
			
		||||
test-qmp-event
 | 
			
		||||
test-qmp-input-strict
 | 
			
		||||
test-qmp-input-visitor
 | 
			
		||||
test-qmp-introspect.[ch]
 | 
			
		||||
test-qmp-marshal.c
 | 
			
		||||
test-qmp-output-visitor
 | 
			
		||||
test-rcu-list
 | 
			
		||||
 | 
			
		||||
@ -234,11 +234,12 @@ check-qapi-schema-y := $(addprefix tests/qapi-schema/, \
 | 
			
		||||
	bad-type-dict.json double-data.json unknown-expr-key.json \
 | 
			
		||||
	redefined-type.json redefined-command.json redefined-builtin.json \
 | 
			
		||||
	redefined-event.json command-int.json bad-data.json event-max.json \
 | 
			
		||||
	type-bypass.json type-bypass-no-gen.json type-bypass-bad-gen.json \
 | 
			
		||||
	type-bypass-bad-gen.json \
 | 
			
		||||
	args-invalid.json \
 | 
			
		||||
	args-array-empty.json args-array-unknown.json args-int.json \
 | 
			
		||||
	args-unknown.json args-member-unknown.json args-member-array.json \
 | 
			
		||||
	args-member-array-bad.json args-alternate.json args-union.json \
 | 
			
		||||
	args-any.json \
 | 
			
		||||
	returns-array-bad.json returns-int.json returns-dict.json \
 | 
			
		||||
	returns-unknown.json returns-alternate.json returns-whitelist.json \
 | 
			
		||||
	missing-colon.json missing-comma-list.json missing-comma-object.json \
 | 
			
		||||
@ -255,7 +256,7 @@ check-qapi-schema-y := $(addprefix tests/qapi-schema/, \
 | 
			
		||||
	flat-union-invalid-branch-key.json flat-union-reverse-define.json \
 | 
			
		||||
	flat-union-string-discriminator.json union-base-no-discriminator.json \
 | 
			
		||||
	flat-union-bad-discriminator.json flat-union-bad-base.json \
 | 
			
		||||
	flat-union-base-star.json \
 | 
			
		||||
	flat-union-base-any.json \
 | 
			
		||||
	flat-union-array-branch.json flat-union-int-branch.json \
 | 
			
		||||
	flat-union-base-union.json flat-union-branch-clash.json \
 | 
			
		||||
	alternate-nested.json alternate-unknown.json alternate-clash.json \
 | 
			
		||||
@ -268,7 +269,8 @@ check-qapi-schema-y := $(addprefix tests/qapi-schema/, \
 | 
			
		||||
	struct-base-clash.json struct-base-clash-deep.json )
 | 
			
		||||
 | 
			
		||||
GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h \
 | 
			
		||||
		     tests/test-qmp-commands.h tests/test-qapi-event.h
 | 
			
		||||
	tests/test-qmp-commands.h tests/test-qapi-event.h \
 | 
			
		||||
	tests/test-qmp-introspect.h
 | 
			
		||||
 | 
			
		||||
test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \
 | 
			
		||||
	tests/check-qlist.o tests/check-qfloat.o tests/check-qjson.o \
 | 
			
		||||
@ -288,7 +290,7 @@ QEMU_CFLAGS += -I$(SRC_PATH)/tests
 | 
			
		||||
test-util-obj-y = libqemuutil.a libqemustub.a
 | 
			
		||||
test-qom-obj-y = $(qom-obj-y) $(test-util-obj-y)
 | 
			
		||||
test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o \
 | 
			
		||||
	tests/test-qapi-event.o \
 | 
			
		||||
	tests/test-qapi-event.o tests/test-qmp-introspect.o \
 | 
			
		||||
	$(test-qom-obj-y)
 | 
			
		||||
test-crypto-obj-y = $(crypto-obj-y) $(test-qom-obj-y)
 | 
			
		||||
test-block-obj-y = $(block-obj-y) $(test-crypto-obj-y)
 | 
			
		||||
@ -345,6 +347,11 @@ $(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-eve
 | 
			
		||||
	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-event.py \
 | 
			
		||||
		$(gen-out-type) -o tests -p "test-" $<, \
 | 
			
		||||
		"  GEN   $@")
 | 
			
		||||
tests/test-qmp-introspect.c tests/test-qmp-introspect.h :\
 | 
			
		||||
$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-introspect.py $(qapi-py)
 | 
			
		||||
	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-introspect.py \
 | 
			
		||||
		$(gen-out-type) -o tests -p "test-" $<, \
 | 
			
		||||
		"  GEN   $@")
 | 
			
		||||
 | 
			
		||||
tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y)
 | 
			
		||||
tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y)
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,10 @@
 | 
			
		||||
[OrderedDict([('struct', 'Data'), ('data', OrderedDict([('*number', 'int'), ('*name', 'str')]))]),
 | 
			
		||||
 OrderedDict([('enum', 'Enum'), ('data', ['hello', 'world'])]),
 | 
			
		||||
 OrderedDict([('alternate', 'Alt'), ('data', OrderedDict([('value', 'int'), ('string', 'Enum'), ('struct', 'Data')]))])]
 | 
			
		||||
[{'enum_name': 'Enum', 'enum_values': ['hello', 'world']},
 | 
			
		||||
 {'enum_name': 'AltKind', 'enum_values': None}]
 | 
			
		||||
[OrderedDict([('struct', 'Data'), ('data', OrderedDict([('*number', 'int'), ('*name', 'str')]))])]
 | 
			
		||||
object :empty
 | 
			
		||||
alternate Alt
 | 
			
		||||
    case value: int
 | 
			
		||||
    case string: Enum
 | 
			
		||||
    case struct: Data
 | 
			
		||||
enum AltKind ['value', 'string', 'struct']
 | 
			
		||||
object Data
 | 
			
		||||
    member number: int optional=True
 | 
			
		||||
    member name: str optional=True
 | 
			
		||||
enum Enum ['hello', 'world']
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								tests/qapi-schema/args-any.err
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/qapi-schema/args-any.err
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
tests/qapi-schema/args-any.json:2: 'data' for command 'oops' cannot use built-in type 'any'
 | 
			
		||||
							
								
								
									
										2
									
								
								tests/qapi-schema/args-any.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								tests/qapi-schema/args-any.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
			
		||||
# we do not allow an 'any' argument
 | 
			
		||||
{ 'command': 'oops', 'data': 'any' }
 | 
			
		||||
@ -1,5 +1,9 @@
 | 
			
		||||
[OrderedDict([('enum', 'abc'), ('data', ['a', 'b', 'c'])]),
 | 
			
		||||
 OrderedDict([('struct', 'def'), ('data', OrderedDict([('array', ['abc'])]))]),
 | 
			
		||||
 OrderedDict([('command', 'okay'), ('data', OrderedDict([('member1', ['int']), ('member2', ['def'])]))])]
 | 
			
		||||
[{'enum_name': 'abc', 'enum_values': ['a', 'b', 'c']}]
 | 
			
		||||
[OrderedDict([('struct', 'def'), ('data', OrderedDict([('array', ['abc'])]))])]
 | 
			
		||||
object :empty
 | 
			
		||||
object :obj-okay-arg
 | 
			
		||||
    member member1: intList optional=False
 | 
			
		||||
    member member2: defList optional=False
 | 
			
		||||
enum abc ['a', 'b', 'c']
 | 
			
		||||
object def
 | 
			
		||||
    member array: abcList optional=False
 | 
			
		||||
command okay :obj-okay-arg -> None
 | 
			
		||||
   gen=True success_response=True
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,2 @@
 | 
			
		||||
[OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])]
 | 
			
		||||
[{'enum_name': 'Status', 'enum_values': ['good', 'bad', 'ugly']}]
 | 
			
		||||
[]
 | 
			
		||||
object :empty
 | 
			
		||||
enum Status ['good', 'bad', 'ugly']
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1 @@
 | 
			
		||||
[]
 | 
			
		||||
[]
 | 
			
		||||
[]
 | 
			
		||||
object :empty
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,2 @@
 | 
			
		||||
[OrderedDict([('enum', 'MyEnum'), ('data', [])])]
 | 
			
		||||
[{'enum_name': 'MyEnum', 'enum_values': []}]
 | 
			
		||||
[]
 | 
			
		||||
object :empty
 | 
			
		||||
enum MyEnum []
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,2 @@
 | 
			
		||||
[OrderedDict([('event', 'oops')])]
 | 
			
		||||
[]
 | 
			
		||||
[]
 | 
			
		||||
object :empty
 | 
			
		||||
event oops None
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								tests/qapi-schema/flat-union-base-any.err
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								tests/qapi-schema/flat-union-base-any.err
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
tests/qapi-schema/flat-union-base-any.json:8: Base 'any' is not a valid struct
 | 
			
		||||
@ -6,7 +6,7 @@
 | 
			
		||||
{ 'struct': 'TestTypeB',
 | 
			
		||||
  'data': { 'integer': 'int' } }
 | 
			
		||||
{ 'union': 'TestUnion',
 | 
			
		||||
  'base': '**',
 | 
			
		||||
  'base': 'any',
 | 
			
		||||
  'discriminator': 'enum1',
 | 
			
		||||
  'data': { 'value1': 'TestTypeA',
 | 
			
		||||
            'value2': 'TestTypeB' } }
 | 
			
		||||
@ -1 +0,0 @@
 | 
			
		||||
tests/qapi-schema/flat-union-base-star.json:8: Base '**' is not a valid struct
 | 
			
		||||
@ -1,9 +1,13 @@
 | 
			
		||||
[OrderedDict([('union', 'TestUnion'), ('base', 'TestBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'TestTypeA'), ('value2', 'TestTypeB')]))]),
 | 
			
		||||
 OrderedDict([('struct', 'TestBase'), ('data', OrderedDict([('enum1', 'TestEnum')]))]),
 | 
			
		||||
 OrderedDict([('enum', 'TestEnum'), ('data', ['value1', 'value2'])]),
 | 
			
		||||
 OrderedDict([('struct', 'TestTypeA'), ('data', OrderedDict([('string', 'str')]))]),
 | 
			
		||||
 OrderedDict([('struct', 'TestTypeB'), ('data', OrderedDict([('integer', 'int')]))])]
 | 
			
		||||
[{'enum_name': 'TestEnum', 'enum_values': ['value1', 'value2']}]
 | 
			
		||||
[OrderedDict([('struct', 'TestBase'), ('data', OrderedDict([('enum1', 'TestEnum')]))]),
 | 
			
		||||
 OrderedDict([('struct', 'TestTypeA'), ('data', OrderedDict([('string', 'str')]))]),
 | 
			
		||||
 OrderedDict([('struct', 'TestTypeB'), ('data', OrderedDict([('integer', 'int')]))])]
 | 
			
		||||
object :empty
 | 
			
		||||
object TestBase
 | 
			
		||||
    member enum1: TestEnum optional=False
 | 
			
		||||
enum TestEnum ['value1', 'value2']
 | 
			
		||||
object TestTypeA
 | 
			
		||||
    member string: str optional=False
 | 
			
		||||
object TestTypeB
 | 
			
		||||
    member integer: int optional=False
 | 
			
		||||
object TestUnion
 | 
			
		||||
    base TestBase
 | 
			
		||||
    tag enum1
 | 
			
		||||
    case value1: TestTypeA
 | 
			
		||||
    case value2: TestTypeB
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,5 @@
 | 
			
		||||
[OrderedDict([('command', 'fooA'), ('data', OrderedDict([('bar1', 'str')]))])]
 | 
			
		||||
[]
 | 
			
		||||
[]
 | 
			
		||||
object :empty
 | 
			
		||||
object :obj-fooA-arg
 | 
			
		||||
    member bar1: str optional=False
 | 
			
		||||
command fooA :obj-fooA-arg -> None
 | 
			
		||||
   gen=True success_response=True
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,2 @@
 | 
			
		||||
[OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])]
 | 
			
		||||
[{'enum_name': 'Status', 'enum_values': ['good', 'bad', 'ugly']}]
 | 
			
		||||
[]
 | 
			
		||||
object :empty
 | 
			
		||||
enum Status ['good', 'bad', 'ugly']
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,2 @@
 | 
			
		||||
[OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])]
 | 
			
		||||
[{'enum_name': 'Status', 'enum_values': ['good', 'bad', 'ugly']}]
 | 
			
		||||
[]
 | 
			
		||||
object :empty
 | 
			
		||||
enum Status ['good', 'bad', 'ugly']
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,2 @@
 | 
			
		||||
[OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])]
 | 
			
		||||
[{'enum_name': 'Status', 'enum_values': ['good', 'bad', 'ugly']}]
 | 
			
		||||
[]
 | 
			
		||||
object :empty
 | 
			
		||||
enum Status ['good', 'bad', 'ugly']
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,5 @@
 | 
			
		||||
[OrderedDict([('command', 'eins')]), OrderedDict([('command', 'zwei')])]
 | 
			
		||||
[]
 | 
			
		||||
[]
 | 
			
		||||
object :empty
 | 
			
		||||
command eins None -> None
 | 
			
		||||
   gen=True success_response=True
 | 
			
		||||
command zwei None -> None
 | 
			
		||||
   gen=True success_response=True
 | 
			
		||||
 | 
			
		||||
@ -44,8 +44,6 @@
 | 
			
		||||
  'data': { 'value1' : 'UserDefA',
 | 
			
		||||
            'value2' : 'UserDefB',
 | 
			
		||||
            'value3' : 'UserDefB' } }
 | 
			
		||||
# FIXME generated struct UserDefFlatUnion has members for direct base
 | 
			
		||||
# UserDefUnionBase, but lacks members for indirect base UserDefZero
 | 
			
		||||
 | 
			
		||||
{ 'struct': 'UserDefUnionBase',
 | 
			
		||||
  'base': 'UserDefZero',
 | 
			
		||||
@ -62,7 +60,6 @@
 | 
			
		||||
 | 
			
		||||
{ 'alternate': 'UserDefAlternate',
 | 
			
		||||
  'data': { 'uda': 'UserDefA', 's': 'str', 'i': 'int' } }
 | 
			
		||||
# FIXME only a declaration of visit_type_UserDefAlternateKind() generated
 | 
			
		||||
 | 
			
		||||
{ 'struct': 'UserDefC',
 | 
			
		||||
  'data': { 'string1': 'str', 'string2': 'str' } }
 | 
			
		||||
@ -81,7 +78,8 @@
 | 
			
		||||
            'number': ['number'],
 | 
			
		||||
            'boolean': ['bool'],
 | 
			
		||||
            'string': ['str'],
 | 
			
		||||
            'sizes': ['size'] } }
 | 
			
		||||
            'sizes': ['size'],
 | 
			
		||||
            'any': ['any'] } }
 | 
			
		||||
 | 
			
		||||
# testing commands
 | 
			
		||||
{ 'command': 'user_def_cmd', 'data': {} }
 | 
			
		||||
@ -91,6 +89,8 @@
 | 
			
		||||
  'returns': 'UserDefTwo' }
 | 
			
		||||
{ 'command': 'user_def_cmd3', 'data': {'a': 'int', '*b': 'int' },
 | 
			
		||||
  'returns': 'int' }
 | 
			
		||||
# note: command name 'guest-sync' chosen to avoid "cannot use built-in" error
 | 
			
		||||
{ 'command': 'guest-sync', 'data': { 'arg': 'any' }, 'returns': 'any' }
 | 
			
		||||
 | 
			
		||||
# For testing integer range flattening in opts-visitor. The following schema
 | 
			
		||||
# corresponds to the option format:
 | 
			
		||||
@ -134,9 +134,6 @@
 | 
			
		||||
{ 'alternate': '__org.qemu_x-Alt',
 | 
			
		||||
  'data': { '__org.qemu_x-branch': 'str', 'b': '__org.qemu_x-Base' } }
 | 
			
		||||
{ 'event': '__ORG.QEMU_X-EVENT', 'data': '__org.qemu_x-Struct' }
 | 
			
		||||
# FIXME generated qapi_event_send___org_qemu_x_event() has only a
 | 
			
		||||
# parameter for data's member __org_qemu_x_member2, none for its base
 | 
			
		||||
# __org.qemu_x-Base's member __org_qemu_x_member1
 | 
			
		||||
{ 'command': '__org.qemu_x-command',
 | 
			
		||||
  'data': { 'a': ['__org.qemu_x-Enum'], 'b': ['__org.qemu_x-Struct'],
 | 
			
		||||
            'c': '__org.qemu_x-Union2', 'd': '__org.qemu_x-Alt' },
 | 
			
		||||
 | 
			
		||||
@ -1,57 +1,169 @@
 | 
			
		||||
[OrderedDict([('enum', 'EnumOne'), ('data', ['value1', 'value2', 'value3'])]),
 | 
			
		||||
 OrderedDict([('struct', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]),
 | 
			
		||||
 OrderedDict([('enum', 'QEnumTwo'), ('prefix', 'QENUM_TWO'), ('data', ['value1', 'value2'])]),
 | 
			
		||||
 OrderedDict([('struct', 'UserDefOne'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('*enum1', 'EnumOne')]))]),
 | 
			
		||||
 OrderedDict([('struct', 'UserDefZero'), ('data', OrderedDict([('integer', 'int')]))]),
 | 
			
		||||
 OrderedDict([('struct', 'UserDefTwoDictDict'), ('data', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')]))]),
 | 
			
		||||
 OrderedDict([('struct', 'UserDefTwoDict'), ('data', OrderedDict([('string1', 'str'), ('dict2', 'UserDefTwoDictDict'), ('*dict3', 'UserDefTwoDictDict')]))]),
 | 
			
		||||
 OrderedDict([('struct', 'UserDefTwo'), ('data', OrderedDict([('string0', 'str'), ('dict1', 'UserDefTwoDict')]))]),
 | 
			
		||||
 OrderedDict([('struct', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]),
 | 
			
		||||
 OrderedDict([('struct', 'UserDefB'), ('data', OrderedDict([('intb', 'int')]))]),
 | 
			
		||||
 OrderedDict([('union', 'UserDefFlatUnion'), ('base', 'UserDefUnionBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'UserDefA'), ('value2', 'UserDefB'), ('value3', 'UserDefB')]))]),
 | 
			
		||||
 OrderedDict([('struct', 'UserDefUnionBase'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]),
 | 
			
		||||
 OrderedDict([('union', 'UserDefFlatUnion2'), ('base', 'UserDefUnionBase'), ('discriminator', 'enum1'), ('data', OrderedDict([('value1', 'UserDefC'), ('value2', 'UserDefB'), ('value3', 'UserDefA')]))]),
 | 
			
		||||
 OrderedDict([('alternate', 'UserDefAlternate'), ('data', OrderedDict([('uda', 'UserDefA'), ('s', 'str'), ('i', 'int')]))]),
 | 
			
		||||
 OrderedDict([('struct', 'UserDefC'), ('data', OrderedDict([('string1', 'str'), ('string2', 'str')]))]),
 | 
			
		||||
 OrderedDict([('union', 'UserDefNativeListUnion'), ('data', OrderedDict([('integer', ['int']), ('s8', ['int8']), ('s16', ['int16']), ('s32', ['int32']), ('s64', ['int64']), ('u8', ['uint8']), ('u16', ['uint16']), ('u32', ['uint32']), ('u64', ['uint64']), ('number', ['number']), ('boolean', ['bool']), ('string', ['str']), ('sizes', ['size'])]))]),
 | 
			
		||||
 OrderedDict([('command', 'user_def_cmd'), ('data', OrderedDict())]),
 | 
			
		||||
 OrderedDict([('command', 'user_def_cmd1'), ('data', OrderedDict([('ud1a', 'UserDefOne')]))]),
 | 
			
		||||
 OrderedDict([('command', 'user_def_cmd2'), ('data', OrderedDict([('ud1a', 'UserDefOne'), ('*ud1b', 'UserDefOne')])), ('returns', 'UserDefTwo')]),
 | 
			
		||||
 OrderedDict([('command', 'user_def_cmd3'), ('data', OrderedDict([('a', 'int'), ('*b', 'int')])), ('returns', 'int')]),
 | 
			
		||||
 OrderedDict([('struct', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))]),
 | 
			
		||||
 OrderedDict([('struct', 'EventStructOne'), ('data', OrderedDict([('struct1', 'UserDefOne'), ('string', 'str'), ('*enum2', 'EnumOne')]))]),
 | 
			
		||||
 OrderedDict([('event', 'EVENT_A')]),
 | 
			
		||||
 OrderedDict([('event', 'EVENT_B'), ('data', OrderedDict())]),
 | 
			
		||||
 OrderedDict([('event', 'EVENT_C'), ('data', OrderedDict([('*a', 'int'), ('*b', 'UserDefOne'), ('c', 'str')]))]),
 | 
			
		||||
 OrderedDict([('event', 'EVENT_D'), ('data', OrderedDict([('a', 'EventStructOne'), ('b', 'str'), ('*c', 'str'), ('*enum3', 'EnumOne')]))]),
 | 
			
		||||
 OrderedDict([('enum', '__org.qemu_x-Enum'), ('data', ['__org.qemu_x-value'])]),
 | 
			
		||||
 OrderedDict([('struct', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member1', '__org.qemu_x-Enum')]))]),
 | 
			
		||||
 OrderedDict([('struct', '__org.qemu_x-Struct'), ('base', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member2', 'str')]))]),
 | 
			
		||||
 OrderedDict([('union', '__org.qemu_x-Union1'), ('data', OrderedDict([('__org.qemu_x-branch', 'str')]))]),
 | 
			
		||||
 OrderedDict([('struct', '__org.qemu_x-Struct2'), ('data', OrderedDict([('array', ['__org.qemu_x-Union1'])]))]),
 | 
			
		||||
 OrderedDict([('union', '__org.qemu_x-Union2'), ('base', '__org.qemu_x-Base'), ('discriminator', '__org.qemu_x-member1'), ('data', OrderedDict([('__org.qemu_x-value', '__org.qemu_x-Struct2')]))]),
 | 
			
		||||
 OrderedDict([('alternate', '__org.qemu_x-Alt'), ('data', OrderedDict([('__org.qemu_x-branch', 'str'), ('b', '__org.qemu_x-Base')]))]),
 | 
			
		||||
 OrderedDict([('event', '__ORG.QEMU_X-EVENT'), ('data', '__org.qemu_x-Struct')]),
 | 
			
		||||
 OrderedDict([('command', '__org.qemu_x-command'), ('data', OrderedDict([('a', ['__org.qemu_x-Enum']), ('b', ['__org.qemu_x-Struct']), ('c', '__org.qemu_x-Union2'), ('d', '__org.qemu_x-Alt')])), ('returns', '__org.qemu_x-Union1')])]
 | 
			
		||||
[{'enum_name': 'EnumOne', 'enum_values': ['value1', 'value2', 'value3']},
 | 
			
		||||
 {'enum_name': 'QEnumTwo', 'enum_values': ['value1', 'value2']},
 | 
			
		||||
 {'enum_name': '__org.qemu_x-Enum', 'enum_values': ['__org.qemu_x-value']},
 | 
			
		||||
 {'enum_name': 'UserDefAlternateKind', 'enum_values': None},
 | 
			
		||||
 {'enum_name': 'UserDefNativeListUnionKind', 'enum_values': None},
 | 
			
		||||
 {'enum_name': '__org.qemu_x-Union1Kind', 'enum_values': None},
 | 
			
		||||
 {'enum_name': '__org.qemu_x-AltKind', 'enum_values': None}]
 | 
			
		||||
[OrderedDict([('struct', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]),
 | 
			
		||||
 OrderedDict([('struct', 'UserDefOne'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('*enum1', 'EnumOne')]))]),
 | 
			
		||||
 OrderedDict([('struct', 'UserDefZero'), ('data', OrderedDict([('integer', 'int')]))]),
 | 
			
		||||
 OrderedDict([('struct', 'UserDefTwoDictDict'), ('data', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')]))]),
 | 
			
		||||
 OrderedDict([('struct', 'UserDefTwoDict'), ('data', OrderedDict([('string1', 'str'), ('dict2', 'UserDefTwoDictDict'), ('*dict3', 'UserDefTwoDictDict')]))]),
 | 
			
		||||
 OrderedDict([('struct', 'UserDefTwo'), ('data', OrderedDict([('string0', 'str'), ('dict1', 'UserDefTwoDict')]))]),
 | 
			
		||||
 OrderedDict([('struct', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]),
 | 
			
		||||
 OrderedDict([('struct', 'UserDefB'), ('data', OrderedDict([('intb', 'int')]))]),
 | 
			
		||||
 OrderedDict([('struct', 'UserDefUnionBase'), ('base', 'UserDefZero'), ('data', OrderedDict([('string', 'str'), ('enum1', 'EnumOne')]))]),
 | 
			
		||||
 OrderedDict([('struct', 'UserDefC'), ('data', OrderedDict([('string1', 'str'), ('string2', 'str')]))]),
 | 
			
		||||
 OrderedDict([('struct', 'UserDefOptions'), ('data', OrderedDict([('*i64', ['int']), ('*u64', ['uint64']), ('*u16', ['uint16']), ('*i64x', 'int'), ('*u64x', 'uint64')]))]),
 | 
			
		||||
 OrderedDict([('struct', 'EventStructOne'), ('data', OrderedDict([('struct1', 'UserDefOne'), ('string', 'str'), ('*enum2', 'EnumOne')]))]),
 | 
			
		||||
 OrderedDict([('struct', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member1', '__org.qemu_x-Enum')]))]),
 | 
			
		||||
 OrderedDict([('struct', '__org.qemu_x-Struct'), ('base', '__org.qemu_x-Base'), ('data', OrderedDict([('__org.qemu_x-member2', 'str')]))]),
 | 
			
		||||
 OrderedDict([('struct', '__org.qemu_x-Struct2'), ('data', OrderedDict([('array', ['__org.qemu_x-Union1'])]))])]
 | 
			
		||||
object :empty
 | 
			
		||||
object :obj-EVENT_C-arg
 | 
			
		||||
    member a: int optional=True
 | 
			
		||||
    member b: UserDefOne optional=True
 | 
			
		||||
    member c: str optional=False
 | 
			
		||||
object :obj-EVENT_D-arg
 | 
			
		||||
    member a: EventStructOne optional=False
 | 
			
		||||
    member b: str optional=False
 | 
			
		||||
    member c: str optional=True
 | 
			
		||||
    member enum3: EnumOne optional=True
 | 
			
		||||
object :obj-__org.qemu_x-command-arg
 | 
			
		||||
    member a: __org.qemu_x-EnumList optional=False
 | 
			
		||||
    member b: __org.qemu_x-StructList optional=False
 | 
			
		||||
    member c: __org.qemu_x-Union2 optional=False
 | 
			
		||||
    member d: __org.qemu_x-Alt optional=False
 | 
			
		||||
object :obj-anyList-wrapper
 | 
			
		||||
    member data: anyList optional=False
 | 
			
		||||
object :obj-boolList-wrapper
 | 
			
		||||
    member data: boolList optional=False
 | 
			
		||||
object :obj-guest-sync-arg
 | 
			
		||||
    member arg: any optional=False
 | 
			
		||||
object :obj-int16List-wrapper
 | 
			
		||||
    member data: int16List optional=False
 | 
			
		||||
object :obj-int32List-wrapper
 | 
			
		||||
    member data: int32List optional=False
 | 
			
		||||
object :obj-int64List-wrapper
 | 
			
		||||
    member data: int64List optional=False
 | 
			
		||||
object :obj-int8List-wrapper
 | 
			
		||||
    member data: int8List optional=False
 | 
			
		||||
object :obj-intList-wrapper
 | 
			
		||||
    member data: intList optional=False
 | 
			
		||||
object :obj-numberList-wrapper
 | 
			
		||||
    member data: numberList optional=False
 | 
			
		||||
object :obj-sizeList-wrapper
 | 
			
		||||
    member data: sizeList optional=False
 | 
			
		||||
object :obj-str-wrapper
 | 
			
		||||
    member data: str optional=False
 | 
			
		||||
object :obj-strList-wrapper
 | 
			
		||||
    member data: strList optional=False
 | 
			
		||||
object :obj-uint16List-wrapper
 | 
			
		||||
    member data: uint16List optional=False
 | 
			
		||||
object :obj-uint32List-wrapper
 | 
			
		||||
    member data: uint32List optional=False
 | 
			
		||||
object :obj-uint64List-wrapper
 | 
			
		||||
    member data: uint64List optional=False
 | 
			
		||||
object :obj-uint8List-wrapper
 | 
			
		||||
    member data: uint8List optional=False
 | 
			
		||||
object :obj-user_def_cmd1-arg
 | 
			
		||||
    member ud1a: UserDefOne optional=False
 | 
			
		||||
object :obj-user_def_cmd2-arg
 | 
			
		||||
    member ud1a: UserDefOne optional=False
 | 
			
		||||
    member ud1b: UserDefOne optional=True
 | 
			
		||||
object :obj-user_def_cmd3-arg
 | 
			
		||||
    member a: int optional=False
 | 
			
		||||
    member b: int optional=True
 | 
			
		||||
event EVENT_A None
 | 
			
		||||
event EVENT_B None
 | 
			
		||||
event EVENT_C :obj-EVENT_C-arg
 | 
			
		||||
event EVENT_D :obj-EVENT_D-arg
 | 
			
		||||
enum EnumOne ['value1', 'value2', 'value3']
 | 
			
		||||
object EventStructOne
 | 
			
		||||
    member struct1: UserDefOne optional=False
 | 
			
		||||
    member string: str optional=False
 | 
			
		||||
    member enum2: EnumOne optional=True
 | 
			
		||||
object NestedEnumsOne
 | 
			
		||||
    member enum1: EnumOne optional=False
 | 
			
		||||
    member enum2: EnumOne optional=True
 | 
			
		||||
    member enum3: EnumOne optional=False
 | 
			
		||||
    member enum4: EnumOne optional=True
 | 
			
		||||
enum QEnumTwo ['value1', 'value2']
 | 
			
		||||
    prefix QENUM_TWO
 | 
			
		||||
object UserDefA
 | 
			
		||||
    member boolean: bool optional=False
 | 
			
		||||
alternate UserDefAlternate
 | 
			
		||||
    case uda: UserDefA
 | 
			
		||||
    case s: str
 | 
			
		||||
    case i: int
 | 
			
		||||
enum UserDefAlternateKind ['uda', 's', 'i']
 | 
			
		||||
object UserDefB
 | 
			
		||||
    member intb: int optional=False
 | 
			
		||||
object UserDefC
 | 
			
		||||
    member string1: str optional=False
 | 
			
		||||
    member string2: str optional=False
 | 
			
		||||
object UserDefFlatUnion
 | 
			
		||||
    base UserDefUnionBase
 | 
			
		||||
    tag enum1
 | 
			
		||||
    case value1: UserDefA
 | 
			
		||||
    case value2: UserDefB
 | 
			
		||||
    case value3: UserDefB
 | 
			
		||||
object UserDefFlatUnion2
 | 
			
		||||
    base UserDefUnionBase
 | 
			
		||||
    tag enum1
 | 
			
		||||
    case value1: UserDefC
 | 
			
		||||
    case value2: UserDefB
 | 
			
		||||
    case value3: UserDefA
 | 
			
		||||
object UserDefNativeListUnion
 | 
			
		||||
    case integer: :obj-intList-wrapper
 | 
			
		||||
    case s8: :obj-int8List-wrapper
 | 
			
		||||
    case s16: :obj-int16List-wrapper
 | 
			
		||||
    case s32: :obj-int32List-wrapper
 | 
			
		||||
    case s64: :obj-int64List-wrapper
 | 
			
		||||
    case u8: :obj-uint8List-wrapper
 | 
			
		||||
    case u16: :obj-uint16List-wrapper
 | 
			
		||||
    case u32: :obj-uint32List-wrapper
 | 
			
		||||
    case u64: :obj-uint64List-wrapper
 | 
			
		||||
    case number: :obj-numberList-wrapper
 | 
			
		||||
    case boolean: :obj-boolList-wrapper
 | 
			
		||||
    case string: :obj-strList-wrapper
 | 
			
		||||
    case sizes: :obj-sizeList-wrapper
 | 
			
		||||
    case any: :obj-anyList-wrapper
 | 
			
		||||
enum UserDefNativeListUnionKind ['integer', 's8', 's16', 's32', 's64', 'u8', 'u16', 'u32', 'u64', 'number', 'boolean', 'string', 'sizes', 'any']
 | 
			
		||||
object UserDefOne
 | 
			
		||||
    base UserDefZero
 | 
			
		||||
    member string: str optional=False
 | 
			
		||||
    member enum1: EnumOne optional=True
 | 
			
		||||
object UserDefOptions
 | 
			
		||||
    member i64: intList optional=True
 | 
			
		||||
    member u64: uint64List optional=True
 | 
			
		||||
    member u16: uint16List optional=True
 | 
			
		||||
    member i64x: int optional=True
 | 
			
		||||
    member u64x: uint64 optional=True
 | 
			
		||||
object UserDefTwo
 | 
			
		||||
    member string0: str optional=False
 | 
			
		||||
    member dict1: UserDefTwoDict optional=False
 | 
			
		||||
object UserDefTwoDict
 | 
			
		||||
    member string1: str optional=False
 | 
			
		||||
    member dict2: UserDefTwoDictDict optional=False
 | 
			
		||||
    member dict3: UserDefTwoDictDict optional=True
 | 
			
		||||
object UserDefTwoDictDict
 | 
			
		||||
    member userdef: UserDefOne optional=False
 | 
			
		||||
    member string: str optional=False
 | 
			
		||||
object UserDefUnionBase
 | 
			
		||||
    base UserDefZero
 | 
			
		||||
    member string: str optional=False
 | 
			
		||||
    member enum1: EnumOne optional=False
 | 
			
		||||
object UserDefZero
 | 
			
		||||
    member integer: int optional=False
 | 
			
		||||
event __ORG.QEMU_X-EVENT __org.qemu_x-Struct
 | 
			
		||||
alternate __org.qemu_x-Alt
 | 
			
		||||
    case __org.qemu_x-branch: str
 | 
			
		||||
    case b: __org.qemu_x-Base
 | 
			
		||||
enum __org.qemu_x-AltKind ['__org.qemu_x-branch', 'b']
 | 
			
		||||
object __org.qemu_x-Base
 | 
			
		||||
    member __org.qemu_x-member1: __org.qemu_x-Enum optional=False
 | 
			
		||||
enum __org.qemu_x-Enum ['__org.qemu_x-value']
 | 
			
		||||
object __org.qemu_x-Struct
 | 
			
		||||
    base __org.qemu_x-Base
 | 
			
		||||
    member __org.qemu_x-member2: str optional=False
 | 
			
		||||
object __org.qemu_x-Struct2
 | 
			
		||||
    member array: __org.qemu_x-Union1List optional=False
 | 
			
		||||
object __org.qemu_x-Union1
 | 
			
		||||
    case __org.qemu_x-branch: :obj-str-wrapper
 | 
			
		||||
enum __org.qemu_x-Union1Kind ['__org.qemu_x-branch']
 | 
			
		||||
object __org.qemu_x-Union2
 | 
			
		||||
    base __org.qemu_x-Base
 | 
			
		||||
    tag __org.qemu_x-member1
 | 
			
		||||
    case __org.qemu_x-value: __org.qemu_x-Struct2
 | 
			
		||||
command __org.qemu_x-command :obj-__org.qemu_x-command-arg -> __org.qemu_x-Union1
 | 
			
		||||
   gen=True success_response=True
 | 
			
		||||
command guest-sync :obj-guest-sync-arg -> any
 | 
			
		||||
   gen=True success_response=True
 | 
			
		||||
command user_def_cmd None -> None
 | 
			
		||||
   gen=True success_response=True
 | 
			
		||||
command user_def_cmd1 :obj-user_def_cmd1-arg -> None
 | 
			
		||||
   gen=True success_response=True
 | 
			
		||||
command user_def_cmd2 :obj-user_def_cmd2-arg -> UserDefTwo
 | 
			
		||||
   gen=True success_response=True
 | 
			
		||||
command user_def_cmd3 :obj-user_def_cmd3-arg -> int
 | 
			
		||||
   gen=True success_response=True
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,3 @@
 | 
			
		||||
[OrderedDict([('command', 'guest-get-time'), ('returns', 'int')])]
 | 
			
		||||
[]
 | 
			
		||||
[]
 | 
			
		||||
object :empty
 | 
			
		||||
command guest-get-time None -> int
 | 
			
		||||
   gen=True success_response=True
 | 
			
		||||
 | 
			
		||||
@ -15,11 +15,42 @@ from pprint import pprint
 | 
			
		||||
import os
 | 
			
		||||
import sys
 | 
			
		||||
 | 
			
		||||
try:
 | 
			
		||||
    exprs = parse_schema(sys.argv[1])
 | 
			
		||||
except SystemExit:
 | 
			
		||||
    raise
 | 
			
		||||
 | 
			
		||||
pprint(exprs)
 | 
			
		||||
pprint(enum_types)
 | 
			
		||||
pprint(struct_types)
 | 
			
		||||
class QAPISchemaTestVisitor(QAPISchemaVisitor):
 | 
			
		||||
    def visit_enum_type(self, name, info, values, prefix):
 | 
			
		||||
        print 'enum %s %s' % (name, values)
 | 
			
		||||
        if prefix:
 | 
			
		||||
            print '    prefix %s' % prefix
 | 
			
		||||
 | 
			
		||||
    def visit_object_type(self, name, info, base, members, variants):
 | 
			
		||||
        print 'object %s' % name
 | 
			
		||||
        if base:
 | 
			
		||||
            print '    base %s' % base.name
 | 
			
		||||
        for m in members:
 | 
			
		||||
            print '    member %s: %s optional=%s' % \
 | 
			
		||||
                (m.name, m.type.name, m.optional)
 | 
			
		||||
        self._print_variants(variants)
 | 
			
		||||
 | 
			
		||||
    def visit_alternate_type(self, name, info, variants):
 | 
			
		||||
        print 'alternate %s' % name
 | 
			
		||||
        self._print_variants(variants)
 | 
			
		||||
 | 
			
		||||
    def visit_command(self, name, info, arg_type, ret_type,
 | 
			
		||||
                      gen, success_response):
 | 
			
		||||
        print 'command %s %s -> %s' % \
 | 
			
		||||
            (name, arg_type and arg_type.name, ret_type and ret_type.name)
 | 
			
		||||
        print '   gen=%s success_response=%s' % (gen, success_response)
 | 
			
		||||
 | 
			
		||||
    def visit_event(self, name, info, arg_type):
 | 
			
		||||
        print 'event %s %s' % (name, arg_type and arg_type.name)
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def _print_variants(variants):
 | 
			
		||||
        if variants:
 | 
			
		||||
            if variants.tag_name:
 | 
			
		||||
                print '    tag %s' % variants.tag_name
 | 
			
		||||
            for v in variants.variants:
 | 
			
		||||
                print '    case %s: %s' % (v.name, v.type.name)
 | 
			
		||||
 | 
			
		||||
schema = QAPISchema(sys.argv[1])
 | 
			
		||||
schema.visit(QAPISchemaTestVisitor())
 | 
			
		||||
 | 
			
		||||
@ -1 +0,0 @@
 | 
			
		||||
tests/qapi-schema/type-bypass-no-gen.json:2: Member 'arg' of 'data' for command 'unsafe' uses '**' but did not request 'gen':false
 | 
			
		||||
@ -1,2 +0,0 @@
 | 
			
		||||
# type bypass only works with 'gen':false
 | 
			
		||||
{ 'command': 'unsafe', 'data': { 'arg': '**' }, 'returns': '**' }
 | 
			
		||||
@ -1 +0,0 @@
 | 
			
		||||
0
 | 
			
		||||
@ -1,2 +0,0 @@
 | 
			
		||||
# Use of 'gen':false allows bypassing type system
 | 
			
		||||
{ 'command': 'unsafe', 'data': { 'arg': '**' }, 'returns': '**', 'gen': false }
 | 
			
		||||
@ -1,3 +0,0 @@
 | 
			
		||||
[OrderedDict([('command', 'unsafe'), ('data', OrderedDict([('arg', '**')])), ('returns', '**'), ('gen', False)])]
 | 
			
		||||
[]
 | 
			
		||||
[]
 | 
			
		||||
@ -51,6 +51,11 @@ int64_t qmp_user_def_cmd3(int64_t a, bool has_b, int64_t b, Error **errp)
 | 
			
		||||
    return a + (has_b ? b : 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QObject *qmp_guest_sync(QObject *arg, Error **errp)
 | 
			
		||||
{
 | 
			
		||||
    return arg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
__org_qemu_x_Union1 *qmp___org_qemu_x_command(__org_qemu_x_EnumList *a,
 | 
			
		||||
                                              __org_qemu_x_StructList *b,
 | 
			
		||||
                                              __org_qemu_x_Union2 *c,
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,9 @@
 | 
			
		||||
#include "test-qapi-types.h"
 | 
			
		||||
#include "test-qapi-visit.h"
 | 
			
		||||
#include "qapi/qmp/types.h"
 | 
			
		||||
#include "test-qmp-introspect.h"
 | 
			
		||||
#include "qmp-introspect.h"
 | 
			
		||||
#include "qapi-visit.h"
 | 
			
		||||
 | 
			
		||||
typedef struct TestInputVisitorData {
 | 
			
		||||
    QObject *obj;
 | 
			
		||||
@ -62,6 +65,30 @@ Visitor *validate_test_init(TestInputVisitorData *data,
 | 
			
		||||
    return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* similar to validate_test_init(), but does not expect a string
 | 
			
		||||
 * literal/format json_string argument and so can be used for
 | 
			
		||||
 * programatically generated strings (and we can't pass in programatically
 | 
			
		||||
 * generated strings via %s format parameters since qobject_from_jsonv()
 | 
			
		||||
 * will wrap those in double-quotes and treat the entire object as a
 | 
			
		||||
 * string)
 | 
			
		||||
 */
 | 
			
		||||
static Visitor *validate_test_init_raw(TestInputVisitorData *data,
 | 
			
		||||
                                       const char *json_string)
 | 
			
		||||
{
 | 
			
		||||
    Visitor *v;
 | 
			
		||||
 | 
			
		||||
    data->obj = qobject_from_json(json_string);
 | 
			
		||||
    g_assert(data->obj != NULL);
 | 
			
		||||
 | 
			
		||||
    data->qiv = qmp_input_visitor_new_strict(data->obj);
 | 
			
		||||
    g_assert(data->qiv != NULL);
 | 
			
		||||
 | 
			
		||||
    v = qmp_input_get_visitor(data->qiv);
 | 
			
		||||
    g_assert(v != NULL);
 | 
			
		||||
 | 
			
		||||
    return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct TestStruct
 | 
			
		||||
{
 | 
			
		||||
    int64_t integer;
 | 
			
		||||
@ -167,9 +194,9 @@ static void test_validate_union_flat(TestInputVisitorData *data,
 | 
			
		||||
 | 
			
		||||
    v = validate_test_init(data,
 | 
			
		||||
                           "{ 'enum1': 'value1', "
 | 
			
		||||
                           "'integer': 41, "
 | 
			
		||||
                           "'string': 'str', "
 | 
			
		||||
                           "'boolean': true }");
 | 
			
		||||
    /* TODO when generator bug is fixed, add 'integer': 41 */
 | 
			
		||||
 | 
			
		||||
    visit_type_UserDefFlatUnion(v, &tmp, NULL, &err);
 | 
			
		||||
    g_assert(!err);
 | 
			
		||||
@ -272,7 +299,7 @@ static void test_validate_fail_union_flat_no_discrim(TestInputVisitorData *data,
 | 
			
		||||
    Visitor *v;
 | 
			
		||||
 | 
			
		||||
    /* test situation where discriminator field ('enum1' here) is missing */
 | 
			
		||||
    v = validate_test_init(data, "{ 'string': 'c', 'string1': 'd', 'string2': 'e' }");
 | 
			
		||||
    v = validate_test_init(data, "{ 'integer': 42, 'string': 'c', 'string1': 'd', 'string2': 'e' }");
 | 
			
		||||
 | 
			
		||||
    visit_type_UserDefFlatUnion2(v, &tmp, NULL, &err);
 | 
			
		||||
    g_assert(err);
 | 
			
		||||
@ -293,6 +320,32 @@ static void test_validate_fail_alternate(TestInputVisitorData *data,
 | 
			
		||||
    qapi_free_UserDefAlternate(tmp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void do_test_validate_qmp_introspect(TestInputVisitorData *data,
 | 
			
		||||
                                            const char *schema_json)
 | 
			
		||||
{
 | 
			
		||||
    SchemaInfoList *schema = NULL;
 | 
			
		||||
    Error *err = NULL;
 | 
			
		||||
    Visitor *v;
 | 
			
		||||
 | 
			
		||||
    v = validate_test_init_raw(data, schema_json);
 | 
			
		||||
 | 
			
		||||
    visit_type_SchemaInfoList(v, &schema, NULL, &err);
 | 
			
		||||
    if (err) {
 | 
			
		||||
        fprintf(stderr, "%s", error_get_pretty(err));
 | 
			
		||||
    }
 | 
			
		||||
    g_assert(!err);
 | 
			
		||||
    g_assert(schema);
 | 
			
		||||
 | 
			
		||||
    qapi_free_SchemaInfoList(schema);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void test_validate_qmp_introspect(TestInputVisitorData *data,
 | 
			
		||||
                                           const void *unused)
 | 
			
		||||
{
 | 
			
		||||
    do_test_validate_qmp_introspect(data, test_qmp_schema_json);
 | 
			
		||||
    do_test_validate_qmp_introspect(data, qmp_schema_json);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void validate_test_add(const char *testpath,
 | 
			
		||||
                               TestInputVisitorData *data,
 | 
			
		||||
                               void (*test_func)(TestInputVisitorData *data, const void *user_data))
 | 
			
		||||
@ -333,6 +386,8 @@ int main(int argc, char **argv)
 | 
			
		||||
                      &testdata, test_validate_fail_alternate);
 | 
			
		||||
    validate_test_add("/visitor/input-strict/fail/union-native-list",
 | 
			
		||||
                      &testdata, test_validate_fail_union_native_list);
 | 
			
		||||
    validate_test_add("/visitor/input-strict/pass/qmp-introspect",
 | 
			
		||||
                      &testdata, test_validate_qmp_introspect);
 | 
			
		||||
 | 
			
		||||
    g_test_run();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -298,6 +298,49 @@ static void test_visitor_in_list(TestInputVisitorData *data,
 | 
			
		||||
    qapi_free_UserDefOneList(head);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void test_visitor_in_any(TestInputVisitorData *data,
 | 
			
		||||
                                const void *unused)
 | 
			
		||||
{
 | 
			
		||||
    QObject *res = NULL;
 | 
			
		||||
    Error *err = NULL;
 | 
			
		||||
    Visitor *v;
 | 
			
		||||
    QInt *qint;
 | 
			
		||||
    QBool *qbool;
 | 
			
		||||
    QString *qstring;
 | 
			
		||||
    QDict *qdict;
 | 
			
		||||
    QObject *qobj;
 | 
			
		||||
 | 
			
		||||
    v = visitor_input_test_init(data, "-42");
 | 
			
		||||
    visit_type_any(v, &res, NULL, &err);
 | 
			
		||||
    g_assert(!err);
 | 
			
		||||
    qint = qobject_to_qint(res);
 | 
			
		||||
    g_assert(qint);
 | 
			
		||||
    g_assert_cmpint(qint_get_int(qint), ==, -42);
 | 
			
		||||
    qobject_decref(res);
 | 
			
		||||
 | 
			
		||||
    v = visitor_input_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }");
 | 
			
		||||
    visit_type_any(v, &res, NULL, &err);
 | 
			
		||||
    g_assert(!err);
 | 
			
		||||
    qdict = qobject_to_qdict(res);
 | 
			
		||||
    g_assert(qdict && qdict_size(qdict) == 3);
 | 
			
		||||
    qobj = qdict_get(qdict, "integer");
 | 
			
		||||
    g_assert(qobj);
 | 
			
		||||
    qint = qobject_to_qint(qobj);
 | 
			
		||||
    g_assert(qint);
 | 
			
		||||
    g_assert_cmpint(qint_get_int(qint), ==, -42);
 | 
			
		||||
    qobj = qdict_get(qdict, "boolean");
 | 
			
		||||
    g_assert(qobj);
 | 
			
		||||
    qbool = qobject_to_qbool(qobj);
 | 
			
		||||
    g_assert(qbool);
 | 
			
		||||
    g_assert(qbool_get_bool(qbool) == true);
 | 
			
		||||
    qobj = qdict_get(qdict, "string");
 | 
			
		||||
    g_assert(qobj);
 | 
			
		||||
    qstring = qobject_to_qstring(qobj);
 | 
			
		||||
    g_assert(qstring);
 | 
			
		||||
    g_assert_cmpstr(qstring_get_str(qstring), ==, "foo");
 | 
			
		||||
    qobject_decref(res);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void test_visitor_in_union_flat(TestInputVisitorData *data,
 | 
			
		||||
                                       const void *unused)
 | 
			
		||||
{
 | 
			
		||||
@ -307,15 +350,15 @@ static void test_visitor_in_union_flat(TestInputVisitorData *data,
 | 
			
		||||
 | 
			
		||||
    v = visitor_input_test_init(data,
 | 
			
		||||
                                "{ 'enum1': 'value1', "
 | 
			
		||||
                                "'integer': 41, "
 | 
			
		||||
                                "'string': 'str', "
 | 
			
		||||
                                "'boolean': true }");
 | 
			
		||||
    /* TODO when generator bug is fixed, add 'integer': 41 */
 | 
			
		||||
 | 
			
		||||
    visit_type_UserDefFlatUnion(v, &tmp, NULL, &err);
 | 
			
		||||
    g_assert(err == NULL);
 | 
			
		||||
    g_assert_cmpint(tmp->enum1, ==, ENUM_ONE_VALUE1);
 | 
			
		||||
    g_assert_cmpstr(tmp->string, ==, "str");
 | 
			
		||||
    /* TODO g_assert_cmpint(tmp->integer, ==, 41); */
 | 
			
		||||
    g_assert_cmpint(tmp->integer, ==, 41);
 | 
			
		||||
    g_assert_cmpint(tmp->value1->boolean, ==, true);
 | 
			
		||||
    qapi_free_UserDefFlatUnion(tmp);
 | 
			
		||||
}
 | 
			
		||||
@ -669,6 +712,8 @@ int main(int argc, char **argv)
 | 
			
		||||
                           &in_visitor_data, test_visitor_in_struct_nested);
 | 
			
		||||
    input_visitor_test_add("/visitor/input/list",
 | 
			
		||||
                           &in_visitor_data, test_visitor_in_list);
 | 
			
		||||
    input_visitor_test_add("/visitor/input/any",
 | 
			
		||||
                           &in_visitor_data, test_visitor_in_any);
 | 
			
		||||
    input_visitor_test_add("/visitor/input/union-flat",
 | 
			
		||||
                           &in_visitor_data, test_visitor_in_union_flat);
 | 
			
		||||
    input_visitor_test_add("/visitor/input/alternate",
 | 
			
		||||
 | 
			
		||||
@ -428,6 +428,57 @@ static void test_visitor_out_list_qapi_free(TestOutputVisitorData *data,
 | 
			
		||||
    qapi_free_UserDefTwoList(head);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void test_visitor_out_any(TestOutputVisitorData *data,
 | 
			
		||||
                                 const void *unused)
 | 
			
		||||
{
 | 
			
		||||
    QObject *qobj;
 | 
			
		||||
    Error *err = NULL;
 | 
			
		||||
    QInt *qint;
 | 
			
		||||
    QBool *qbool;
 | 
			
		||||
    QString *qstring;
 | 
			
		||||
    QDict *qdict;
 | 
			
		||||
    QObject *obj;
 | 
			
		||||
 | 
			
		||||
    qobj = QOBJECT(qint_from_int(-42));
 | 
			
		||||
    visit_type_any(data->ov, &qobj, NULL, &err);
 | 
			
		||||
    g_assert(!err);
 | 
			
		||||
    obj = qmp_output_get_qobject(data->qov);
 | 
			
		||||
    g_assert(obj != NULL);
 | 
			
		||||
    g_assert(qobject_type(obj) == QTYPE_QINT);
 | 
			
		||||
    g_assert_cmpint(qint_get_int(qobject_to_qint(obj)), ==, -42);
 | 
			
		||||
    qobject_decref(obj);
 | 
			
		||||
    qobject_decref(qobj);
 | 
			
		||||
 | 
			
		||||
    qdict = qdict_new();
 | 
			
		||||
    qdict_put(qdict, "integer", qint_from_int(-42));
 | 
			
		||||
    qdict_put(qdict, "boolean", qbool_from_bool(true));
 | 
			
		||||
    qdict_put(qdict, "string", qstring_from_str("foo"));
 | 
			
		||||
    qobj = QOBJECT(qdict);
 | 
			
		||||
    visit_type_any(data->ov, &qobj, NULL, &err);
 | 
			
		||||
    g_assert(!err);
 | 
			
		||||
    obj = qmp_output_get_qobject(data->qov);
 | 
			
		||||
    g_assert(obj != NULL);
 | 
			
		||||
    qdict = qobject_to_qdict(obj);
 | 
			
		||||
    g_assert(qdict);
 | 
			
		||||
    qobj = qdict_get(qdict, "integer");
 | 
			
		||||
    g_assert(qobj);
 | 
			
		||||
    qint = qobject_to_qint(qobj);
 | 
			
		||||
    g_assert(qint);
 | 
			
		||||
    g_assert_cmpint(qint_get_int(qint), ==, -42);
 | 
			
		||||
    qobj = qdict_get(qdict, "boolean");
 | 
			
		||||
    g_assert(qobj);
 | 
			
		||||
    qbool = qobject_to_qbool(qobj);
 | 
			
		||||
    g_assert(qbool);
 | 
			
		||||
    g_assert(qbool_get_bool(qbool) == true);
 | 
			
		||||
    qobj = qdict_get(qdict, "string");
 | 
			
		||||
    g_assert(qobj);
 | 
			
		||||
    qstring = qobject_to_qstring(qobj);
 | 
			
		||||
    g_assert(qstring);
 | 
			
		||||
    g_assert_cmpstr(qstring_get_str(qstring), ==, "foo");
 | 
			
		||||
    qobject_decref(obj);
 | 
			
		||||
    qobject_decref(qobj);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void test_visitor_out_union_flat(TestOutputVisitorData *data,
 | 
			
		||||
                                        const void *unused)
 | 
			
		||||
{
 | 
			
		||||
@ -485,7 +536,8 @@ static void test_visitor_out_empty(TestOutputVisitorData *data,
 | 
			
		||||
    QObject *arg;
 | 
			
		||||
 | 
			
		||||
    arg = qmp_output_get_qobject(data->qov);
 | 
			
		||||
    g_assert(!arg);
 | 
			
		||||
    g_assert(qobject_type(arg) == QTYPE_QNULL);
 | 
			
		||||
    qobject_decref(arg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void init_native_list(UserDefNativeListUnion *cvalue)
 | 
			
		||||
@ -832,6 +884,8 @@ int main(int argc, char **argv)
 | 
			
		||||
                            &out_visitor_data, test_visitor_out_struct_errors);
 | 
			
		||||
    output_visitor_test_add("/visitor/output/list",
 | 
			
		||||
                            &out_visitor_data, test_visitor_out_list);
 | 
			
		||||
    output_visitor_test_add("/visitor/output/any",
 | 
			
		||||
                            &out_visitor_data, test_visitor_out_any);
 | 
			
		||||
    output_visitor_test_add("/visitor/output/list-qapi-free",
 | 
			
		||||
                            &out_visitor_data, test_visitor_out_list_qapi_free);
 | 
			
		||||
    output_visitor_test_add("/visitor/output/union-flat",
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user