All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v3 00/14] qapi doc generation (whole version, squashed)
@ 2016-11-07  7:30 Marc-André Lureau
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 01/14] qapi: add missing 'bus' argument in device_add Marc-André Lureau
                   ` (13 more replies)
  0 siblings, 14 replies; 28+ messages in thread
From: Marc-André Lureau @ 2016-11-07  7:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

Add a qapi2texi script to generate the documentation from the qapi
schemas.

The 13th patch in this series is a squashed version of the
documentation move from qmp-commands.txt to the schemas. The whole
version (not sent on the ML to avoid spamming) is in the following git
branch: https://github.com/elmarco/qemu/commits/qapi-doc

v3:
- many improvements to the doc parser:
  - throws an error in various malformated conditions
  - allows multiple meta-sections, except for "Since:" and "Return:"
  - build a list of docs, instead of attaching docs to expressions
  - accept() breaks on new doc block, and get_doc() returns a QAPIDoc
- fix more documentation to fit the new parser
- use a master texi file that includes the generated file, instead of
  templated texi file
- texi fixes after Markus review
- only build and install html and man pages by default
- fix .gitignore

v2:
- change licence to be lgpl2+
- fix some comments & commit message
- add more code comments
- improve the doc parsing to treat only "Since" as a special case not
  requiring ":" (common notation in the doc)
- include some early schema doc fixes (to fix generated doc)
- include the squashed version of the doc move
- include the man page and installation build changes

Marc-André Lureau (14):
  qapi: add missing 'bus' argument in device_add
  qga/schema: fix double-return in doc
  qga/schema: improve guest-set-vcpus Returns: section
  qapi: fix schema symbol sections
  qapi: fix missing symbol @prefix
  qapi: fix various symbols mismatch in documentation
  qapi: use one symbol per line
  qapi: add missing colon-ending for section name
  qapi: add some sections in docs
  docs: add master qapi texi files
  qapi: add qapi2texi script
  texi2pod: learn quotation, deftp and deftypefn
  qmp-commands: (SQUASHED) move doc to schema
  build-sys: add qapi doc generation targets

 Makefile                      |   57 +-
 scripts/qapi.py               |  175 +-
 scripts/qapi2texi.py          |  316 ++++
 scripts/texi2pod.pl           |   44 +-
 .gitignore                    |   11 +-
 docs/qapi-code-gen.txt        |   44 +-
 docs/qemu-ga-ref.texi         |   65 +
 docs/qemu-qmp-ref.texi        |  156 ++
 docs/qmp-commands.txt         | 3824 -----------------------------------------
 docs/qmp-events.txt           |  731 --------
 docs/qmp-intro.txt            |   87 -
 docs/writing-qmp-commands.txt |    2 +-
 qapi-schema.json              | 1621 +++++++++++++++--
 qapi/block-core.json          |  894 ++++++++--
 qapi/block.json               |   82 +-
 qapi/common.json              |   52 +-
 qapi/crypto.json              |   41 +-
 qapi/event.json               |  304 +++-
 qapi/introspect.json          |   28 +-
 qapi/rocker.json              |   63 +-
 qapi/trace.json               |   25 +-
 qga/qapi-schema.json          |   64 +-
 22 files changed, 3583 insertions(+), 5103 deletions(-)
 create mode 100755 scripts/qapi2texi.py
 create mode 100644 docs/qemu-ga-ref.texi
 create mode 100644 docs/qemu-qmp-ref.texi
 delete mode 100644 docs/qmp-commands.txt
 delete mode 100644 docs/qmp-events.txt
 delete mode 100644 docs/qmp-intro.txt

-- 
2.10.0

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [Qemu-devel] [PATCH v3 01/14] qapi: add missing 'bus' argument in device_add
  2016-11-07  7:30 [Qemu-devel] [PATCH v3 00/14] qapi doc generation (whole version, squashed) Marc-André Lureau
@ 2016-11-07  7:30 ` Marc-André Lureau
  2016-11-07 15:10   ` Markus Armbruster
  2016-11-07 22:55   ` Eric Blake
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 02/14] qga/schema: fix double-return in doc Marc-André Lureau
                   ` (12 subsequent siblings)
  13 siblings, 2 replies; 28+ messages in thread
From: Marc-André Lureau @ 2016-11-07  7:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

'device_add' is incomplete for now, but 'bus' is a common argument for
regarless of the device, and is present in documentation. Add it to the
device_add schema definition.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi-schema.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/qapi-schema.json b/qapi-schema.json
index b0b4bf6..4ba5772 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2317,7 +2317,7 @@
 # Since: 0.13
 ##
 { 'command': 'device_add',
-  'data': {'driver': 'str', 'id': 'str'},
+  'data': {'driver': 'str', '*bus': 'str', 'id': 'str'},
   'gen': false } # so we can get the additional arguments
 
 ##
-- 
2.10.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Qemu-devel] [PATCH v3 02/14] qga/schema: fix double-return in doc
  2016-11-07  7:30 [Qemu-devel] [PATCH v3 00/14] qapi doc generation (whole version, squashed) Marc-André Lureau
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 01/14] qapi: add missing 'bus' argument in device_add Marc-André Lureau
@ 2016-11-07  7:30 ` Marc-André Lureau
  2016-11-07 22:59   ` Eric Blake
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 03/14] qga/schema: improve guest-set-vcpus Returns: section Marc-André Lureau
                   ` (11 subsequent siblings)
  13 siblings, 1 reply; 28+ messages in thread
From: Marc-André Lureau @ 2016-11-07  7:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

guest-get-memory-block-info documentation should have only one
"Returns:".

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qga/qapi-schema.json | 1 -
 1 file changed, 1 deletion(-)

diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index c21f308..758803a 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -952,7 +952,6 @@
 #
 # Get information relating to guest memory blocks.
 #
-# Returns: memory block size in bytes.
 # Returns: @GuestMemoryBlockInfo
 #
 # Since 2.3
-- 
2.10.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Qemu-devel] [PATCH v3 03/14] qga/schema: improve guest-set-vcpus Returns: section
  2016-11-07  7:30 [Qemu-devel] [PATCH v3 00/14] qapi doc generation (whole version, squashed) Marc-André Lureau
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 01/14] qapi: add missing 'bus' argument in device_add Marc-André Lureau
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 02/14] qga/schema: fix double-return in doc Marc-André Lureau
@ 2016-11-07  7:30 ` Marc-André Lureau
  2016-11-07 15:25   ` Markus Armbruster
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 04/14] qapi: fix schema symbol sections Marc-André Lureau
                   ` (10 subsequent siblings)
  13 siblings, 1 reply; 28+ messages in thread
From: Marc-André Lureau @ 2016-11-07  7:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

The documentation parser finishes a section after an empty line. Fix the
Returns: section of guest-set-vcpus, and itemize the possible return
values.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qga/qapi-schema.json | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 758803a..cb68c17 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -696,22 +696,18 @@
 #
 # Returns: The length of the initial sublist that has been successfully
 #          processed. The guest agent maximizes this value. Possible cases:
-#
-#          0:                if the @vcpus list was empty on input. Guest state
+#          - 0:              if the @vcpus list was empty on input. Guest state
 #                            has not been changed. Otherwise,
-#
-#          Error:            processing the first node of @vcpus failed for the
+#          - Error:          processing the first node of @vcpus failed for the
 #                            reason returned. Guest state has not been changed.
 #                            Otherwise,
-#
-#          < length(@vcpus): more than zero initial nodes have been processed,
+#          - < length(@vcpus): more than zero initial nodes have been processed,
 #                            but not the entire @vcpus list. Guest state has
 #                            changed accordingly. To retrieve the error
 #                            (assuming it persists), repeat the call with the
 #                            successfully processed initial sublist removed.
 #                            Otherwise,
-#
-#          length(@vcpus):   call successful.
+#          - length(@vcpus): call successful.
 #
 # Since: 1.5
 ##
-- 
2.10.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Qemu-devel] [PATCH v3 04/14] qapi: fix schema symbol sections
  2016-11-07  7:30 [Qemu-devel] [PATCH v3 00/14] qapi doc generation (whole version, squashed) Marc-André Lureau
                   ` (2 preceding siblings ...)
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 03/14] qga/schema: improve guest-set-vcpus Returns: section Marc-André Lureau
@ 2016-11-07  7:30 ` Marc-André Lureau
  2016-11-07 23:07   ` Eric Blake
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 05/14] qapi: fix missing symbol @prefix Marc-André Lureau
                   ` (9 subsequent siblings)
  13 siblings, 1 reply; 28+ messages in thread
From: Marc-André Lureau @ 2016-11-07  7:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

According to docs/qapi-code-gen.txt, there needs to be '##' to start a
and end a symbol section, that's also what the documentation parser
expects.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi-schema.json     | 18 +++++++++++++-----
 qapi/block-core.json |  1 +
 qga/qapi-schema.json |  3 +++
 3 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/qapi-schema.json b/qapi-schema.json
index 4ba5772..1d8ad72 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -65,6 +65,7 @@
 { 'enum': 'LostTickPolicy',
   'data': ['discard', 'delay', 'merge', 'slew' ] }
 
+##
 # @add_client
 #
 # Allow client connections for VNC, Spice and socket based
@@ -442,6 +443,7 @@
            'cache-miss': 'int', 'cache-miss-rate': 'number',
            'overflow': 'int' } }
 
+##
 # @MigrationStatus:
 #
 # An enumeration of migration status.
@@ -627,6 +629,7 @@
 ##
 { 'command': 'query-migrate-capabilities', 'returns':   ['MigrationCapabilityStatus']}
 
+##
 # @MigrationParameter
 #
 # Migration parameters enumeration
@@ -685,7 +688,7 @@
            'tls-creds', 'tls-hostname', 'max-bandwidth',
            'downtime-limit', 'x-checkpoint-delay' ] }
 
-#
+##
 # @migrate-set-parameters
 #
 # Set various migration parameters.  See MigrationParameters for details.
@@ -697,7 +700,7 @@
 { 'command': 'migrate-set-parameters', 'boxed': true,
   'data': 'MigrationParameters' }
 
-#
+##
 # @MigrationParameters
 #
 # Optional members can be omitted on input ('migrate-set-parameters')
@@ -795,6 +798,7 @@
 # command.
 #
 # Since: 2.5
+##
 { 'command': 'migrate-start-postcopy' }
 
 ##
@@ -2252,6 +2256,7 @@
 ##
 { 'command': 'migrate-incoming', 'data': {'uri': 'str' } }
 
+##
 # @xen-save-devices-state:
 #
 # Save the state of all devices to file. The RAM and the block devices
@@ -3482,6 +3487,7 @@
             'modelb': 'CpuModelInfo' },
   'returns': 'CpuModelBaselineInfo' }
 
+##
 # @AddfdInfo:
 #
 # Information about a file descriptor that was added to an fd set.
@@ -4530,14 +4536,16 @@
 ##
 { 'command': 'query-memory-devices', 'returns': ['MemoryDeviceInfo'] }
 
-## @ACPISlotType
+##
+# @ACPISlotType
 #
 # @DIMM: memory slot
 # @CPU: logical CPU slot (since 2.7)
-#
+##
 { 'enum': 'ACPISlotType', 'data': [ 'DIMM', 'CPU' ] }
 
-## @ACPIOSTInfo
+##
+# @ACPIOSTInfo
 #
 # OSPM Status Indication for a device
 # For description of possible values of @source and @status fields
diff --git a/qapi/block-core.json b/qapi/block-core.json
index bcd3b9e..5108b42 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -2810,6 +2810,7 @@
             'offset': 'int',
             'speed' : 'int' } }
 
+##
 # @PreallocMode
 #
 # Preallocation mode of QEMU image file
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index cb68c17..5173c4a 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -833,6 +833,7 @@
 { 'command': 'guest-set-user-password',
   'data': { 'username': 'str', 'password': 'str', 'crypted': 'bool' } }
 
+##
 # @GuestMemoryBlock:
 #
 # @phys-index: Arbitrary guest-specific unique identifier of the MEMORY BLOCK.
@@ -932,6 +933,7 @@
   'data':    {'mem-blks': ['GuestMemoryBlock'] },
   'returns': ['GuestMemoryBlockResponse'] }
 
+##
 # @GuestMemoryBlockInfo:
 #
 # @size: the size (in bytes) of the guest memory blocks,
@@ -955,6 +957,7 @@
 { 'command': 'guest-get-memory-block-info',
   'returns': 'GuestMemoryBlockInfo' }
 
+##
 # @GuestExecStatus:
 #
 # @exited: true if process has already terminated.
-- 
2.10.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Qemu-devel] [PATCH v3 05/14] qapi: fix missing symbol @prefix
  2016-11-07  7:30 [Qemu-devel] [PATCH v3 00/14] qapi doc generation (whole version, squashed) Marc-André Lureau
                   ` (3 preceding siblings ...)
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 04/14] qapi: fix schema symbol sections Marc-André Lureau
@ 2016-11-07  7:30 ` Marc-André Lureau
  2016-11-07 23:08   ` Eric Blake
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 06/14] qapi: fix various symbols mismatch in documentation Marc-André Lureau
                   ` (8 subsequent siblings)
  13 siblings, 1 reply; 28+ messages in thread
From: Marc-André Lureau @ 2016-11-07  7:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi-schema.json     |  4 ++--
 qapi/block-core.json |  4 ++--
 qapi/crypto.json     | 36 ++++++++++++++++++------------------
 3 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/qapi-schema.json b/qapi-schema.json
index 1d8ad72..5f377fa 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -4650,7 +4650,7 @@
 { 'include': 'qapi/rocker.json' }
 
 ##
-# ReplayMode:
+# @ReplayMode:
 #
 # Mode of the replay subsystem.
 #
@@ -4718,7 +4718,7 @@
 { 'command': 'query-gic-capabilities', 'returns': ['GICCapability'] }
 
 ##
-# CpuInstanceProperties
+# @CpuInstanceProperties
 #
 # List of properties to be used for hotplugging a CPU instance,
 # it should be passed by management with device_add command when
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 5108b42..372889c 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1144,7 +1144,7 @@
   'data': 'DriveMirror' }
 
 ##
-# DriveMirror
+# @DriveMirror
 #
 # A set of parameters describing drive mirror setup.
 #
@@ -1368,7 +1368,7 @@
   'data': 'BlockIOThrottle' }
 
 ##
-# BlockIOThrottle
+# @BlockIOThrottle
 #
 # A set of parameters describing block throttling.
 #
diff --git a/qapi/crypto.json b/qapi/crypto.json
index 5c9d7d4..15d296e 100644
--- a/qapi/crypto.json
+++ b/qapi/crypto.json
@@ -3,7 +3,7 @@
 # QAPI crypto definitions
 
 ##
-# QCryptoTLSCredsEndpoint:
+# @QCryptoTLSCredsEndpoint:
 #
 # The type of network endpoint that will be using the credentials.
 # Most types of credential require different setup / structures
@@ -22,7 +22,7 @@
 
 
 ##
-# QCryptoSecretFormat:
+# @QCryptoSecretFormat:
 #
 # The data format that the secret is provided in
 #
@@ -36,7 +36,7 @@
 
 
 ##
-# QCryptoHashAlgorithm:
+# @QCryptoHashAlgorithm:
 #
 # The supported algorithms for computing content digests
 #
@@ -55,7 +55,7 @@
 
 
 ##
-# QCryptoCipherAlgorithm:
+# @QCryptoCipherAlgorithm:
 #
 # The supported algorithms for content encryption ciphers
 #
@@ -82,7 +82,7 @@
 
 
 ##
-# QCryptoCipherMode:
+# @QCryptoCipherMode:
 #
 # The supported modes for content encryption ciphers
 #
@@ -98,7 +98,7 @@
 
 
 ##
-# QCryptoIVGenAlgorithm:
+# @QCryptoIVGenAlgorithm:
 #
 # The supported algorithms for generating initialization
 # vectors for full disk encryption. The 'plain' generator
@@ -116,7 +116,7 @@
   'data': ['plain', 'plain64', 'essiv']}
 
 ##
-# QCryptoBlockFormat:
+# @QCryptoBlockFormat:
 #
 # The supported full disk encryption formats
 #
@@ -131,7 +131,7 @@
   'data': ['qcow', 'luks']}
 
 ##
-# QCryptoBlockOptionsBase:
+# @QCryptoBlockOptionsBase:
 #
 # The common options that apply to all full disk
 # encryption formats
@@ -144,7 +144,7 @@
   'data': { 'format': 'QCryptoBlockFormat' }}
 
 ##
-# QCryptoBlockOptionsQCow:
+# @QCryptoBlockOptionsQCow:
 #
 # The options that apply to QCow/QCow2 AES-CBC encryption format
 #
@@ -158,7 +158,7 @@
   'data': { '*key-secret': 'str' }}
 
 ##
-# QCryptoBlockOptionsLUKS:
+# @QCryptoBlockOptionsLUKS:
 #
 # The options that apply to LUKS encryption format
 #
@@ -172,7 +172,7 @@
 
 
 ##
-# QCryptoBlockCreateOptionsLUKS:
+# @QCryptoBlockCreateOptionsLUKS:
 #
 # The options that apply to LUKS encryption format initialization
 #
@@ -202,7 +202,7 @@
 
 
 ##
-# QCryptoBlockOpenOptions:
+# @QCryptoBlockOpenOptions:
 #
 # The options that are available for all encryption formats
 # when opening an existing volume
@@ -217,7 +217,7 @@
 
 
 ##
-# QCryptoBlockCreateOptions:
+# @QCryptoBlockCreateOptions:
 #
 # The options that are available for all encryption formats
 # when initializing a new volume
@@ -232,7 +232,7 @@
 
 
 ##
-# QCryptoBlockInfoBase:
+# @QCryptoBlockInfoBase:
 #
 # The common information that applies to all full disk
 # encryption formats
@@ -246,7 +246,7 @@
 
 
 ##
-# QCryptoBlockInfoLUKSSlot:
+# @QCryptoBlockInfoLUKSSlot:
 #
 # Information about the LUKS block encryption key
 # slot options
@@ -266,7 +266,7 @@
 
 
 ##
-# QCryptoBlockInfoLUKS:
+# @QCryptoBlockInfoLUKS:
 #
 # Information about the LUKS block encryption options
 #
@@ -294,7 +294,7 @@
            'slots': [ 'QCryptoBlockInfoLUKSSlot' ] }}
 
 ##
-# QCryptoBlockInfoQCow:
+# @QCryptoBlockInfoQCow:
 #
 # Information about the QCow block encryption options
 #
@@ -305,7 +305,7 @@
 
 
 ##
-# QCryptoBlockInfo:
+# @QCryptoBlockInfo:
 #
 # Information about the block encryption options
 #
-- 
2.10.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Qemu-devel] [PATCH v3 06/14] qapi: fix various symbols mismatch in documentation
  2016-11-07  7:30 [Qemu-devel] [PATCH v3 00/14] qapi doc generation (whole version, squashed) Marc-André Lureau
                   ` (4 preceding siblings ...)
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 05/14] qapi: fix missing symbol @prefix Marc-André Lureau
@ 2016-11-07  7:30 ` Marc-André Lureau
  2016-11-07 15:40   ` Markus Armbruster
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 07/14] qapi: use one symbol per line Marc-André Lureau
                   ` (7 subsequent siblings)
  13 siblings, 1 reply; 28+ messages in thread
From: Marc-André Lureau @ 2016-11-07  7:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

There are various mismatch:
- invalid symbols
- section and member symbols mismatch
- enum or union values vs 'type'

The documentation parser catches all these cases.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi-schema.json     | 20 +++++++++-----------
 qapi/block-core.json |  4 ----
 qapi/common.json     |  6 +++---
 qapi/rocker.json     |  2 +-
 qga/qapi-schema.json |  6 +++---
 5 files changed, 16 insertions(+), 22 deletions(-)

diff --git a/qapi-schema.json b/qapi-schema.json
index 5f377fa..0c9a293 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -693,8 +693,6 @@
 #
 # Set various migration parameters.  See MigrationParameters for details.
 #
-# @x-checkpoint-delay: the delay time between two checkpoints. (Since 2.8)
-#
 # Since: 2.4
 ##
 { 'command': 'migrate-set-parameters', 'boxed': true,
@@ -1171,7 +1169,7 @@
            '*service': 'str', '*auth': 'str', '*clients': ['VncClientInfo']} }
 
 ##
-# @VncPriAuth:
+# @VncPrimaryAuth:
 #
 # vnc primary authentication method.
 #
@@ -3174,7 +3172,7 @@
 #
 # @alias: #optional an alias for the machine name
 #
-# @default: #optional whether the machine is default
+# @is-default: #optional whether the machine is default
 #
 # @cpu-max: maximum number of CPUs supported by the machine type
 #           (since 1.5.0)
@@ -3727,7 +3725,6 @@
 #
 # @device: The name of the special file for the device,
 #          i.e. /dev/ttyS0 on Unix or COM1: on Windows
-# @type: What kind of device this is.
 #
 # Since: 1.4
 ##
@@ -3992,7 +3989,7 @@
 #
 # A union referencing different TPM backend types' configuration options
 #
-# @passthrough: The configuration options for the TPM passthrough type
+# @type: 'passthrough' The configuration options for the TPM passthrough type
 #
 # Since: 1.5
 ##
@@ -4000,7 +3997,7 @@
    'data': { 'passthrough' : 'TPMPassthroughOptions' } }
 
 ##
-# @TpmInfo:
+# @TPMInfo:
 #
 # Information about the TPM
 #
@@ -4344,10 +4341,11 @@
 #
 # Input event union.
 #
-# @key: Input event of Keyboard
-# @btn: Input event of pointer buttons
-# @rel: Input event of relative pointer motion
-# @abs: Input event of absolute pointer motion
+# @type: the input type, one of:
+#  - 'key': Input event of Keyboard
+#  - 'btn': Input event of pointer buttons
+#  - 'rel': Input event of relative pointer motion
+#  - 'abs': Input event of absolute pointer motion
 #
 # Since: 2.0
 ##
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 372889c..c64a48c 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -2160,10 +2160,6 @@
 #
 # @type:       Transport type used for gluster connection
 #
-# @unix:       socket file
-#
-# @tcp:        host address and port number
-#
 # This is similar to SocketAddress, only distinction:
 #
 # 1. GlusterServer is a flat union, SocketAddress is a simple union.
diff --git a/qapi/common.json b/qapi/common.json
index 9353a7b..6987100 100644
--- a/qapi/common.json
+++ b/qapi/common.json
@@ -34,11 +34,11 @@
 #
 # A three-part version number.
 #
-# @qemu.major:  The major version number.
+# @major:  The major version number.
 #
-# @qemu.minor:  The minor version number.
+# @minor:  The minor version number.
 #
-# @qemu.micro:  The micro version number.
+# @micro:  The micro version number.
 #
 # Since: 2.4
 ##
diff --git a/qapi/rocker.json b/qapi/rocker.json
index 2fe7fdf..ace2776 100644
--- a/qapi/rocker.json
+++ b/qapi/rocker.json
@@ -1,5 +1,5 @@
 ##
-# @Rocker:
+# @RockerSwitch:
 #
 # Rocker switch information.
 #
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 5173c4a..2e6cc91 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -203,7 +203,7 @@
 #
 # Open a file in the guest and retrieve a file handle for it
 #
-# @filepath: Full path to the file in the guest to open.
+# @path: Full path to the file in the guest to open.
 #
 # @mode: #optional open mode, as per fopen(), "r" is the default.
 #
@@ -378,7 +378,7 @@
   'data': { 'handle': 'int' } }
 
 ##
-# @GuestFsFreezeStatus
+# @GuestFsfreezeStatus
 #
 # An enumeration of filesystem freeze states
 #
@@ -766,7 +766,7 @@
 # @GuestDiskAddress:
 #
 # @pci-controller: controller's PCI address
-# @type: bus type
+# @bus-type: bus type
 # @bus: bus id
 # @target: target id
 # @unit: unit id
-- 
2.10.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Qemu-devel] [PATCH v3 07/14] qapi: use one symbol per line
  2016-11-07  7:30 [Qemu-devel] [PATCH v3 00/14] qapi doc generation (whole version, squashed) Marc-André Lureau
                   ` (5 preceding siblings ...)
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 06/14] qapi: fix various symbols mismatch in documentation Marc-André Lureau
@ 2016-11-07  7:30 ` Marc-André Lureau
  2016-11-07 15:57   ` Markus Armbruster
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 08/14] qapi: add missing colon-ending for section name Marc-André Lureau
                   ` (6 subsequent siblings)
  13 siblings, 1 reply; 28+ messages in thread
From: Marc-André Lureau @ 2016-11-07  7:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

The documentation parser only handles a single symbol per line.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi/block-core.json | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/qapi/block-core.json b/qapi/block-core.json
index c64a48c..e1cc94a 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1712,9 +1712,13 @@
 #
 # Drivers that are supported in block device operations.
 #
-# @host_device, @host_cdrom: Since 2.1
+# @host_device: Since 2.1
+# @host_cdrom: Since 2.1
 # @gluster: Since 2.7
-# @nbd, @nfs, @replication, @ssh: Since 2.8
+# @nbd: Since 2.8
+# @nfs: Since 2.8
+# @replication: Since 2.8
+# @ssh: Since 2.8
 #
 # Since: 2.0
 ##
-- 
2.10.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Qemu-devel] [PATCH v3 08/14] qapi: add missing colon-ending for section name
  2016-11-07  7:30 [Qemu-devel] [PATCH v3 00/14] qapi doc generation (whole version, squashed) Marc-André Lureau
                   ` (6 preceding siblings ...)
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 07/14] qapi: use one symbol per line Marc-André Lureau
@ 2016-11-07  7:30 ` Marc-André Lureau
  2016-11-07 15:58   ` Markus Armbruster
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 09/14] qapi: add some sections in docs Marc-André Lureau
                   ` (5 subsequent siblings)
  13 siblings, 1 reply; 28+ messages in thread
From: Marc-André Lureau @ 2016-11-07  7:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

The documentation parser expects a section name to end with ':',
otherwise the comment is treated as free-form text body.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi-schema.json     | 300 +++++++++++++++++++++++++--------------------------
 qapi/block-core.json | 196 ++++++++++++++++-----------------
 qapi/block.json      |  16 +--
 qapi/common.json     |   8 +-
 qapi/event.json      |  58 +++++-----
 qapi/introspect.json |  28 ++---
 qapi/trace.json      |   8 +-
 qga/qapi-schema.json |  44 ++++----
 8 files changed, 329 insertions(+), 329 deletions(-)

diff --git a/qapi-schema.json b/qapi-schema.json
index 0c9a293..e9605b0 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -66,7 +66,7 @@
   'data': ['discard', 'delay', 'merge', 'slew' ] }
 
 ##
-# @add_client
+# @add_client:
 #
 # Allow client connections for VNC, Spice and socket based
 # character devices to be passed in to QEMU via SCM_RIGHTS.
@@ -97,7 +97,7 @@
 #
 # @name: #optional The name of the guest
 #
-# Since 0.14.0
+# Since: 0.14.0
 ##
 { 'struct': 'NameInfo', 'data': {'*name': 'str'} }
 
@@ -108,7 +108,7 @@
 #
 # Returns: @NameInfo of the guest
 #
-# Since 0.14.0
+# Since: 0.14.0
 ##
 { 'command': 'query-name', 'returns': 'NameInfo' }
 
@@ -137,7 +137,7 @@
 { 'command': 'query-kvm', 'returns': 'KvmInfo' }
 
 ##
-# @RunState
+# @RunState:
 #
 # An enumeration of VM run states.
 #
@@ -235,7 +235,7 @@
 #
 # Returns: The @UuidInfo for the guest
 #
-# Since 0.14.0
+# Since: 0.14.0
 ##
 { 'command': 'query-uuid', 'returns': 'UuidInfo' }
 
@@ -382,7 +382,7 @@
 { 'command': 'query-events', 'returns': ['EventInfo'] }
 
 ##
-# @MigrationStats
+# @MigrationStats:
 #
 # Detailed migration status.
 #
@@ -396,7 +396,7 @@
 #
 # @skipped: number of skipped zero pages (since 1.5)
 #
-# @normal : number of normal pages (since 1.2)
+# @normal: number of normal pages (since 1.2)
 #
 # @normal-bytes: number of normal bytes sent (since 1.2)
 #
@@ -420,7 +420,7 @@
            'postcopy-requests' : 'int' } }
 
 ##
-# @XBZRLECacheStats
+# @XBZRLECacheStats:
 #
 # Detailed XBZRLE migration cache statistics
 #
@@ -474,7 +474,7 @@
             'active', 'postcopy-active', 'completed', 'failed', 'colo' ] }
 
 ##
-# @MigrationInfo
+# @MigrationInfo:
 #
 # Information about current migration process.
 #
@@ -534,7 +534,7 @@
            '*error-desc': 'str'} }
 
 ##
-# @query-migrate
+# @query-migrate:
 #
 # Returns information about current migration process.
 #
@@ -545,7 +545,7 @@
 { 'command': 'query-migrate', 'returns': 'MigrationInfo' }
 
 ##
-# @MigrationCapability
+# @MigrationCapability:
 #
 # Migration capabilities enumeration
 #
@@ -593,7 +593,7 @@
            'compress', 'events', 'postcopy-ram', 'x-colo'] }
 
 ##
-# @MigrationCapabilityStatus
+# @MigrationCapabilityStatus:
 #
 # Migration capability information
 #
@@ -607,7 +607,7 @@
   'data': { 'capability' : 'MigrationCapability', 'state' : 'bool' } }
 
 ##
-# @migrate-set-capabilities
+# @migrate-set-capabilities:
 #
 # Enable/Disable the following migration capabilities (like xbzrle)
 #
@@ -619,7 +619,7 @@
   'data': { 'capabilities': ['MigrationCapabilityStatus'] } }
 
 ##
-# @query-migrate-capabilities
+# @query-migrate-capabilities:
 #
 # Returns information about the current migration capabilities status
 #
@@ -630,7 +630,7 @@
 { 'command': 'query-migrate-capabilities', 'returns':   ['MigrationCapabilityStatus']}
 
 ##
-# @MigrationParameter
+# @MigrationParameter:
 #
 # Migration parameters enumeration
 #
@@ -689,7 +689,7 @@
            'downtime-limit', 'x-checkpoint-delay' ] }
 
 ##
-# @migrate-set-parameters
+# @migrate-set-parameters:
 #
 # Set various migration parameters.  See MigrationParameters for details.
 #
@@ -699,7 +699,7 @@
   'data': 'MigrationParameters' }
 
 ##
-# @MigrationParameters
+# @MigrationParameters:
 #
 # Optional members can be omitted on input ('migrate-set-parameters')
 # but most members will always be present on output
@@ -758,7 +758,7 @@
             '*x-checkpoint-delay': 'int'} }
 
 ##
-# @query-migrate-parameters
+# @query-migrate-parameters:
 #
 # Returns information about the current migration parameters
 #
@@ -770,7 +770,7 @@
   'returns': 'MigrationParameters' }
 
 ##
-# @client_migrate_info
+# @client_migrate_info:
 #
 # Set migration information for remote display.  This makes the server
 # ask the client to automatically reconnect using the new parameters
@@ -789,7 +789,7 @@
             '*tls-port': 'int', '*cert-subject': 'str' } }
 
 ##
-# @migrate-start-postcopy
+# @migrate-start-postcopy:
 #
 # Followup to a migration command to switch the migration to postcopy mode.
 # The postcopy-ram capability must be set before the original migration
@@ -800,7 +800,7 @@
 { 'command': 'migrate-start-postcopy' }
 
 ##
-# @COLOMessage
+# @COLOMessage:
 #
 # The message transmission between Primary side and Secondary side.
 #
@@ -826,7 +826,7 @@
             'vmstate-loaded' ] }
 
 ##
-# @COLOMode
+# @COLOMode:
 #
 # The colo mode
 #
@@ -842,7 +842,7 @@
   'data': [ 'unknown', 'primary', 'secondary'] }
 
 ##
-# @FailoverStatus
+# @FailoverStatus:
 #
 # An enumeration of COLO failover status
 #
@@ -860,7 +860,7 @@
   'data': [ 'none', 'require', 'active', 'completed'] }
 
 ##
-# @x-colo-lost-heartbeat
+# @x-colo-lost-heartbeat:
 #
 # Tell qemu that heartbeat is lost, request it to do takeover procedures.
 # If this command is sent to the PVM, the Primary side will exit COLO mode.
@@ -954,7 +954,7 @@
 #
 # @pc: the 64-bit instruction pointer
 #
-# Since 2.6
+# Since: 2.6
 ##
 { 'struct': 'CpuInfoX86', 'data': { 'pc': 'int' } }
 
@@ -967,7 +967,7 @@
 #
 # @npc: the NPC component of the instruction pointer
 #
-# Since 2.6
+# Since: 2.6
 ##
 { 'struct': 'CpuInfoSPARC', 'data': { 'pc': 'int', 'npc': 'int' } }
 
@@ -978,7 +978,7 @@
 #
 # @nip: the instruction pointer
 #
-# Since 2.6
+# Since: 2.6
 ##
 { 'struct': 'CpuInfoPPC', 'data': { 'nip': 'int' } }
 
@@ -989,7 +989,7 @@
 #
 # @PC: the instruction pointer
 #
-# Since 2.6
+# Since: 2.6
 ##
 { 'struct': 'CpuInfoMIPS', 'data': { 'PC': 'int' } }
 
@@ -1000,7 +1000,7 @@
 #
 # @PC: the instruction pointer
 #
-# Since 2.6
+# Since: 2.6
 ##
 { 'struct': 'CpuInfoTricore', 'data': { 'PC': 'int' } }
 
@@ -1009,7 +1009,7 @@
 #
 # No additional information is available about the virtual CPU
 #
-# Since 2.6
+# Since: 2.6
 #
 ##
 { 'struct': 'CpuInfoOther', 'data': { } }
@@ -1044,7 +1044,7 @@
 #
 # Returns a list of information about each iothread.
 #
-# Note this list excludes the QEMU main loop thread, which is not declared
+# Note: this list excludes the QEMU main loop thread, which is not declared
 # using the -object iothread command-line option.  It is always the main thread
 # of the process.
 #
@@ -1055,7 +1055,7 @@
 { 'command': 'query-iothreads', 'returns': ['IOThreadInfo'] }
 
 ##
-# @NetworkAddressFamily
+# @NetworkAddressFamily:
 #
 # The network address family
 #
@@ -1075,7 +1075,7 @@
   'data': [ 'ipv4', 'ipv6', 'unix', 'vsock', 'unknown' ] }
 
 ##
-# @VncBasicInfo
+# @VncBasicInfo:
 #
 # The basic information for vnc network connection
 #
@@ -1098,7 +1098,7 @@
             'websocket': 'bool' } }
 
 ##
-# @VncServerInfo
+# @VncServerInfo:
 #
 # The network connection information for server
 #
@@ -1248,7 +1248,7 @@
 { 'command': 'query-vnc-servers', 'returns': ['VncInfo2'] }
 
 ##
-# @SpiceBasicInfo
+# @SpiceBasicInfo:
 #
 # The basic information for SPICE network connection
 #
@@ -1266,7 +1266,7 @@
             'family': 'NetworkAddressFamily' } }
 
 ##
-# @SpiceServerInfo
+# @SpiceServerInfo:
 #
 # Information about a SPICE server
 #
@@ -1279,7 +1279,7 @@
   'data': { '*auth': 'str' } }
 
 ##
-# @SpiceChannel
+# @SpiceChannel:
 #
 # Information about a SPICE client channel.
 #
@@ -1304,7 +1304,7 @@
            'tls': 'bool'} }
 
 ##
-# @SpiceQueryMouseMode
+# @SpiceQueryMouseMode:
 #
 # An enumeration of Spice mouse states.
 #
@@ -1323,7 +1323,7 @@
   'data': [ 'client', 'server', 'unknown' ] }
 
 ##
-# @SpiceInfo
+# @SpiceInfo:
 #
 # Information about the SPICE session.
 #
@@ -1362,7 +1362,7 @@
            'mouse-mode': 'SpiceQueryMouseMode', '*channels': ['SpiceChannel']} }
 
 ##
-# @query-spice
+# @query-spice:
 #
 # Returns information about the current SPICE server
 #
@@ -1412,7 +1412,7 @@
 { 'struct': 'PciMemoryRange', 'data': {'base': 'int', 'limit': 'int'} }
 
 ##
-# @PciMemoryRegion
+# @PciMemoryRegion:
 #
 # Information about a PCI device I/O region.
 #
@@ -1621,7 +1621,7 @@
 { 'command': 'cpu', 'data': {'index': 'int'} }
 
 ##
-# @cpu-add
+# @cpu-add:
 #
 # Adds CPU with specified ID
 #
@@ -1629,7 +1629,7 @@
 #
 # Returns: Nothing on success
 #
-# Since 1.5
+# Since: 1.5
 ##
 { 'command': 'cpu-add', 'data': {'id': 'int'} }
 
@@ -1760,17 +1760,17 @@
 { 'command': 'balloon', 'data': {'value': 'int'} }
 
 ##
-# @Abort
+# @Abort:
 #
 # This action can be used to test transaction failure.
 #
 # Since: 1.6
-###
+##
 { 'struct': 'Abort',
   'data': { } }
 
 ##
-# @ActionCompletionMode
+# @ActionCompletionMode:
 #
 # An enumeration of Transactional completion modes.
 #
@@ -1790,12 +1790,12 @@
   'data': [ 'individual', 'grouped' ] }
 
 ##
-# @TransactionAction
+# @TransactionAction:
 #
 # A discriminated record of operations that can be performed with
 # @transaction.
 #
-# Since 1.1
+# Since: 1.1
 #
 # drive-backup since 1.6
 # abort since 1.6
@@ -1818,7 +1818,7 @@
    } }
 
 ##
-# @TransactionProperties
+# @TransactionProperties:
 #
 # Optional arguments to modify the behavior of a Transaction.
 #
@@ -1835,7 +1835,7 @@
 }
 
 ##
-# @transaction
+# @transaction:
 #
 # Executes a number of transactionable QMP commands atomically. If any
 # operation fails, then the entire set of actions will be abandoned and the
@@ -1855,7 +1855,7 @@
 # information on only one failed operation returned in an error condition, and
 # subsequent actions will not have been attempted.
 #
-# Since 1.1
+# Since: 1.1
 ##
 { 'command': 'transaction',
   'data': { 'actions': [ 'TransactionAction' ],
@@ -1892,7 +1892,7 @@
   'returns': 'str' }
 
 ##
-# @migrate_cancel
+# @migrate_cancel:
 #
 # Cancel the current executing migration process.
 #
@@ -1905,7 +1905,7 @@
 { 'command': 'migrate_cancel' }
 
 ##
-# @migrate_set_downtime
+# @migrate_set_downtime:
 #
 # Set maximum tolerated downtime for migration.
 #
@@ -1920,7 +1920,7 @@
 { 'command': 'migrate_set_downtime', 'data': {'value': 'number'} }
 
 ##
-# @migrate_set_speed
+# @migrate_set_speed:
 #
 # Set maximum speed for migration.
 #
@@ -1935,7 +1935,7 @@
 { 'command': 'migrate_set_speed', 'data': {'value': 'int'} }
 
 ##
-# @migrate-set-cache-size
+# @migrate-set-cache-size:
 #
 # Set XBZRLE cache size
 #
@@ -1951,7 +1951,7 @@
 { 'command': 'migrate-set-cache-size', 'data': {'value': 'int'} }
 
 ##
-# @query-migrate-cache-size
+# @query-migrate-cache-size:
 #
 # query XBZRLE cache size
 #
@@ -2216,7 +2216,7 @@
   'returns': [ 'DevicePropertyInfo' ] }
 
 ##
-# @migrate
+# @migrate:
 #
 # Migrates the current running guest to another Virtual Machine.
 #
@@ -2237,7 +2237,7 @@
   'data': {'uri': 'str', '*blk': 'bool', '*inc': 'bool', '*detach': 'bool' } }
 
 ##
-# @migrate-incoming
+# @migrate-incoming:
 #
 # Start an incoming migration, the qemu must have been started
 # with -incoming defer
@@ -2271,7 +2271,7 @@
 { 'command': 'xen-save-devices-state', 'data': {'filename': 'str'} }
 
 ##
-# @xen-set-global-dirty-log
+# @xen-set-global-dirty-log:
 #
 # Enable or disable the global dirty log mode.
 #
@@ -2363,7 +2363,7 @@
   'data': [ 'elf', 'kdump-zlib', 'kdump-lzo', 'kdump-snappy' ] }
 
 ##
-# @dump-guest-memory
+# @dump-guest-memory:
 #
 # Dump guest's memory to vmcore. It is a synchronous operation that can take
 # very long depending on the amount of guest memory.
@@ -2417,7 +2417,7 @@
             '*format': 'DumpGuestMemoryFormat'} }
 
 ##
-# @DumpStatus
+# @DumpStatus:
 #
 # Describe the status of a long-running background guest memory dump.
 #
@@ -2429,13 +2429,13 @@
 #
 # @failed: the last dump has failed.
 #
-# Since 2.6
+# Since: 2.6
 ##
 { 'enum': 'DumpStatus',
   'data': [ 'none', 'active', 'completed', 'failed' ] }
 
 ##
-# @DumpQueryResult
+# @DumpQueryResult:
 #
 # The result format for 'query-dump'.
 #
@@ -2445,7 +2445,7 @@
 #
 # @total: total bytes to be written in latest dump (uncompressed)
 #
-# Since 2.6
+# Since: 2.6
 ##
 { 'struct': 'DumpQueryResult',
   'data': { 'status': 'DumpStatus',
@@ -2453,7 +2453,7 @@
             'total': 'int' } }
 
 ##
-# @query-dump
+# @query-dump:
 #
 # Query latest dump status.
 #
@@ -2488,7 +2488,7 @@
   'returns': 'DumpGuestMemoryCapability' }
 
 ##
-# @dump-skeys
+# @dump-skeys:
 #
 # Dump guest's storage keys
 #
@@ -2575,17 +2575,17 @@
 { 'command': 'object-del', 'data': {'id': 'str'} }
 
 ##
-# @NetdevNoneOptions
+# @NetdevNoneOptions:
 #
 # Use it alone to have zero network devices.
 #
-# Since 1.2
+# Since: 1.2
 ##
 { 'struct': 'NetdevNoneOptions',
   'data': { } }
 
 ##
-# @NetLegacyNicOptions
+# @NetLegacyNicOptions:
 #
 # Create a new Network Interface Card.
 #
@@ -2599,7 +2599,7 @@
 #
 # @vectors: #optional number of MSI-x vectors, 0 to disable MSI-X
 #
-# Since 1.2
+# Since: 1.2
 ##
 { 'struct': 'NetLegacyNicOptions',
   'data': {
@@ -2610,18 +2610,18 @@
     '*vectors': 'uint32' } }
 
 ##
-# @String
+# @String:
 #
 # A fat type wrapping 'str', to be embedded in lists.
 #
-# Since 1.2
+# Since: 1.2
 ##
 { 'struct': 'String',
   'data': {
     'str': 'str' } }
 
 ##
-# @NetdevUserOptions
+# @NetdevUserOptions:
 #
 # Use the user mode network stack which requires no administrator privilege to
 # run.
@@ -2678,7 +2678,7 @@
 #
 # @guestfwd: #optional forward guest TCP connections
 #
-# Since 1.2
+# Since: 1.2
 ##
 { 'struct': 'NetdevUserOptions',
   'data': {
@@ -2704,7 +2704,7 @@
     '*guestfwd':  ['String'] } }
 
 ##
-# @NetdevTapOptions
+# @NetdevTapOptions:
 #
 # Connect the host TAP network interface name to the VLAN.
 #
@@ -2741,7 +2741,7 @@
 # @poll-us: #optional maximum number of microseconds that could
 # be spent on busy polling for tap (since 2.7)
 #
-# Since 1.2
+# Since: 1.2
 ##
 { 'struct': 'NetdevTapOptions',
   'data': {
@@ -2762,7 +2762,7 @@
     '*poll-us':    'uint32'} }
 
 ##
-# @NetdevSocketOptions
+# @NetdevSocketOptions:
 #
 # Connect the VLAN to a remote VLAN in another QEMU virtual machine using a TCP
 # socket connection.
@@ -2779,7 +2779,7 @@
 #
 # @udp: #optional UDP unicast address and port number
 #
-# Since 1.2
+# Since: 1.2
 ##
 { 'struct': 'NetdevSocketOptions',
   'data': {
@@ -2791,7 +2791,7 @@
     '*udp':       'str' } }
 
 ##
-# @NetdevL2TPv3Options
+# @NetdevL2TPv3Options:
 #
 # Connect the VLAN to Ethernet over L2TPv3 Static tunnel
 #
@@ -2827,7 +2827,7 @@
 # @offset: #optional additional offset - allows the insertion of
 #          additional application-specific data before the packet payload
 #
-# Since 2.1
+# Since: 2.1
 ##
 { 'struct': 'NetdevL2TPv3Options',
   'data': {
@@ -2847,7 +2847,7 @@
     '*offset':      'uint32' } }
 
 ##
-# @NetdevVdeOptions
+# @NetdevVdeOptions:
 #
 # Connect the VLAN to a vde switch running on the host.
 #
@@ -2859,7 +2859,7 @@
 #
 # @mode: #optional permissions for socket
 #
-# Since 1.2
+# Since: 1.2
 ##
 { 'struct': 'NetdevVdeOptions',
   'data': {
@@ -2869,7 +2869,7 @@
     '*mode':  'uint16' } }
 
 ##
-# @NetdevDumpOptions
+# @NetdevDumpOptions:
 #
 # Dump VLAN network traffic to a file.
 #
@@ -2878,7 +2878,7 @@
 #
 # @file: #optional dump file path (default is qemu-vlan0.pcap)
 #
-# Since 1.2
+# Since: 1.2
 ##
 { 'struct': 'NetdevDumpOptions',
   'data': {
@@ -2886,7 +2886,7 @@
     '*file': 'str' } }
 
 ##
-# @NetdevBridgeOptions
+# @NetdevBridgeOptions:
 #
 # Connect a host TAP network interface to a host bridge device.
 #
@@ -2894,7 +2894,7 @@
 #
 # @helper: #optional command to execute to configure bridge
 #
-# Since 1.2
+# Since: 1.2
 ##
 { 'struct': 'NetdevBridgeOptions',
   'data': {
@@ -2902,20 +2902,20 @@
     '*helper': 'str' } }
 
 ##
-# @NetdevHubPortOptions
+# @NetdevHubPortOptions:
 #
 # Connect two or more net clients through a software hub.
 #
 # @hubid: hub identifier number
 #
-# Since 1.2
+# Since: 1.2
 ##
 { 'struct': 'NetdevHubPortOptions',
   'data': {
     'hubid':     'int32' } }
 
 ##
-# @NetdevNetmapOptions
+# @NetdevNetmapOptions:
 #
 # Connect a client to a netmap-enabled NIC or to a VALE switch port
 #
@@ -2928,7 +2928,7 @@
 #
 # @devname: #optional path of the netmap device (default: '/dev/netmap').
 #
-# Since 2.0
+# Since: 2.0
 ##
 { 'struct': 'NetdevNetmapOptions',
   'data': {
@@ -2936,7 +2936,7 @@
     '*devname':    'str' } }
 
 ##
-# @NetdevVhostUserOptions
+# @NetdevVhostUserOptions:
 #
 # Vhost-user network backend
 #
@@ -2947,7 +2947,7 @@
 # @queues: #optional number of queues to be created for multiqueue vhost-user
 #          (default: 1) (Since 2.5)
 #
-# Since 2.1
+# Since: 2.1
 ##
 { 'struct': 'NetdevVhostUserOptions',
   'data': {
@@ -2956,18 +2956,18 @@
     '*queues':        'int' } }
 
 ##
-# @NetClientDriver
+# @NetClientDriver:
 #
 # Available netdev drivers.
 #
-# Since 2.7
+# Since: 2.7
 ##
 { 'enum': 'NetClientDriver',
   'data': [ 'none', 'nic', 'user', 'tap', 'l2tpv3', 'socket', 'vde', 'dump',
             'bridge', 'hubport', 'netmap', 'vhost-user' ] }
 
 ##
-# @Netdev
+# @Netdev:
 #
 # Captures the configuration of a network device.
 #
@@ -2975,7 +2975,7 @@
 #
 # @type: Specify the driver used for interpreting remaining arguments.
 #
-# Since 1.2
+# Since: 1.2
 #
 # 'l2tpv3' - since 2.1
 ##
@@ -2997,7 +2997,7 @@
     'vhost-user': 'NetdevVhostUserOptions' } }
 
 ##
-# @NetLegacy
+# @NetLegacy:
 #
 # Captures the configuration of a network device; legacy.
 #
@@ -3009,7 +3009,7 @@
 #
 # @opts: device type specific properties (legacy)
 #
-# Since 1.2
+# Since: 1.2
 ##
 { 'struct': 'NetLegacy',
   'data': {
@@ -3019,11 +3019,11 @@
     'opts':  'NetLegacyOptions' } }
 
 ##
-# @NetLegacyOptions
+# @NetLegacyOptions:
 #
 # Like Netdev, but for use only by the legacy command line options
 #
-# Since 1.2
+# Since: 1.2
 ##
 { 'union': 'NetLegacyOptions',
   'data': {
@@ -3040,7 +3040,7 @@
     'vhost-user': 'NetdevVhostUserOptions' } }
 
 ##
-# @NetFilterDirection
+# @NetFilterDirection:
 #
 # Indicates whether a netfilter is attached to a netdev's transmit queue or
 # receive queue or both.
@@ -3054,13 +3054,13 @@
 # @tx: the filter is attached to the transmit queue of the netdev,
 #      where it will receive packets sent by the netdev.
 #
-# Since 2.5
+# Since: 2.5
 ##
 { 'enum': 'NetFilterDirection',
   'data': [ 'all', 'rx', 'tx' ] }
 
 ##
-# @InetSocketAddress
+# @InetSocketAddress:
 #
 # Captures a socket address or address range in the Internet namespace.
 #
@@ -3076,7 +3076,7 @@
 # @ipv6: whether to accept IPv6 addresses, default try both IPv4 and IPv6
 #        #optional
 #
-# Since 1.3
+# Since: 1.3
 ##
 { 'struct': 'InetSocketAddress',
   'data': {
@@ -3087,30 +3087,30 @@
     '*ipv6': 'bool' } }
 
 ##
-# @UnixSocketAddress
+# @UnixSocketAddress:
 #
 # Captures a socket address in the local ("Unix socket") namespace.
 #
 # @path: filesystem path to use
 #
-# Since 1.3
+# Since: 1.3
 ##
 { 'struct': 'UnixSocketAddress',
   'data': {
     'path': 'str' } }
 
 ##
-# @VsockSocketAddress
+# @VsockSocketAddress:
 #
 # Captures a socket address in the vsock namespace.
 #
 # @cid: unique host identifier
 # @port: port
 #
-# Note that string types are used to allow for possible future hostname or
+# Note: string types are used to allow for possible future hostname or
 # service resolution support.
 #
-# Since 2.8
+# Since: 2.8
 ##
 { 'struct': 'VsockSocketAddress',
   'data': {
@@ -3118,11 +3118,11 @@
     'port': 'str' } }
 
 ##
-# @SocketAddress
+# @SocketAddress:
 #
 # Captures the address of a socket, which could also be a named file descriptor
 #
-# Since 1.3
+# Since: 1.3
 ##
 { 'union': 'SocketAddress',
   'data': {
@@ -3273,7 +3273,7 @@
             '*props': 'any' } }
 
 ##
-# @CpuModelExpansionType
+# @CpuModelExpansionType:
 #
 # An enumeration of CPU model expansion types.
 #
@@ -3296,7 +3296,7 @@
 
 
 ##
-# @CpuModelExpansionInfo
+# @CpuModelExpansionInfo:
 #
 # The result of a cpu model expansion.
 #
@@ -3370,7 +3370,7 @@
   'data': [ 'incompatible', 'identical', 'superset', 'subset' ] }
 
 ##
-# @CpuModelCompareInfo
+# @CpuModelCompareInfo:
 #
 # The result of a CPU model comparison.
 #
@@ -3434,7 +3434,7 @@
   'returns': 'CpuModelCompareInfo' }
 
 ##
-# @CpuModelBaselineInfo
+# @CpuModelBaselineInfo:
 #
 # The result of a CPU model baseline.
 #
@@ -3640,7 +3640,7 @@
             'kp_comma', 'kp_equals', 'power' ] }
 
 ##
-# @KeyValue
+# @KeyValue:
 #
 # Represents a keyboard key.
 #
@@ -4026,7 +4026,7 @@
 { 'command': 'query-tpm', 'returns': ['TPMInfo'] }
 
 ##
-# @AcpiTableOptions
+# @AcpiTableOptions:
 #
 # Specify an ACPI table on the command line to load.
 #
@@ -4069,7 +4069,7 @@
 #        ACPI table header. At least one file is required. This field excludes
 #        @file.
 #
-# Since 1.5
+# Since: 1.5
 ##
 { 'struct': 'AcpiTableOptions',
   'data': {
@@ -4097,7 +4097,7 @@
 # @size: accepts a number followed by an optional suffix (K)ilo,
 #        (M)ega, (G)iga, (T)era
 #
-# Since 1.5
+# Since: 1.5
 ##
 { 'enum': 'CommandLineParameterType',
   'data': ['string', 'boolean', 'number', 'size'] }
@@ -4115,7 +4115,7 @@
 #
 # @default: #optional default value string (since 2.1)
 #
-# Since 1.5
+# Since: 1.5
 ##
 { 'struct': 'CommandLineParameterInfo',
   'data': { 'name': 'str',
@@ -4132,7 +4132,7 @@
 #
 # @parameters: an array of @CommandLineParameterInfo
 #
-# Since 1.5
+# Since: 1.5
 ##
 { 'struct': 'CommandLineOptionInfo',
   'data': { 'option': 'str', 'parameters': ['CommandLineParameterInfo'] } }
@@ -4147,13 +4147,13 @@
 # Returns: list of @CommandLineOptionInfo for all options (or for the given
 #          @option).  Returns an error if the given @option doesn't exist.
 #
-# Since 1.5
+# Since: 1.5
 ##
 {'command': 'query-command-line-options', 'data': { '*option': 'str' },
  'returns': ['CommandLineOptionInfo'] }
 
 ##
-# @X86CPURegister32
+# @X86CPURegister32:
 #
 # A X86 32-bit register
 #
@@ -4163,7 +4163,7 @@
   'data': [ 'EAX', 'EBX', 'ECX', 'EDX', 'ESP', 'EBP', 'ESI', 'EDI' ] }
 
 ##
-# @X86CPUFeatureWordInfo
+# @X86CPUFeatureWordInfo:
 #
 # Information about a X86 CPU feature word
 #
@@ -4185,11 +4185,11 @@
             'features': 'int' } }
 
 ##
-# @DummyForceArrays
+# @DummyForceArrays:
 #
 # Not used by QMP; hack to let us use X86CPUFeatureWordInfoList internally
 #
-# Since 2.5
+# Since: 2.5
 ##
 { 'struct': 'DummyForceArrays',
   'data': { 'unused': ['X86CPUFeatureWordInfo'] } }
@@ -4239,7 +4239,7 @@
 #
 # @multicast-table: a list of multicast macaddr string
 #
-# Since 1.6
+# Since: 1.6
 ##
 { 'struct': 'RxFilterInfo',
   'data': {
@@ -4274,7 +4274,7 @@
   'returns': ['RxFilterInfo'] }
 
 ##
-# @InputButton
+# @InputButton:
 #
 # Button of a pointer input device (mouse, tablet).
 #
@@ -4284,7 +4284,7 @@
   'data'  : [ 'left', 'middle', 'right', 'wheel-up', 'wheel-down' ] }
 
 ##
-# @InputAxis
+# @InputAxis:
 #
 # Position axis of a pointer input device (mouse, tablet).
 #
@@ -4294,7 +4294,7 @@
   'data'  : [ 'x', 'y' ] }
 
 ##
-# @InputKeyEvent
+# @InputKeyEvent:
 #
 # Keyboard input event.
 #
@@ -4308,7 +4308,7 @@
               'down'    : 'bool' } }
 
 ##
-# @InputBtnEvent
+# @InputBtnEvent:
 #
 # Pointer button input event.
 #
@@ -4322,7 +4322,7 @@
               'down'    : 'bool' } }
 
 ##
-# @InputMoveEvent
+# @InputMoveEvent:
 #
 # Pointer motion input event.
 #
@@ -4337,7 +4337,7 @@
               'value'   : 'int' } }
 
 ##
-# @InputEvent
+# @InputEvent:
 #
 # Input event union.
 #
@@ -4356,7 +4356,7 @@
               'abs'     : 'InputMoveEvent' } }
 
 ##
-# @input-send-event
+# @input-send-event:
 #
 # Send input event(s) to guest.
 #
@@ -4386,18 +4386,18 @@
             'events' : [ 'InputEvent' ] } }
 
 ##
-# @NumaOptions
+# @NumaOptions:
 #
 # A discriminated record of NUMA options. (for OptsVisitor)
 #
-# Since 2.1
+# Since: 2.1
 ##
 { 'union': 'NumaOptions',
   'data': {
     'node': 'NumaNodeOptions' }}
 
 ##
-# @NumaNodeOptions
+# @NumaNodeOptions:
 #
 # Create a guest NUMA node. (for OptsVisitor)
 #
@@ -4423,7 +4423,7 @@
    '*memdev': 'str' }}
 
 ##
-# @HostMemPolicy
+# @HostMemPolicy:
 #
 # Host memory policy types
 #
@@ -4437,7 +4437,7 @@
 # @interleave: memory allocations are interleaved across the set
 #              of host nodes specified
 #
-# Since 2.1
+# Since: 2.1
 ##
 { 'enum': 'HostMemPolicy',
   'data': [ 'default', 'preferred', 'bind', 'interleave' ] }
@@ -4526,7 +4526,7 @@
 { 'union': 'MemoryDeviceInfo', 'data': {'dimm': 'PCDIMMDeviceInfo'} }
 
 ##
-# @query-memory-devices
+# @query-memory-devices:
 #
 # Lists available memory devices and their state
 #
@@ -4535,7 +4535,7 @@
 { 'command': 'query-memory-devices', 'returns': ['MemoryDeviceInfo'] }
 
 ##
-# @ACPISlotType
+# @ACPISlotType:
 #
 # @DIMM: memory slot
 # @CPU: logical CPU slot (since 2.7)
@@ -4543,7 +4543,7 @@
 { 'enum': 'ACPISlotType', 'data': [ 'DIMM', 'CPU' ] }
 
 ##
-# @ACPIOSTInfo
+# @ACPIOSTInfo:
 #
 # OSPM Status Indication for a device
 # For description of possible values of @source and @status fields
@@ -4569,7 +4569,7 @@
               'status': 'int' } }
 
 ##
-# @query-acpi-ospm-status
+# @query-acpi-ospm-status:
 #
 # Lists ACPI OSPM status of ACPI device objects,
 # which might be reported via _OST method
@@ -4579,7 +4579,7 @@
 { 'command': 'query-acpi-ospm-status', 'returns': ['ACPIOSTInfo'] }
 
 ##
-# @WatchdogExpirationAction
+# @WatchdogExpirationAction:
 #
 # An enumeration of the actions taken when the watchdog device's timer is
 # expired
@@ -4607,7 +4607,7 @@
             'inject-nmi' ] }
 
 ##
-# @IoOperationType
+# @IoOperationType:
 #
 # An enumeration of the I/O operation types
 #
@@ -4621,7 +4621,7 @@
   'data': [ 'read', 'write' ] }
 
 ##
-# @GuestPanicAction
+# @GuestPanicAction:
 #
 # An enumeration of the actions taken when guest OS panic is detected
 #
@@ -4633,7 +4633,7 @@
   'data': [ 'pause', 'poweroff' ] }
 
 ##
-# @rtc-reset-reinjection
+# @rtc-reset-reinjection:
 #
 # This command will reset the RTC interrupt reinjection backlog.
 # Can be used if another mechanism to synchronize guest time
@@ -4716,7 +4716,7 @@
 { 'command': 'query-gic-capabilities', 'returns': ['GICCapability'] }
 
 ##
-# @CpuInstanceProperties
+# @CpuInstanceProperties:
 #
 # List of properties to be used for hotplugging a CPU instance,
 # it should be passed by management with device_add command when
@@ -4744,7 +4744,7 @@
 }
 
 ##
-# @HotpluggableCPU
+# @HotpluggableCPU:
 #
 # @type: CPU object type for usage with device_add command
 # @props: list of properties to be used for hotplugging CPU
@@ -4763,7 +4763,7 @@
 }
 
 ##
-# @query-hotpluggable-cpus
+# @query-hotpluggable-cpus:
 #
 # Returns: a list of HotpluggableCPU objects.
 #
diff --git a/qapi/block-core.json b/qapi/block-core.json
index e1cc94a..bc78042 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -6,7 +6,7 @@
 { 'include': 'common.json' }
 
 ##
-# @SnapshotInfo
+# @SnapshotInfo:
 #
 # @id: unique snapshot id
 #
@@ -213,7 +213,7 @@
            '*filename': 'str' } }
 
 ##
-# @BlockdevCacheInfo
+# @BlockdevCacheInfo:
 #
 # Cache mode information for a block device
 #
@@ -378,7 +378,7 @@
 # @offset: if present, the image file stores the data for this range in
 #          raw format at the given offset.
 #
-# Since 1.7
+# Since: 1.7
 ##
 { 'struct': 'BlockDeviceMapEntry',
   'data': { 'start': 'int', 'length': 'int', 'depth': 'int', 'zero': 'bool',
@@ -790,7 +790,7 @@
                                       '*node-name': 'str', 'password': 'str'} }
 
 ##
-# @block_resize
+# @block_resize:
 #
 # Resize a block image while a guest is running.
 #
@@ -812,7 +812,7 @@
                                        'size': 'int' }}
 
 ##
-# @NewImageMode
+# @NewImageMode:
 #
 # An enumeration that tells QEMU how to set the backing file path in
 # a new image file.
@@ -829,7 +829,7 @@
   'data': [ 'existing', 'absolute-paths' ] }
 
 ##
-# @BlockdevSnapshotSync
+# @BlockdevSnapshotSync:
 #
 # Either @device or @node-name must be set but not both.
 #
@@ -852,7 +852,7 @@
             '*format': 'str', '*mode': 'NewImageMode' } }
 
 ##
-# @BlockdevSnapshot
+# @BlockdevSnapshot:
 #
 # @node: device or node name that will have a snapshot created.
 #
@@ -861,13 +861,13 @@
 #           It must not have a current backing file (this can be
 #           achieved by passing "backing": "" to blockdev-add).
 #
-# Since 2.5
+# Since: 2.5
 ##
 { 'struct': 'BlockdevSnapshot',
   'data': { 'node': 'str', 'overlay': 'str' } }
 
 ##
-# @DriveBackup
+# @DriveBackup:
 #
 # @job-id: #optional identifier for the newly-created block job. If
 #          omitted, the device name will be used. (Since 2.7)
@@ -905,9 +905,9 @@
 #                   default 'report' (no limitations, since this applies to
 #                   a different block device than @device).
 #
-# Note that @on-source-error and @on-target-error only affect background I/O.
-# If an error occurs during a guest write request, the device's rerror/werror
-# actions will be used.
+# Note: @on-source-error and @on-target-error only affect background
+# I/O.  If an error occurs during a guest write request, the device's
+# rerror/werror actions will be used.
 #
 # Since: 1.6
 ##
@@ -919,7 +919,7 @@
             '*on-target-error': 'BlockdevOnError' } }
 
 ##
-# @BlockdevBackup
+# @BlockdevBackup:
 #
 # @job-id: #optional identifier for the newly-created block job. If
 #          omitted, the device name will be used. (Since 2.7)
@@ -946,9 +946,9 @@
 #                   default 'report' (no limitations, since this applies to
 #                   a different block device than @device).
 #
-# Note that @on-source-error and @on-target-error only affect background I/O.
-# If an error occurs during a guest write request, the device's rerror/werror
-# actions will be used.
+# Note: @on-source-error and @on-target-error only affect background
+# I/O.  If an error occurs during a guest write request, the device's
+# rerror/werror actions will be used.
 #
 # Since: 2.3
 ##
@@ -961,7 +961,7 @@
             '*on-target-error': 'BlockdevOnError' } }
 
 ##
-# @blockdev-snapshot-sync
+# @blockdev-snapshot-sync:
 #
 # Generates a synchronous snapshot of a block device.
 #
@@ -970,26 +970,26 @@
 # Returns: nothing on success
 #          If @device is not a valid block device, DeviceNotFound
 #
-# Since 0.14.0
+# Since: 0.14.0
 ##
 { 'command': 'blockdev-snapshot-sync',
   'data': 'BlockdevSnapshotSync' }
 
 
 ##
-# @blockdev-snapshot
+# @blockdev-snapshot:
 #
 # Generates a snapshot of a block device.
 #
 # For the arguments, see the documentation of BlockdevSnapshot.
 #
-# Since 2.5
+# Since: 2.5
 ##
 { 'command': 'blockdev-snapshot',
   'data': 'BlockdevSnapshot' }
 
 ##
-# @change-backing-file
+# @change-backing-file:
 #
 # Change the backing file in the image file metadata.  This does not
 # cause QEMU to reopen the image file to reparse the backing filename
@@ -1016,7 +1016,7 @@
             'backing-file': 'str' } }
 
 ##
-# @block-commit
+# @block-commit:
 #
 # Live commit of data from overlay image nodes into backing nodes - i.e.,
 # writes data between 'top' and 'base' into 'base'.
@@ -1079,7 +1079,7 @@
             '*backing-file': 'str', '*speed': 'int' } }
 
 ##
-# @drive-backup
+# @drive-backup:
 #
 # Start a point-in-time copy of a block device to a new destination.  The
 # status of ongoing drive-backup operations can be checked with
@@ -1092,13 +1092,13 @@
 # Returns: nothing on success
 #          If @device is not a valid block device, GenericError
 #
-# Since 1.6
+# Since: 1.6
 ##
 { 'command': 'drive-backup', 'boxed': true,
   'data': 'DriveBackup' }
 
 ##
-# @blockdev-backup
+# @blockdev-backup:
 #
 # Start a point-in-time copy of a block device to a new destination.  The
 # status of ongoing blockdev-backup operations can be checked with
@@ -1111,25 +1111,25 @@
 # Returns: nothing on success
 #          If @device is not a valid block device, DeviceNotFound
 #
-# Since 2.3
+# Since: 2.3
 ##
 { 'command': 'blockdev-backup', 'boxed': true,
   'data': 'BlockdevBackup' }
 
 
 ##
-# @query-named-block-nodes
+# @query-named-block-nodes:
 #
 # Get the named block driver list
 #
 # Returns: the list of BlockDeviceInfo
 #
-# Since 2.0
+# Since: 2.0
 ##
 { 'command': 'query-named-block-nodes', 'returns': [ 'BlockDeviceInfo' ] }
 
 ##
-# @drive-mirror
+# @drive-mirror:
 #
 # Start mirroring a block device's writes to a new destination.
 #
@@ -1138,13 +1138,13 @@
 # Returns: nothing on success
 #          If @device is not a valid block device, GenericError
 #
-# Since 1.3
+# Since: 1.3
 ##
 { 'command': 'drive-mirror', 'boxed': true,
   'data': 'DriveMirror' }
 
 ##
-# @DriveMirror
+# @DriveMirror:
 #
 # A set of parameters describing drive mirror setup.
 #
@@ -1198,7 +1198,7 @@
 #         written. Both will result in identical contents.
 #         Default is true. (Since 2.4)
 #
-# Since 1.3
+# Since: 1.3
 ##
 { 'struct': 'DriveMirror',
   'data': { '*job-id': 'str', 'device': 'str', 'target': 'str',
@@ -1210,19 +1210,19 @@
             '*unmap': 'bool' } }
 
 ##
-# @BlockDirtyBitmap
+# @BlockDirtyBitmap:
 #
 # @node: name of device/node which the bitmap is tracking
 #
 # @name: name of the dirty bitmap
 #
-# Since 2.4
+# Since: 2.4
 ##
 { 'struct': 'BlockDirtyBitmap',
   'data': { 'node': 'str', 'name': 'str' } }
 
 ##
-# @BlockDirtyBitmapAdd
+# @BlockDirtyBitmapAdd:
 #
 # @node: name of device/node which the bitmap is tracking
 #
@@ -1231,13 +1231,13 @@
 # @granularity: #optional the bitmap granularity, default is 64k for
 #               block-dirty-bitmap-add
 #
-# Since 2.4
+# Since: 2.4
 ##
 { 'struct': 'BlockDirtyBitmapAdd',
   'data': { 'node': 'str', 'name': 'str', '*granularity': 'uint32' } }
 
 ##
-# @block-dirty-bitmap-add
+# @block-dirty-bitmap-add:
 #
 # Create a dirty bitmap with a name on the node
 #
@@ -1245,13 +1245,13 @@
 #          If @node is not a valid block device or node, DeviceNotFound
 #          If @name is already taken, GenericError with an explanation
 #
-# Since 2.4
+# Since: 2.4
 ##
 { 'command': 'block-dirty-bitmap-add',
   'data': 'BlockDirtyBitmapAdd' }
 
 ##
-# @block-dirty-bitmap-remove
+# @block-dirty-bitmap-remove:
 #
 # Remove a dirty bitmap on the node
 #
@@ -1260,13 +1260,13 @@
 #          If @name is not found, GenericError with an explanation
 #          if @name is frozen by an operation, GenericError
 #
-# Since 2.4
+# Since: 2.4
 ##
 { 'command': 'block-dirty-bitmap-remove',
   'data': 'BlockDirtyBitmap' }
 
 ##
-# @block-dirty-bitmap-clear
+# @block-dirty-bitmap-clear:
 #
 # Clear (reset) a dirty bitmap on the device
 #
@@ -1274,13 +1274,13 @@
 #          If @node is not a valid block device, DeviceNotFound
 #          If @name is not found, GenericError with an explanation
 #
-# Since 2.4
+# Since: 2.4
 ##
 { 'command': 'block-dirty-bitmap-clear',
   'data': 'BlockDirtyBitmap' }
 
 ##
-# @blockdev-mirror
+# @blockdev-mirror:
 #
 # Start mirroring a block device's writes to a new destination.
 #
@@ -1321,7 +1321,7 @@
 #
 # Returns: nothing on success.
 #
-# Since 2.6
+# Since: 2.6
 ##
 { 'command': 'blockdev-mirror',
   'data': { '*job-id': 'str', 'device': 'str', 'target': 'str',
@@ -1368,7 +1368,7 @@
   'data': 'BlockIOThrottle' }
 
 ##
-# @BlockIOThrottle
+# @BlockIOThrottle:
 #
 # A set of parameters describing block throttling.
 #
@@ -1650,7 +1650,7 @@
 { 'command': 'block-job-complete', 'data': { 'device': 'str' } }
 
 ##
-# @BlockdevDiscardOptions
+# @BlockdevDiscardOptions:
 #
 # Determines how to handle discard requests.
 #
@@ -1663,7 +1663,7 @@
   'data': [ 'ignore', 'unmap' ] }
 
 ##
-# @BlockdevDetectZeroesOptions
+# @BlockdevDetectZeroesOptions:
 #
 # Describes the operation mode for the automatic conversion of plain
 # zero writes by the OS to driver specific optimized zero write commands.
@@ -1679,7 +1679,7 @@
   'data': [ 'off', 'on', 'unmap' ] }
 
 ##
-# @BlockdevAioOptions
+# @BlockdevAioOptions:
 #
 # Selects the AIO backend to handle I/O requests
 #
@@ -1692,7 +1692,7 @@
   'data': [ 'threads', 'native' ] }
 
 ##
-# @BlockdevCacheOptions
+# @BlockdevCacheOptions:
 #
 # Includes cache-related options for block devices
 #
@@ -1708,7 +1708,7 @@
             '*no-flush': 'bool' } }
 
 ##
-# @BlockdevDriver
+# @BlockdevDriver:
 #
 # Drivers that are supported in block device operations.
 #
@@ -1731,7 +1731,7 @@
             'vvfat' ] }
 
 ##
-# @BlockdevOptionsFile
+# @BlockdevOptionsFile:
 #
 # Driver specific block device options for the file backend.
 #
@@ -1745,7 +1745,7 @@
             '*aio': 'BlockdevAioOptions' } }
 
 ##
-# @BlockdevOptionsNull
+# @BlockdevOptionsNull:
 #
 # Driver specific block device options for the null backend.
 #
@@ -1760,7 +1760,7 @@
   'data': { '*size': 'int', '*latency-ns': 'uint64' } }
 
 ##
-# @BlockdevOptionsVVFAT
+# @BlockdevOptionsVVFAT:
 #
 # Driver specific block device options for the vvfat protocol.
 #
@@ -1781,7 +1781,7 @@
             '*label': 'str', '*rw': 'bool' } }
 
 ##
-# @BlockdevOptionsGenericFormat
+# @BlockdevOptionsGenericFormat:
 #
 # Driver specific block device options for image format that have no option
 # besides their data source.
@@ -1794,7 +1794,7 @@
   'data': { 'file': 'BlockdevRef' } }
 
 ##
-# @BlockdevOptionsLUKS
+# @BlockdevOptionsLUKS:
 #
 # Driver specific block device options for LUKS.
 #
@@ -1810,7 +1810,7 @@
 
 
 ##
-# @BlockdevOptionsGenericCOWFormat
+# @BlockdevOptionsGenericCOWFormat:
 #
 # Driver specific block device options for image format that have no option
 # besides their data source and an optional backing file.
@@ -1827,7 +1827,7 @@
   'data': { '*backing': 'BlockdevRef' } }
 
 ##
-# @Qcow2OverlapCheckMode
+# @Qcow2OverlapCheckMode:
 #
 # General overlap check modes.
 #
@@ -1847,7 +1847,7 @@
   'data': [ 'none', 'constant', 'cached', 'all' ] }
 
 ##
-# @Qcow2OverlapCheckFlags
+# @Qcow2OverlapCheckFlags:
 #
 # Structure of flags for each metadata structure. Setting a field to 'true'
 # makes qemu guard that structure against unintended overwriting. The default
@@ -1870,7 +1870,7 @@
             '*inactive-l2':    'bool' } }
 
 ##
-# @Qcow2OverlapChecks
+# @Qcow2OverlapChecks:
 #
 # Specifies which metadata structures should be guarded against unintended
 # overwriting.
@@ -1887,7 +1887,7 @@
             'mode':  'Qcow2OverlapCheckMode' } }
 
 ##
-# @BlockdevOptionsQcow2
+# @BlockdevOptionsQcow2:
 #
 # Driver specific block device options for qcow2.
 #
@@ -1937,7 +1937,7 @@
 
 
 ##
-# @BlockdevOptionsArchipelago
+# @BlockdevOptionsArchipelago:
 #
 # Driver specific block device options for Archipelago.
 #
@@ -1966,7 +1966,7 @@
             '*segment': 'str' } }
 
 ##
-# @BlockdevOptionsSsh
+# @BlockdevOptionsSsh:
 #
 # @server:              host address
 #
@@ -1977,7 +1977,7 @@
 #
 # TODO: Expose the host_key_check option in QMP
 #
-# Since 2.8
+# Since: 2.8
 ##
 { 'struct': 'BlockdevOptionsSsh',
   'data': { 'server': 'InetSocketAddress',
@@ -1986,7 +1986,7 @@
 
 
 ##
-# @BlkdebugEvent
+# @BlkdebugEvent:
 #
 # Trigger events supported by blkdebug.
 #
@@ -2009,7 +2009,7 @@
             'pwritev_zero', 'pwritev_done', 'empty_image_prepare' ] }
 
 ##
-# @BlkdebugInjectErrorOptions
+# @BlkdebugInjectErrorOptions:
 #
 # Describes a single error injection for blkdebug.
 #
@@ -2041,7 +2041,7 @@
             '*immediately': 'bool' } }
 
 ##
-# @BlkdebugSetStateOptions
+# @BlkdebugSetStateOptions:
 #
 # Describes a single state-change event for blkdebug.
 #
@@ -2061,7 +2061,7 @@
             'new_state': 'int' } }
 
 ##
-# @BlockdevOptionsBlkdebug
+# @BlockdevOptionsBlkdebug:
 #
 # Driver specific block device options for blkdebug.
 #
@@ -2086,7 +2086,7 @@
             '*set-state': ['BlkdebugSetStateOptions'] } }
 
 ##
-# @BlockdevOptionsBlkverify
+# @BlockdevOptionsBlkverify:
 #
 # Driver specific block device options for blkverify.
 #
@@ -2101,7 +2101,7 @@
             'raw': 'BlockdevRef' } }
 
 ##
-# @QuorumReadPattern
+# @QuorumReadPattern:
 #
 # An enumeration of quorum read patterns.
 #
@@ -2114,7 +2114,7 @@
 { 'enum': 'QuorumReadPattern', 'data': [ 'quorum', 'fifo' ] }
 
 ##
-# @BlockdevOptionsQuorum
+# @BlockdevOptionsQuorum:
 #
 # Driver specific block device options for Quorum
 #
@@ -2141,7 +2141,7 @@
             '*read-pattern': 'QuorumReadPattern' } }
 
 ##
-# @GlusterTransport
+# @GlusterTransport:
 #
 # An enumeration of Gluster transport types
 #
@@ -2156,7 +2156,7 @@
 
 
 ##
-# @GlusterServer
+# @GlusterServer:
 #
 # Captures the address of a socket
 #
@@ -2185,7 +2185,7 @@
             'tcp': 'InetSocketAddress' } }
 
 ##
-# @BlockdevOptionsGluster
+# @BlockdevOptionsGluster:
 #
 # Driver specific block device options for Gluster
 #
@@ -2209,7 +2209,7 @@
             '*logfile': 'str' } }
 
 ##
-# @ReplicationMode
+# @ReplicationMode:
 #
 # An enumeration of replication modes.
 #
@@ -2222,7 +2222,7 @@
 { 'enum' : 'ReplicationMode', 'data' : [ 'primary', 'secondary' ] }
 
 ##
-# @BlockdevOptionsReplication
+# @BlockdevOptionsReplication:
 #
 # Driver specific block device options for replication
 #
@@ -2240,19 +2240,19 @@
             '*top-id': 'str' } }
 
 ##
-# @NFSTransport
+# @NFSTransport:
 #
 # An enumeration of NFS transport types
 #
 # @inet:        TCP transport
 #
-# Since 2.8
+# Since: 2.8
 ##
 { 'enum': 'NFSTransport',
   'data': [ 'inet' ] }
 
 ##
-# @NFSServer
+# @NFSServer:
 #
 # Captures the address of the socket
 #
@@ -2260,14 +2260,14 @@
 #
 # @host:        host address for NFS server
 #
-# Since 2.8
+# Since: 2.8
 ##
 { 'struct': 'NFSServer',
   'data': { 'type': 'NFSTransport',
             'host': 'str' } }
 
 ##
-# @BlockdevOptionsNfs
+# @BlockdevOptionsNfs:
 #
 # Driver specific block device option for NFS
 #
@@ -2295,7 +2295,7 @@
 # @debug-level:             #optional set the NFS debug level (max 2) (defaults
 #                           to libnfs default)
 #
-# Since 2.8
+# Since: 2.8
 ##
 { 'struct': 'BlockdevOptionsNfs',
   'data': { 'server': 'NFSServer',
@@ -2308,7 +2308,7 @@
             '*debug-level': 'int' } }
 
 ##
-# @BlockdevOptionsCurl
+# @BlockdevOptionsCurl:
 #
 # Driver specific block device options for the curl backend.
 #
@@ -2320,7 +2320,7 @@
   'data': { 'filename': 'str' } }
 
 ##
-# @BlockdevOptionsNbd
+# @BlockdevOptionsNbd:
 #
 # Driver specific block device options for NBD.
 #
@@ -2338,7 +2338,7 @@
             '*tls-creds': 'str' } }
 
 ##
-# @BlockdevOptionsRaw
+# @BlockdevOptionsRaw:
 #
 # Driver specific block device options for the raw driver.
 #
@@ -2352,7 +2352,7 @@
   'data': { '*offset': 'int', '*size': 'int' } }
 
 ##
-# @BlockdevOptions
+# @BlockdevOptions:
 #
 # Options for creating a block device.  Many options are available for all
 # block devices, independent of the block driver:
@@ -2419,7 +2419,7 @@
   } }
 
 ##
-# @BlockdevRef
+# @BlockdevRef:
 #
 # Reference to a block device.
 #
@@ -2617,7 +2617,7 @@
 
 
 ##
-# @BlockErrorAction
+# @BlockErrorAction:
 #
 # An enumeration of action that has been taken when a DISK I/O occurs
 #
@@ -2634,7 +2634,7 @@
 
 
 ##
-# @BLOCK_IMAGE_CORRUPTED
+# @BLOCK_IMAGE_CORRUPTED:
 #
 # Emitted when a corruption has been detected in a disk image
 #
@@ -2669,7 +2669,7 @@
             'fatal'      : 'bool' } }
 
 ##
-# @BLOCK_IO_ERROR
+# @BLOCK_IO_ERROR:
 #
 # Emitted when a disk I/O error occurs
 #
@@ -2705,7 +2705,7 @@
             'reason': 'str' } }
 
 ##
-# @BLOCK_JOB_COMPLETED
+# @BLOCK_JOB_COMPLETED:
 #
 # Emitted when a block job has completed
 #
@@ -2737,7 +2737,7 @@
             '*error': 'str' } }
 
 ##
-# @BLOCK_JOB_CANCELLED
+# @BLOCK_JOB_CANCELLED:
 #
 # Emitted when a block job has been cancelled
 #
@@ -2763,7 +2763,7 @@
             'speed' : 'int' } }
 
 ##
-# @BLOCK_JOB_ERROR
+# @BLOCK_JOB_ERROR:
 #
 # Emitted when a block job encounters an error
 #
@@ -2782,7 +2782,7 @@
             'action'   : 'BlockErrorAction' } }
 
 ##
-# @BLOCK_JOB_READY
+# @BLOCK_JOB_READY:
 #
 # Emitted when a block job is ready to complete
 #
@@ -2811,7 +2811,7 @@
             'speed' : 'int' } }
 
 ##
-# @PreallocMode
+# @PreallocMode:
 #
 # Preallocation mode of QEMU image file
 #
@@ -2823,13 +2823,13 @@
 #        space is really available. @full preallocation also sets up
 #        metadata correctly.
 #
-# Since 2.2
+# Since: 2.2
 ##
 { 'enum': 'PreallocMode',
   'data': [ 'off', 'metadata', 'falloc', 'full' ] }
 
 ##
-# @BLOCK_WRITE_THRESHOLD
+# @BLOCK_WRITE_THRESHOLD:
 #
 # Emitted when writes on block device reaches or exceeds the
 # configured write threshold. For thin-provisioned devices, this
@@ -2852,7 +2852,7 @@
             'write-threshold': 'uint64' } }
 
 ##
-# @block-set-write-threshold
+# @block-set-write-threshold:
 #
 # Change the write threshold for a block drive. An event will be delivered
 # if a write to this block drive crosses the configured threshold.
@@ -2870,7 +2870,7 @@
   'data': { 'node-name': 'str', 'write-threshold': 'uint64' } }
 
 ##
-# @x-blockdev-change
+# @x-blockdev-change:
 #
 # Dynamically reconfigure the block driver state graph. It can be used
 # to add, remove, insert or replace a graph node. Currently only the
diff --git a/qapi/block.json b/qapi/block.json
index 4661fc9..937df05 100644
--- a/qapi/block.json
+++ b/qapi/block.json
@@ -40,7 +40,7 @@
   'data': ['auto', 'none', 'lba', 'large', 'rechs']}
 
 ##
-# @FloppyDriveType
+# @FloppyDriveType:
 #
 # Type of Floppy drive to be emulated by the Floppy Disk Controller.
 #
@@ -56,7 +56,7 @@
   'data': ['144', '288', '120', 'none', 'auto']}
 
 ##
-# @BlockdevSnapshotInternal
+# @BlockdevSnapshotInternal:
 #
 # @device: the device name or node-name of a root node to generate the snapshot
 #          from
@@ -73,7 +73,7 @@
   'data': { 'device': 'str', 'name': 'str' } }
 
 ##
-# @blockdev-snapshot-internal-sync
+# @blockdev-snapshot-internal-sync:
 #
 # Synchronously take an internal snapshot of a block device, when the format
 # of the image used supports it.
@@ -87,13 +87,13 @@
 #          If the format of the image used does not support it,
 #          BlockFormatFeatureNotSupported
 #
-# Since 1.7
+# Since: 1.7
 ##
 { 'command': 'blockdev-snapshot-internal-sync',
   'data': 'BlockdevSnapshotInternal' }
 
 ##
-# @blockdev-snapshot-delete-internal-sync
+# @blockdev-snapshot-delete-internal-sync:
 #
 # Synchronously delete an internal snapshot of a block device, when the format
 # of the image used support it. The snapshot is identified by name or id or
@@ -114,7 +114,7 @@
 #          BlockFormatFeatureNotSupported
 #          If @id and @name are both not specified, GenericError
 #
-# Since 1.7
+# Since: 1.7
 ##
 { 'command': 'blockdev-snapshot-delete-internal-sync',
   'data': { 'device': 'str', '*id': 'str', '*name': 'str'},
@@ -190,7 +190,7 @@
 { 'command': 'nbd-server-stop' }
 
 ##
-# @DEVICE_TRAY_MOVED
+# @DEVICE_TRAY_MOVED:
 #
 # Emitted whenever the tray of a removable device is moved by the guest or by
 # HMP/QMP commands
@@ -209,7 +209,7 @@
   'data': { 'device': 'str', 'id': 'str', 'tray-open': 'bool' } }
 
 ##
-# @QuorumOpType
+# @QuorumOpType:
 #
 # An enumeration of the quorum operation types
 #
diff --git a/qapi/common.json b/qapi/common.json
index 6987100..624a861 100644
--- a/qapi/common.json
+++ b/qapi/common.json
@@ -3,7 +3,7 @@
 # QAPI common definitions
 
 ##
-# @QapiErrorClass
+# @QapiErrorClass:
 #
 # QEMU error classes
 #
@@ -30,7 +30,7 @@
             'DeviceNotActive', 'DeviceNotFound', 'KVMMissingCap' ] }
 
 ##
-# @VersionTriple
+# @VersionTriple:
 #
 # A three-part version number.
 #
@@ -101,7 +101,7 @@
 { 'command': 'query-commands', 'returns': ['CommandInfo'] }
 
 ##
-# @OnOffAuto
+# @OnOffAuto:
 #
 # An enumeration of three options: on, off, and auto
 #
@@ -117,7 +117,7 @@
   'data': [ 'auto', 'on', 'off' ] }
 
 ##
-# @OnOffSplit
+# @OnOffSplit:
 #
 # An enumeration of three values: on, off, and split
 #
diff --git a/qapi/event.json b/qapi/event.json
index 8642052..37bf34e 100644
--- a/qapi/event.json
+++ b/qapi/event.json
@@ -1,5 +1,5 @@
 ##
-# @SHUTDOWN
+# @SHUTDOWN:
 #
 # Emitted when the virtual machine has shut down, indicating that qemu is
 # about to exit.
@@ -12,7 +12,7 @@
 { 'event': 'SHUTDOWN' }
 
 ##
-# @POWERDOWN
+# @POWERDOWN:
 #
 # Emitted when the virtual machine is powered down through the power control
 # system, such as via ACPI.
@@ -22,7 +22,7 @@
 { 'event': 'POWERDOWN' }
 
 ##
-# @RESET
+# @RESET:
 #
 # Emitted when the virtual machine is reset
 #
@@ -31,7 +31,7 @@
 { 'event': 'RESET' }
 
 ##
-# @STOP
+# @STOP:
 #
 # Emitted when the virtual machine is stopped
 #
@@ -40,7 +40,7 @@
 { 'event': 'STOP' }
 
 ##
-# @RESUME
+# @RESUME:
 #
 # Emitted when the virtual machine resumes execution
 #
@@ -49,7 +49,7 @@
 { 'event': 'RESUME' }
 
 ##
-# @SUSPEND
+# @SUSPEND:
 #
 # Emitted when guest enters a hardware suspension state, for example, S3 state,
 # which is sometimes called standby state
@@ -59,7 +59,7 @@
 { 'event': 'SUSPEND' }
 
 ##
-# @SUSPEND_DISK
+# @SUSPEND_DISK:
 #
 # Emitted when guest enters a hardware suspension state with data saved on
 # disk, for example, S4 state, which is sometimes called hibernate state
@@ -71,7 +71,7 @@
 { 'event': 'SUSPEND_DISK' }
 
 ##
-# @WAKEUP
+# @WAKEUP:
 #
 # Emitted when the guest has woken up from suspend state and is running
 #
@@ -80,7 +80,7 @@
 { 'event': 'WAKEUP' }
 
 ##
-# @RTC_CHANGE
+# @RTC_CHANGE:
 #
 # Emitted when the guest changes the RTC time.
 #
@@ -93,7 +93,7 @@
   'data': { 'offset': 'int' } }
 
 ##
-# @WATCHDOG
+# @WATCHDOG:
 #
 # Emitted when the watchdog device's timer is expired
 #
@@ -108,7 +108,7 @@
   'data': { 'action': 'WatchdogExpirationAction' } }
 
 ##
-# @DEVICE_DELETED
+# @DEVICE_DELETED:
 #
 # Emitted whenever the device removal completion is acknowledged by the guest.
 # At this point, it's safe to reuse the specified device ID. Device removal can
@@ -124,7 +124,7 @@
   'data': { '*device': 'str', 'path': 'str' } }
 
 ##
-# @NIC_RX_FILTER_CHANGED
+# @NIC_RX_FILTER_CHANGED:
 #
 # Emitted once until the 'query-rx-filter' command is executed, the first event
 # will always be emitted
@@ -139,7 +139,7 @@
   'data': { '*name': 'str', 'path': 'str' } }
 
 ##
-# @VNC_CONNECTED
+# @VNC_CONNECTED:
 #
 # Emitted when a VNC client establishes a connection
 #
@@ -157,7 +157,7 @@
             'client': 'VncBasicInfo' } }
 
 ##
-# @VNC_INITIALIZED
+# @VNC_INITIALIZED:
 #
 # Emitted after authentication takes place (if any) and the VNC session is
 # made active
@@ -173,7 +173,7 @@
             'client': 'VncClientInfo' } }
 
 ##
-# @VNC_DISCONNECTED
+# @VNC_DISCONNECTED:
 #
 # Emitted when the connection is closed
 #
@@ -188,7 +188,7 @@
             'client': 'VncClientInfo' } }
 
 ##
-# @SPICE_CONNECTED
+# @SPICE_CONNECTED:
 #
 # Emitted when a SPICE client establishes a connection
 #
@@ -203,7 +203,7 @@
             'client': 'SpiceBasicInfo' } }
 
 ##
-# @SPICE_INITIALIZED
+# @SPICE_INITIALIZED:
 #
 # Emitted after initial handshake and authentication takes place (if any)
 # and the SPICE channel is up and running
@@ -219,7 +219,7 @@
             'client': 'SpiceChannel' } }
 
 ##
-# @SPICE_DISCONNECTED
+# @SPICE_DISCONNECTED:
 #
 # Emitted when the SPICE connection is closed
 #
@@ -234,7 +234,7 @@
             'client': 'SpiceBasicInfo' } }
 
 ##
-# @SPICE_MIGRATE_COMPLETED
+# @SPICE_MIGRATE_COMPLETED:
 #
 # Emitted when SPICE migration has completed
 #
@@ -243,7 +243,7 @@
 { 'event': 'SPICE_MIGRATE_COMPLETED' }
 
 ##
-# @MIGRATION
+# @MIGRATION:
 #
 # Emitted when a migration event happens
 #
@@ -255,7 +255,7 @@
   'data': {'status': 'MigrationStatus'}}
 
 ##
-# @MIGRATION_PASS
+# @MIGRATION_PASS:
 #
 # Emitted from the source side of a migration at the start of each pass
 # (when it syncs the dirty bitmap)
@@ -268,7 +268,7 @@
   'data': { 'pass': 'int' } }
 
 ##
-# @ACPI_DEVICE_OST
+# @ACPI_DEVICE_OST:
 #
 # Emitted when guest executes ACPI _OST method.
 #
@@ -280,7 +280,7 @@
      'data': { 'info': 'ACPIOSTInfo' } }
 
 ##
-# @BALLOON_CHANGE
+# @BALLOON_CHANGE:
 #
 # Emitted when the guest changes the actual BALLOON level. This value is
 # equivalent to the @actual field return by the 'query-balloon' command
@@ -293,7 +293,7 @@
   'data': { 'actual': 'int' } }
 
 ##
-# @GUEST_PANICKED
+# @GUEST_PANICKED:
 #
 # Emitted when guest OS panic is detected
 #
@@ -305,7 +305,7 @@
   'data': { 'action': 'GuestPanicAction' } }
 
 ##
-# @QUORUM_FAILURE
+# @QUORUM_FAILURE:
 #
 # Emitted by the Quorum block driver if it fails to establish a quorum
 #
@@ -321,7 +321,7 @@
   'data': { 'reference': 'str', 'sector-num': 'int', 'sectors-count': 'int' } }
 
 ##
-# @QUORUM_REPORT_BAD
+# @QUORUM_REPORT_BAD:
 #
 # Emitted to report a corruption of a Quorum file
 #
@@ -345,7 +345,7 @@
             'sector-num': 'int', 'sectors-count': 'int' } }
 
 ##
-# @VSERPORT_CHANGE
+# @VSERPORT_CHANGE:
 #
 # Emitted when the guest opens or closes a virtio-serial port.
 #
@@ -359,7 +359,7 @@
   'data': { 'id': 'str', 'open': 'bool' } }
 
 ##
-# @MEM_UNPLUG_ERROR
+# @MEM_UNPLUG_ERROR:
 #
 # Emitted when memory hot unplug error occurs.
 #
@@ -373,7 +373,7 @@
   'data': { 'device': 'str', 'msg': 'str' } }
 
 ##
-# @DUMP_COMPLETED
+# @DUMP_COMPLETED:
 #
 # Emitted when background dump has completed
 #
diff --git a/qapi/introspect.json b/qapi/introspect.json
index 3fd81fb..fd4dc84 100644
--- a/qapi/introspect.json
+++ b/qapi/introspect.json
@@ -11,7 +11,7 @@
 # See the COPYING file in the top-level directory.
 
 ##
-# @query-qmp-schema
+# @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
@@ -49,7 +49,7 @@
   'gen': false }                # just to simplify qmp_query_json()
 
 ##
-# @SchemaMetaType
+# @SchemaMetaType:
 #
 # This is a @SchemaInfo's meta type, i.e. the kind of entity it
 # describes.
@@ -75,7 +75,7 @@
             'command', 'event' ] }
 
 ##
-# @SchemaInfo
+# @SchemaInfo:
 #
 # @name: the entity's name, inherited from @base.
 #        Commands and events have the name defined in the QAPI schema.
@@ -105,7 +105,7 @@
       'event': 'SchemaInfoEvent' } }
 
 ##
-# @SchemaInfoBuiltin
+# @SchemaInfoBuiltin:
 #
 # Additional SchemaInfo members for meta-type 'builtin'.
 #
@@ -117,7 +117,7 @@
   'data': { 'json-type': 'JSONType' } }
 
 ##
-# @JSONType
+# @JSONType:
 #
 # The four primitive and two structured types according to RFC 7159
 # section 1, plus 'int' (split off 'number'), plus the obvious top
@@ -130,7 +130,7 @@
             'object', 'array', 'value' ] }
 
 ##
-# @SchemaInfoEnum
+# @SchemaInfoEnum:
 #
 # Additional SchemaInfo members for meta-type 'enum'.
 #
@@ -144,7 +144,7 @@
   'data': { 'values': ['str'] } }
 
 ##
-# @SchemaInfoArray
+# @SchemaInfoArray:
 #
 # Additional SchemaInfo members for meta-type 'array'.
 #
@@ -158,7 +158,7 @@
   'data': { 'element-type': 'str' } }
 
 ##
-# @SchemaInfoObject
+# @SchemaInfoObject:
 #
 # Additional SchemaInfo members for meta-type 'object'.
 #
@@ -183,7 +183,7 @@
             '*variants': [ 'SchemaInfoObjectVariant' ] } }
 
 ##
-# @SchemaInfoObjectMember
+# @SchemaInfoObjectMember:
 #
 # An object member.
 #
@@ -206,7 +206,7 @@
 # @default's type must be null or match @type
 
 ##
-# @SchemaInfoObjectVariant
+# @SchemaInfoObjectVariant:
 #
 # The variant members for a value of the type tag.
 #
@@ -221,7 +221,7 @@
   'data': { 'case': 'str', 'type': 'str' } }
 
 ##
-# @SchemaInfoAlternate
+# @SchemaInfoAlternate:
 #
 # Additional SchemaInfo members for meta-type 'alternate'.
 #
@@ -237,7 +237,7 @@
   'data': { 'members': [ 'SchemaInfoAlternateMember' ] } }
 
 ##
-# @SchemaInfoAlternateMember
+# @SchemaInfoAlternateMember:
 #
 # An alternate member.
 #
@@ -249,7 +249,7 @@
   'data': { 'type': 'str' } }
 
 ##
-# @SchemaInfoCommand
+# @SchemaInfoCommand:
 #
 # Additional SchemaInfo members for meta-type 'command'.
 #
@@ -266,7 +266,7 @@
   'data': { 'arg-type': 'str', 'ret-type': 'str' } }
 
 ##
-# @SchemaInfoEvent
+# @SchemaInfoEvent:
 #
 # Additional SchemaInfo members for meta-type 'event'.
 #
diff --git a/qapi/trace.json b/qapi/trace.json
index e872146..4fd39b7 100644
--- a/qapi/trace.json
+++ b/qapi/trace.json
@@ -17,7 +17,7 @@
 #
 # @enabled: The event is dynamically enabled.
 #
-# Since 2.2
+# Since: 2.2
 ##
 { 'enum': 'TraceEventState',
   'data': ['unavailable', 'disabled', 'enabled'] }
@@ -34,7 +34,7 @@
 # An event is per-vCPU if it has the "vcpu" property in the "trace-events"
 # files.
 #
-# Since 2.2
+# Since: 2.2
 ##
 { 'struct': 'TraceEventInfo',
   'data': {'name': 'str', 'state': 'TraceEventState', 'vcpu': 'bool'} }
@@ -58,7 +58,7 @@
 # exact match, @vcpu is given and the event does not have the "vcpu" property,
 # an error is returned.
 #
-# Since 2.2
+# Since: 2.2
 ##
 { 'command': 'trace-event-get-state',
   'data': {'name': 'str', '*vcpu': 'int'},
@@ -83,7 +83,7 @@
 # match, @vcpu is given and the event does not have the "vcpu" property, an
 # error is returned.
 #
-# Since 2.2
+# Since: 2.2
 ##
 { 'command': 'trace-event-set-state',
   'data': {'name': 'str', 'enable': 'bool', '*ignore-unavailable': 'bool',
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 2e6cc91..0633515 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -102,7 +102,7 @@
 #
 # Returns: Time in nanoseconds.
 #
-# Since 1.5
+# Since: 1.5
 ##
 { 'command': 'guest-get-time',
   'returns': 'int' }
@@ -149,13 +149,13 @@
 # @success-response: whether command returns a response on success
 #                    (since 1.7)
 #
-# Since 1.1.0
+# Since: 1.1.0
 ##
 { 'struct': 'GuestAgentCommandInfo',
   'data': { 'name': 'str', 'enabled': 'bool', 'success-response': 'bool' } }
 
 ##
-# @GuestAgentInfo
+# @GuestAgentInfo:
 #
 # Information about guest agent.
 #
@@ -163,7 +163,7 @@
 #
 # @supported_commands: Information about guest agent commands
 #
-# Since 0.15.0
+# Since: 0.15.0
 ##
 { 'struct': 'GuestAgentInfo',
   'data': { 'version': 'str',
@@ -230,7 +230,7 @@
   'data': { 'handle': 'int' } }
 
 ##
-# @GuestFileRead
+# @GuestFileRead:
 #
 # Result of guest agent file-read operation
 #
@@ -264,7 +264,7 @@
   'returns': 'GuestFileRead' }
 
 ##
-# @GuestFileWrite
+# @GuestFileWrite:
 #
 # Result of guest agent file-write operation
 #
@@ -300,7 +300,7 @@
 
 
 ##
-# @GuestFileSeek
+# @GuestFileSeek:
 #
 # Result of guest agent file-seek operation
 #
@@ -378,7 +378,7 @@
   'data': { 'handle': 'int' } }
 
 ##
-# @GuestFsfreezeStatus
+# @GuestFsfreezeStatus:
 #
 # An enumeration of filesystem freeze states
 #
@@ -455,7 +455,7 @@
   'returns': 'int' }
 
 ##
-# @GuestFilesystemTrimResult
+# @GuestFilesystemTrimResult:
 #
 # @path: path that was trimmed
 # @error: an error message when trim failed
@@ -469,7 +469,7 @@
            '*trimmed': 'int', '*minimum': 'int', '*error': 'str'} }
 
 ##
-# @GuestFilesystemTrimResponse
+# @GuestFilesystemTrimResponse:
 #
 # @paths: list of @GuestFilesystemTrimResult per path that was trimmed
 #
@@ -501,7 +501,7 @@
   'returns': 'GuestFilesystemTrimResponse' }
 
 ##
-# @guest-suspend-disk
+# @guest-suspend-disk:
 #
 # Suspend guest to disk.
 #
@@ -529,7 +529,7 @@
 { 'command': 'guest-suspend-disk', 'success-response': false }
 
 ##
-# @guest-suspend-ram
+# @guest-suspend-ram:
 #
 # Suspend guest to ram.
 #
@@ -561,7 +561,7 @@
 { 'command': 'guest-suspend-ram', 'success-response': false }
 
 ##
-# @guest-suspend-hybrid
+# @guest-suspend-hybrid:
 #
 # Save guest state to disk and suspend to ram.
 #
@@ -716,7 +716,7 @@
   'returns': 'int' }
 
 ##
-# @GuestDiskBusType
+# @GuestDiskBusType:
 #
 # An enumeration of bus type of disks
 #
@@ -779,7 +779,7 @@
            'bus': 'int', 'target': 'int', 'unit': 'int'} }
 
 ##
-# @GuestFilesystemInfo
+# @GuestFilesystemInfo:
 #
 # @name: disk name
 # @mountpoint: mount point path
@@ -807,7 +807,7 @@
   'returns': ['GuestFilesystemInfo'] }
 
 ##
-# @guest-set-user-password
+# @guest-set-user-password:
 #
 # @username: the user account whose password to change
 # @password: the new password entry string, base64 encoded
@@ -828,7 +828,7 @@
 #
 # Returns: Nothing on success.
 #
-# Since 2.3
+# Since: 2.3
 ##
 { 'command': 'guest-set-user-password',
   'data': { 'username': 'str', 'password': 'str', 'crypted': 'bool' } }
@@ -869,7 +869,7 @@
   'returns': ['GuestMemoryBlock'] }
 
 ##
-# @GuestMemoryBlockResponseType
+# @GuestMemoryBlockResponseType:
 #
 # An enumeration of memory block operation result.
 #
@@ -952,7 +952,7 @@
 #
 # Returns: @GuestMemoryBlockInfo
 #
-# Since 2.3
+# Since: 2.3
 ##
 { 'command': 'guest-get-memory-block-info',
   'returns': 'GuestMemoryBlockInfo' }
@@ -980,7 +980,7 @@
             '*out-data': 'str', '*err-data': 'str',
             '*out-truncated': 'bool', '*err-truncated': 'bool' }}
 ##
-# @guest-exec-status
+# @guest-exec-status:
 #
 # Check status of process associated with PID retrieved via guest-exec.
 # Reap the process and associated metadata if it has exited.
@@ -989,7 +989,7 @@
 #
 # Returns: GuestExecStatus on success.
 #
-# Since 2.5
+# Since: 2.5
 ##
 { 'command': 'guest-exec-status',
   'data':    { 'pid': 'int' },
@@ -999,7 +999,7 @@
 # @GuestExec:
 # @pid: pid of child process in guest OS
 #
-#Since: 2.5
+# Since: 2.5
 ##
 { 'struct': 'GuestExec',
   'data': { 'pid': 'int'} }
-- 
2.10.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Qemu-devel] [PATCH v3 09/14] qapi: add some sections in docs
  2016-11-07  7:30 [Qemu-devel] [PATCH v3 00/14] qapi doc generation (whole version, squashed) Marc-André Lureau
                   ` (7 preceding siblings ...)
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 08/14] qapi: add missing colon-ending for section name Marc-André Lureau
@ 2016-11-07  7:30 ` Marc-André Lureau
  2016-11-07 15:59   ` Markus Armbruster
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 10/14] docs: add master qapi texi files Marc-André Lureau
                   ` (4 subsequent siblings)
  13 siblings, 1 reply; 28+ messages in thread
From: Marc-André Lureau @ 2016-11-07  7:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

Add some more section title, and misc fixes.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 qapi-schema.json     |  4 ++++
 qapi/block-core.json |  6 ++++--
 qapi/block.json      | 10 ++++++++--
 qapi/common.json     |  6 ++++--
 qapi/crypto.json     |  5 ++++-
 qapi/event.json      |  6 ++++++
 qapi/rocker.json     |  4 ++++
 qapi/trace.json      |  3 +++
 8 files changed, 37 insertions(+), 7 deletions(-)

diff --git a/qapi-schema.json b/qapi-schema.json
index e9605b0..b7dff19 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -20,6 +20,10 @@
 # QAPI introspection
 { 'include': 'qapi/introspect.json' }
 
+##
+# = QMP commands
+##
+
 ##
 # @qmp_capabilities:
 #
diff --git a/qapi/block-core.json b/qapi/block-core.json
index bc78042..91febed 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1,6 +1,8 @@
 # -*- Mode: Python -*-
-#
-# QAPI block core definitions (vm unrelated)
+
+##
+# == QAPI block core definitions (vm unrelated)
+##
 
 # QAPI common definitions
 { 'include': 'common.json' }
diff --git a/qapi/block.json b/qapi/block.json
index 937df05..e4ad74b 100644
--- a/qapi/block.json
+++ b/qapi/block.json
@@ -1,10 +1,16 @@
 # -*- Mode: Python -*-
-#
-# QAPI block definitions (vm related)
+
+##
+# = QAPI block definitions
+##
 
 # QAPI block core definitions
 { 'include': 'block-core.json' }
 
+##
+# == QAPI block definitions (vm unrelated)
+##
+
 ##
 # @BiosAtaTranslation:
 #
diff --git a/qapi/common.json b/qapi/common.json
index 624a861..d93f159 100644
--- a/qapi/common.json
+++ b/qapi/common.json
@@ -1,6 +1,8 @@
 # -*- Mode: Python -*-
-#
-# QAPI common definitions
+
+##
+# = QAPI common definitions
+##
 
 ##
 # @QapiErrorClass:
diff --git a/qapi/crypto.json b/qapi/crypto.json
index 15d296e..1e517b0 100644
--- a/qapi/crypto.json
+++ b/qapi/crypto.json
@@ -1,6 +1,9 @@
 # -*- Mode: Python -*-
 #
-# QAPI crypto definitions
+
+##
+# = QAPI crypto definitions
+##
 
 ##
 # @QCryptoTLSCredsEndpoint:
diff --git a/qapi/event.json b/qapi/event.json
index 37bf34e..59942b0 100644
--- a/qapi/event.json
+++ b/qapi/event.json
@@ -1,3 +1,9 @@
+# -*- Mode: Python -*-
+
+##
+# = Events
+##
+
 ##
 # @SHUTDOWN:
 #
diff --git a/qapi/rocker.json b/qapi/rocker.json
index ace2776..dd72e02 100644
--- a/qapi/rocker.json
+++ b/qapi/rocker.json
@@ -1,4 +1,8 @@
 ##
+# = Rocker API
+##
+
+##
 # @RockerSwitch:
 #
 # Rocker switch information.
diff --git a/qapi/trace.json b/qapi/trace.json
index 4fd39b7..3ad7df7 100644
--- a/qapi/trace.json
+++ b/qapi/trace.json
@@ -5,6 +5,9 @@
 # This work is licensed under the terms of the GNU GPL, version 2 or later.
 # See the COPYING file in the top-level directory.
 
+##
+# = Tracing commands
+##
 
 ##
 # @TraceEventState:
-- 
2.10.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Qemu-devel] [PATCH v3 10/14] docs: add master qapi texi files
  2016-11-07  7:30 [Qemu-devel] [PATCH v3 00/14] qapi doc generation (whole version, squashed) Marc-André Lureau
                   ` (8 preceding siblings ...)
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 09/14] qapi: add some sections in docs Marc-André Lureau
@ 2016-11-07  7:30 ` Marc-André Lureau
  2016-11-08 14:19   ` Markus Armbruster
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 11/14] qapi: add qapi2texi script Marc-André Lureau
                   ` (3 subsequent siblings)
  13 siblings, 1 reply; 28+ messages in thread
From: Marc-André Lureau @ 2016-11-07  7:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

The qapi2texi scripts generates a file to be included in a texi
file. Add "QEMU QMP Reference Manual" and "QEMU Guest Agent Protocol
Reference" master texi files. Move qmp-intro.txt into qemu-qmp-ref.texi,
to widen its content on various installed target
formats (man/txt/html/pdf/info..)

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 docs/qemu-ga-ref.texi         |  65 ++++++++++++++++++
 docs/qemu-qmp-ref.texi        | 156 ++++++++++++++++++++++++++++++++++++++++++
 docs/qmp-intro.txt            |  87 -----------------------
 docs/writing-qmp-commands.txt |   2 +-
 4 files changed, 222 insertions(+), 88 deletions(-)
 create mode 100644 docs/qemu-ga-ref.texi
 create mode 100644 docs/qemu-qmp-ref.texi
 delete mode 100644 docs/qmp-intro.txt

diff --git a/docs/qemu-ga-ref.texi b/docs/qemu-ga-ref.texi
new file mode 100644
index 0000000..ad90712
--- /dev/null
+++ b/docs/qemu-ga-ref.texi
@@ -0,0 +1,65 @@
+\input texinfo
+@setfilename qemu-ga-ref.info
+
+@exampleindent 0
+@paragraphindent 0
+
+@settitle QEMU Guest Agent Protocol Reference
+
+@copying
+This is the QEMU Guest Agent Protocol reference manual.
+
+Copyright @copyright{} 2016 The QEMU Project developers
+@end copying
+
+@ifinfo
+@dircategory QEMU
+@direntry
+* QEMU-GA-Ref: (qemu-ga-ref).   QEMU Guest Agent Protocol Reference
+@end direntry
+@end ifinfo
+
+@titlepage
+@title Guest Agent Protocol Reference Manual
+@subtitle QEMU version @value{VERSION}
+@page
+@vskip 0pt plus 1filll
+@insertcopying
+@end titlepage
+
+@contents
+
+@ifnottex
+@node Top
+@top QEMU Guest Agent protocol reference
+@end ifnottex
+
+@menu
+* API Reference::
+* Commands and Events Index::
+* Data Types Index::
+@end menu
+
+@node API Reference
+@chapter API Reference
+
+@c for texi2pod:
+@c man begin DESCRIPTION
+
+@include qemu-ga-qapi.texi
+
+@c man end
+
+@c man begin SEEALSO
+The HTML documentation of QEMU for more information.
+@c man end
+
+@node Commands and Events Index
+@unnumbered Commands and Events Index
+@printindex fn
+
+@node Data Types Index
+@unnumbered Data Types Index
+@printindex tp
+
+@bye
diff --git a/docs/qemu-qmp-ref.texi b/docs/qemu-qmp-ref.texi
new file mode 100644
index 0000000..c1740ae
--- /dev/null
+++ b/docs/qemu-qmp-ref.texi
@@ -0,0 +1,156 @@
+\input texinfo
+@setfilename qemu-qmp-ref.info
+
+@exampleindent 0
+@paragraphindent 0
+
+@settitle QEMU QMP Reference Manual
+
+@copying
+This is the QEMU QMP reference manual.
+
+Copyright @copyright{} 2016 The QEMU Project developers
+@end copying
+
+@ifinfo
+@dircategory QEMU
+@direntry
+* QEMU-QMP-Ref: (qemu-qmp-ref). QEMU QMP Reference Manual
+@end direntry
+@end ifinfo
+
+@titlepage
+@title QMP Reference Manual
+@subtitle QEMU version @value{VERSION}
+@page
+@vskip 0pt plus 1filll
+@insertcopying
+@end titlepage
+
+@contents
+
+@ifnottex
+@node Top
+@top QEMU QMP reference
+@end ifnottex
+
+@menu
+* Introduction::
+* API Reference::
+* Commands and Events Index::
+* Data Types Index::
+@end menu
+
+@node Introduction
+@chapter Introduction
+
+The QEMU Machine Protocol (@acronym{QMP}) allows applications to
+operate a QEMU instance.
+
+QMP is @uref{http://www.json.org, JSON} based and features the
+following:
+
+@itemize @bullet
+@item
+Lightweight, plain-text, easy to parse data format
+@item
+Asynchronous messages support (ie. events)
+@item
+Capabilities Negotiation
+@item
+Introspection
+@end itemize
+
+For detailed information on QEMU Machine Protocol, the specification
+is in @file{qmp-spec.txt}.
+
+@section Usage
+
+You can use the @option{-qmp} option to enable QMP. For example, the
+following makes QMP available on localhost port 4444:
+
+@example
+$ qemu [...] -qmp tcp:localhost:4444,server,nowait
+@end example
+
+However, for more flexibility and to make use of more options, the
+@option{-mon} command-line option should be used. For instance, the
+following example creates one HMP instance (human monitor) on stdio
+and one QMP instance on localhost port 4444:
+
+@example
+$ qemu [...] -chardev socket,id=mon1,host=localhost,port=4444,server,nowait \
+             -mon chardev=mon1,mode=control,pretty=on
+@end example
+
+Please refer to QEMU's manpage for more information.
+
+@section Simple testing
+
+To manually test QMP one can connect with telnet and issue commands by
+hand:
+
+@example
+$ telnet localhost 4444
+Trying 127.0.0.1...
+Connected to localhost.
+Escape character is '^]'.
+@{
+    "QMP": @{
+        "version": @{
+            "qemu": @{
+                "micro": 50,
+                "minor": 6,
+                "major": 1
+            @},
+            "package": ""
+        @},
+        "capabilities": [
+        ]
+    @}
+@}
+
+@{ "execute": "qmp_capabilities" @}
+@{
+    "return": @{
+    @}
+@}
+
+@{ "execute": "query-status" @}
+@{
+    "return": @{
+        "status": "prelaunch",
+        "singlestep": false,
+        "running": false
+    @}
+@}
+@end example
+
+@section Wiki
+
+Please refer to the @uref{http://wiki.qemu-project.org/QMP, QMP QEMU
+ wiki page} for more details on QMP.
+
+@node API Reference
+@chapter API Reference
+
+@c for texi2pod:
+@c man begin DESCRIPTION
+
+@include qemu-qapi.texi
+
+@c man end
+
+@c man begin SEEALSO
+The HTML documentation of QEMU for more precise information.
+@c man end
+
+@node Commands and Events Index
+@unnumbered Commands and Events Index
+@printindex fn
+
+@node Data Types Index
+@unnumbered Data Types Index
+@printindex tp
+
+@bye
diff --git a/docs/qmp-intro.txt b/docs/qmp-intro.txt
deleted file mode 100644
index f6a3a03..0000000
--- a/docs/qmp-intro.txt
+++ /dev/null
@@ -1,87 +0,0 @@
-                          QEMU Machine Protocol
-                          =====================
-
-Introduction
-------------
-
-The QEMU Machine Protocol (QMP) allows applications to operate a
-QEMU instance.
-
-QMP is JSON[1] based and features the following:
-
-- Lightweight, text-based, easy to parse data format
-- Asynchronous messages support (ie. events)
-- Capabilities Negotiation
-
-For detailed information on QMP's usage, please, refer to the following files:
-
-o qmp-spec.txt      QEMU Machine Protocol current specification
-o qmp-commands.txt  QMP supported commands (auto-generated at build-time)
-o qmp-events.txt    List of available asynchronous events
-
-[1] http://www.json.org
-
-Usage
------
-
-You can use the -qmp option to enable QMP. For example, the following
-makes QMP available on localhost port 4444:
-
-$ qemu [...] -qmp tcp:localhost:4444,server,nowait
-
-However, for more flexibility and to make use of more options, the -mon
-command-line option should be used. For instance, the following example
-creates one HMP instance (human monitor) on stdio and one QMP instance
-on localhost port 4444:
-
-$ qemu [...] -chardev stdio,id=mon0 -mon chardev=mon0,mode=readline \
-             -chardev socket,id=mon1,host=localhost,port=4444,server,nowait \
-             -mon chardev=mon1,mode=control,pretty=on
-
-Please, refer to QEMU's manpage for more information.
-
-Simple Testing
---------------
-
-To manually test QMP one can connect with telnet and issue commands by hand:
-
-$ telnet localhost 4444
-Trying 127.0.0.1...
-Connected to localhost.
-Escape character is '^]'.
-{
-    "QMP": {
-        "version": {
-            "qemu": {
-                "micro": 50, 
-                "minor": 6, 
-                "major": 1
-            }, 
-            "package": ""
-        }, 
-        "capabilities": [
-        ]
-    }
-}
-
-{ "execute": "qmp_capabilities" }
-{
-    "return": {
-    }
-}
-
-{ "execute": "query-status" }
-{
-    "return": {
-        "status": "prelaunch", 
-        "singlestep": false, 
-        "running": false
-    }
-}
-
-Please, refer to the qapi-schema.json file for a complete command reference.
-
-QMP wiki page
--------------
-
-http://wiki.qemu-project.org/QMP
diff --git a/docs/writing-qmp-commands.txt b/docs/writing-qmp-commands.txt
index 44c14db..de54977 100644
--- a/docs/writing-qmp-commands.txt
+++ b/docs/writing-qmp-commands.txt
@@ -8,7 +8,7 @@ into the QAPI framework implementation.
 
 For an in-depth introduction to the QAPI framework, please refer to
 docs/qapi-code-gen.txt. For documentation about the QMP protocol,
-start with docs/qmp-intro.txt.
+start with docs/qemu-qmp-ref.texi.
 
 == Overview ==
 
-- 
2.10.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Qemu-devel] [PATCH v3 11/14] qapi: add qapi2texi script
  2016-11-07  7:30 [Qemu-devel] [PATCH v3 00/14] qapi doc generation (whole version, squashed) Marc-André Lureau
                   ` (9 preceding siblings ...)
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 10/14] docs: add master qapi texi files Marc-André Lureau
@ 2016-11-07  7:30 ` Marc-André Lureau
  2016-11-10 16:37   ` Markus Armbruster
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 12/14] texi2pod: learn quotation, deftp and deftypefn Marc-André Lureau
                   ` (2 subsequent siblings)
  13 siblings, 1 reply; 28+ messages in thread
From: Marc-André Lureau @ 2016-11-07  7:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

As the name suggests, the qapi2texi script converts JSON QAPI
description into a texi file suitable for different target
formats (info/man/txt/pdf/html...).

It parses the following kind of blocks:

Free-form:

  ##
  # = Section
  # == Subsection
  #
  # Some text foo with *emphasis*
  # 1. with a list
  # 2. like that
  #
  # And some code:
  # | $ echo foo
  # | -> do this
  # | <- get that
  #
  ##

Symbol:

  ##
  # @symbol:
  #
  # Symbol body ditto ergo sum. Foo bar
  # baz ding.
  #
  # @arg: foo
  # @arg: #optional foo
  #
  # Returns: returns bla bla
  #          Or bla blah
  #
  # Since: version
  # Notes: notes, comments can have
  #        - itemized list
  #        - like this
  #
  # Example:
  #
  # -> { "execute": "quit" }
  # <- { "return": {} }
  #
  ##

That's roughly following the following BNF grammar:

api_comment = "##\n" comment "##\n"
comment = freeform_comment | symbol_comment
freeform_comment = { "#" text "\n" }
symbol_comment = "#" "@" name ":\n" { freeform | member | meta }
member = "#" '@' name ':' [ text ] freeform_comment
meta = "#" ( "Returns:", "Since:", "Note:", "Notes:", "Example:", "Examples:" ) [ text ] freeform_comment
text = free-text markdown-like, "#optional" for members

Thanks to the following json expressions, the documentation is enhanced
with extra information about the type of arguments and return value
expected.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/qapi.py        | 175 ++++++++++++++++++++++++++-
 scripts/qapi2texi.py   | 316 +++++++++++++++++++++++++++++++++++++++++++++++++
 docs/qapi-code-gen.txt |  44 +++++--
 3 files changed, 524 insertions(+), 11 deletions(-)
 create mode 100755 scripts/qapi2texi.py

diff --git a/scripts/qapi.py b/scripts/qapi.py
index 21bc32f..ed52ee4 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -122,6 +122,103 @@ class QAPIExprError(Exception):
             "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
 
 
+class QAPIDoc(object):
+    def __init__(self, parser):
+        self.parser = parser
+        self.symbol = None
+        self.body = []
+        # args is {'arg': 'doc', ...}
+        self.args = OrderedDict()
+        # meta is [(Since/Notes/Examples/Returns:, 'doc'), ...]
+        self.meta = []
+        # the current section to populate, array of [dict, key, comment...]
+        self.section = None
+        self.expr_elem = None
+
+    def get_body(self):
+        return "\n".join(self.body)
+
+    def has_meta(self, name):
+        """Returns True if the doc has a meta section 'name'"""
+        return next((True for i in self.meta if i[0] == name), False)
+
+    def append(self, line):
+        """Adds a # comment line, to be parsed and added in a section"""
+        line = line[1:]
+        if len(line) == 0:
+            self._append_section(line)
+            return
+
+        if line[0] != ' ':
+            raise QAPISchemaError(self.parser, "missing space after #")
+
+        line = line[1:]
+        # take the first word out
+        name = line.split(' ', 1)[0]
+        if name.startswith("@") and name.endswith(":"):
+            line = line[len(name):]
+            name = name[1:-1]
+            if self.symbol is None:
+                # the first is the symbol this APIDoc object documents
+                if len(self.body):
+                    raise QAPISchemaError(self.parser, "symbol must come first")
+                self.symbol = name
+            else:
+                # else an arg
+                self._start_args_section(name)
+        elif self.symbol and name in (
+                "Returns:", "Since:",
+                # those are often singular or plural
+                "Note:", "Notes:",
+                "Example:", "Examples:"):
+            # new "meta" section
+            line = line[len(name):]
+            self._start_meta_section(name[:-1])
+
+        self._append_section(line)
+
+    def _start_args_section(self, name):
+        self.end_section()
+        if self.args.has_key(name):
+            raise QAPISchemaError(self.parser, "'%s' arg duplicated" % name)
+        self.section = [self.args, name]
+
+    def _start_meta_section(self, name):
+        self.end_section()
+        if name in ("Returns", "Since") and self.has_meta(name):
+            raise QAPISchemaError(self.parser, "'%s' section duplicated" % name)
+        self.section = [self.meta, name]
+
+    def _append_section(self, line):
+        """Add a comment to the current section, or the comment body"""
+        if self.section:
+            name = self.section[1]
+            if not name.startswith("Example"):
+                # an empty line ends the section, except with Example
+                if len(self.section) > 2 and len(line) == 0:
+                    self.end_section()
+                    return
+                # Example is verbatim
+                line = line.strip()
+            if len(line) > 0:
+                self.section.append(line)
+        else:
+            self.body.append(line.strip())
+
+    def end_section(self):
+        if self.section is not None:
+            target = self.section[0]
+            name = self.section[1]
+            if len(self.section) < 3:
+                raise QAPISchemaError(self.parser, "Empty doc section")
+            doc = "\n".join(self.section[2:])
+            if isinstance(target, dict):
+                target[name] = doc
+            else:
+                target.append((name, doc))
+            self.section = None
+
+
 class QAPISchemaParser(object):
 
     def __init__(self, fp, previously_included=[], incl_info=None):
@@ -137,9 +234,15 @@ class QAPISchemaParser(object):
         self.line = 1
         self.line_pos = 0
         self.exprs = []
+        self.docs = []
         self.accept()
 
         while self.tok is not None:
+            if self.tok == '#' and self.val.startswith('##'):
+                doc = self.get_doc()
+                self.docs.append(doc)
+                continue
+
             expr_info = {'file': fname, 'line': self.line,
                          'parent': self.incl_info}
             expr = self.get_expr(False)
@@ -160,6 +263,7 @@ class QAPISchemaParser(object):
                         raise QAPIExprError(expr_info, "Inclusion loop for %s"
                                             % include)
                     inf = inf['parent']
+
                 # skip multiple include of the same file
                 if incl_abs_fname in previously_included:
                     continue
@@ -171,12 +275,40 @@ class QAPISchemaParser(object):
                 exprs_include = QAPISchemaParser(fobj, previously_included,
                                                  expr_info)
                 self.exprs.extend(exprs_include.exprs)
+                self.docs.extend(exprs_include.docs)
             else:
                 expr_elem = {'expr': expr,
                              'info': expr_info}
+                if len(self.docs) > 0:
+                    self.docs[-1].expr_elem = expr_elem
                 self.exprs.append(expr_elem)
 
-    def accept(self):
+    def get_doc(self):
+        if self.val != '##':
+            raise QAPISchemaError(self, "Doc comment not starting with '##'")
+
+        doc = QAPIDoc(self)
+        self.accept(False)
+        while self.tok == '#':
+            if self.val.startswith('##'):
+                # ## ends doc
+                if self.val != '##':
+                    raise QAPISchemaError(self, "non-empty '##' line %s"
+                                          % self.val)
+                self.accept()
+                doc.end_section()
+                return doc
+            else:
+                doc.append(self.val)
+            self.accept(False)
+
+        if self.val != '##':
+            raise QAPISchemaError(self, "Doc comment not finishing with '##'")
+
+        doc.end_section()
+        return doc
+
+    def accept(self, skip_comment=True):
         while True:
             self.tok = self.src[self.cursor]
             self.pos = self.cursor
@@ -184,7 +316,13 @@ class QAPISchemaParser(object):
             self.val = None
 
             if self.tok == '#':
+                if self.src[self.cursor] == '#':
+                    # ## starts a doc comment
+                    skip_comment = False
                 self.cursor = self.src.find('\n', self.cursor)
+                self.val = self.src[self.pos:self.cursor]
+                if not skip_comment:
+                    return
             elif self.tok in "{}:,[]":
                 return
             elif self.tok == "'":
@@ -779,6 +917,41 @@ def check_exprs(exprs):
 
     return exprs
 
+def check_docs(docs):
+    for doc in docs:
+        expr_elem = doc.expr_elem
+        if not expr_elem:
+            continue
+
+        expr = expr_elem['expr']
+        for i in ('enum', 'union', 'alternate', 'struct', 'command', 'event'):
+            if i in expr:
+                meta = i
+                break
+
+        info = expr_elem['info']
+        name = expr[meta]
+        if doc.symbol != name:
+            raise QAPIExprError(info,
+                                "Documentation symbol mismatch '%s' != '%s'"
+                                % (doc.symbol, name))
+        if not 'command' in expr and doc.has_meta('Returns'):
+            raise QAPIExprError(info, "Invalid return documentation")
+
+        doc_args = set(doc.args.keys())
+        if meta == 'union':
+            data = expr.get('base', [])
+        else:
+            data = expr.get('data', [])
+        if isinstance(data, dict):
+            data = data.keys()
+        args = set([k.strip('*') for k in data])
+        if meta == 'alternate' or \
+           (meta == 'union' and not expr.get('discriminator')):
+            args.add('type')
+        if not doc_args.issubset(args):
+            raise QAPIExprError(info, "Members documentation is not a subset of"
+                                " API %r > %r" % (list(doc_args), list(args)))
 
 #
 # Schema compiler frontend
diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
new file mode 100755
index 0000000..7e2440c
--- /dev/null
+++ b/scripts/qapi2texi.py
@@ -0,0 +1,316 @@
+#!/usr/bin/env python
+# QAPI texi generator
+#
+# This work is licensed under the terms of the GNU LGPL, version 2+.
+# See the COPYING file in the top-level directory.
+"""This script produces the documentation of a qapi schema in texinfo format"""
+import re
+import sys
+
+from qapi import *
+
+COMMAND_FMT = """
+@deftypefn {type} {{{ret}}} {name} @
+{{{args}}}
+
+{body}
+
+@end deftypefn
+
+""".format
+
+ENUM_FMT = """
+@deftp Enum {name}
+
+{body}
+
+@end deftp
+
+""".format
+
+STRUCT_FMT = """
+@deftp {type} {name} @
+{{{attrs}}}
+
+{body}
+
+@end deftp
+
+""".format
+
+EXAMPLE_FMT = """@example
+{code}
+@end example
+""".format
+
+
+def subst_strong(doc):
+    """Replaces *foo* by @strong{foo}"""
+    return re.sub(r'\*([^_\n]+)\*', r'@emph{\1}', doc)
+
+
+def subst_emph(doc):
+    """Replaces _foo_ by @emph{foo}"""
+    return re.sub(r'\s_([^_\n]+)_\s', r' @emph{\1} ', doc)
+
+
+def subst_vars(doc):
+    """Replaces @var by @var{var}"""
+    return re.sub(r'@([\w-]+)', r'@var{\1}', doc)
+
+
+def subst_braces(doc):
+    """Replaces {} with @{ @}"""
+    return doc.replace("{", "@{").replace("}", "@}")
+
+
+def texi_example(doc):
+    """Format @example"""
+    doc = subst_braces(doc).strip('\n')
+    return EXAMPLE_FMT(code=doc)
+
+
+def texi_comment(doc):
+    """
+    Format a comment
+
+    Lines starting with:
+    - |: generates an @example
+    - =: generates @section
+    - ==: generates @subsection
+    - 1. or 1): generates an @enumerate @item
+    - o/*/-: generates an @itemize list
+    """
+    lines = []
+    doc = subst_braces(doc)
+    doc = subst_vars(doc)
+    doc = subst_emph(doc)
+    doc = subst_strong(doc)
+    inlist = ""
+    lastempty = False
+    for line in doc.split('\n'):
+        empty = line == ""
+
+        if line.startswith("| "):
+            line = EXAMPLE_FMT(code=line[1:])
+        elif line.startswith("= "):
+            line = "@section " + line[1:]
+        elif line.startswith("== "):
+            line = "@subsection " + line[2:]
+        elif re.match("^([0-9]*[.)]) ", line):
+            if not inlist:
+                lines.append("@enumerate")
+                inlist = "enumerate"
+            line = line[line.find(" ")+1:]
+            lines.append("@item")
+        elif re.match("^[o*-] ", line):
+            if not inlist:
+                lines.append("@itemize %s" % {'o': "@bullet",
+                                              '*': "@minus",
+                                              '-': ""}[line[0]])
+                inlist = "itemize"
+            lines.append("@item")
+            line = line[2:]
+        elif lastempty and inlist:
+            lines.append("@end %s\n" % inlist)
+            inlist = ""
+
+        lastempty = empty
+        lines.append(line)
+
+    if inlist:
+        lines.append("@end %s\n" % inlist)
+    return "\n".join(lines)
+
+
+def texi_args(expr):
+    """
+    Format the functions/structure/events.. arguments/members
+    """
+    data = expr["data"] if "data" in expr else {}
+    if isinstance(data, str):
+        args = data
+    else:
+        arg_list = []
+        for name, typ in data.iteritems():
+            # optional arg
+            if name.startswith("*"):
+                name = name[1:]
+                arg_list.append("['%s': @var{%s}]" % (name, typ))
+            # regular arg
+            else:
+                arg_list.append("'%s': @var{%s}" % (name, typ))
+        args = ", ".join(arg_list)
+    return args
+
+def section_order(section):
+    return {"Returns": 0,
+            "Note": 1,
+            "Notes": 1,
+            "Since": 2,
+            "Example": 3,
+            "Examples": 3}[section]
+
+def texi_body(doc, arg="@var"):
+    """
+    Format the body of a symbol documentation:
+    - a table of arguments
+    - followed by "Returns/Notes/Since/Example" sections
+    """
+    body = "@table %s\n" % arg
+    for arg, desc in doc.args.iteritems():
+        if desc.startswith("#optional"):
+            desc = desc[10:]
+            arg += "*"
+        elif desc.endswith("#optional"):
+            desc = desc[:-10]
+            arg += "*"
+        body += "@item %s\n%s\n" % (arg, texi_comment(desc))
+    body += "@end table\n"
+    body += texi_comment(doc.get_body())
+
+    meta = sorted(doc.meta, key=lambda i: section_order(i[0]))
+    for m in meta:
+        key, doc = m
+        func = texi_comment
+        if key.startswith("Example"):
+            func = texi_example
+
+        body += "\n@quotation %s\n%s\n@end quotation" % \
+                (key, func(doc))
+    return body
+
+
+def texi_alternate(expr, doc):
+    """
+    Format an alternate to texi
+    """
+    args = texi_args(expr)
+    body = texi_body(doc)
+    return STRUCT_FMT(type="Alternate",
+                      name=doc.symbol,
+                      attrs="[ " + args + " ]",
+                      body=body)
+
+
+def texi_union(expr, doc):
+    """
+    Format an union to texi
+    """
+    args = texi_args(expr)
+    body = texi_body(doc)
+    return STRUCT_FMT(type="Union",
+                      name=doc.symbol,
+                      attrs="[ " + args + " ]",
+                      body=body)
+
+
+def texi_enum(_, doc):
+    """
+    Format an enum to texi
+    """
+    body = texi_body(doc, "@samp")
+    return ENUM_FMT(name=doc.symbol,
+                    body=body)
+
+
+def texi_struct(expr, doc):
+    """
+    Format a struct to texi
+    """
+    args = texi_args(expr)
+    body = texi_body(doc)
+    return STRUCT_FMT(type="Struct",
+                      name=doc.symbol,
+                      attrs="@{ " + args + " @}",
+                      body=body)
+
+
+def texi_command(expr, doc):
+    """
+    Format a command to texi
+    """
+    args = texi_args(expr)
+    ret = expr["returns"] if "returns" in expr else ""
+    body = texi_body(doc)
+    return COMMAND_FMT(type="Command",
+                       name=doc.symbol,
+                       ret=ret,
+                       args="(" + args + ")",
+                       body=body)
+
+
+def texi_event(expr, doc):
+    """
+    Format an event to texi
+    """
+    args = texi_args(expr)
+    body = texi_body(doc)
+    return COMMAND_FMT(type="Event",
+                       name=doc.symbol,
+                       ret="",
+                       args="(" + args + ")",
+                       body=body)
+
+
+def texi(docs):
+    """
+    Convert QAPI schema expressions to texi documentation
+    """
+    res = []
+    for doc in docs:
+        try:
+            expr_elem = doc.expr_elem
+            if expr_elem is None:
+                res.append(texi_body(doc))
+                continue
+
+            expr = expr_elem['expr']
+            (kind, _) = expr.items()[0]
+
+            fmt = {"command": texi_command,
+                   "struct": texi_struct,
+                   "enum": texi_enum,
+                   "union": texi_union,
+                   "alternate": texi_alternate,
+                   "event": texi_event}
+            try:
+                fmt = fmt[kind]
+            except KeyError:
+                raise ValueError("Unknown expression kind '%s'" % kind)
+            res.append(fmt(expr, doc))
+        except:
+            print >>sys.stderr, "error at @%s" % qapi
+            raise
+
+    return '\n'.join(res)
+
+
+def parse_schema(fname):
+    """
+    Parse the given schema file and return the exprs
+    """
+    try:
+        schema = QAPISchemaParser(open(fname, "r"))
+        check_exprs(schema.exprs)
+        check_docs(schema.docs)
+        return schema.docs
+    except (QAPISchemaError, QAPIExprError), err:
+        print >>sys.stderr, err
+        exit(1)
+
+
+def main(argv):
+    """
+    Takes schema argument, prints result to stdout
+    """
+    if len(argv) != 2:
+        print >>sys.stderr, "%s: need exactly 1 argument: SCHEMA" % argv[0]
+        sys.exit(1)
+
+    docs = parse_schema(argv[1])
+    print texi(docs)
+
+
+if __name__ == "__main__":
+    main(sys.argv)
diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
index 2841c51..d82e251 100644
--- a/docs/qapi-code-gen.txt
+++ b/docs/qapi-code-gen.txt
@@ -45,16 +45,13 @@ QAPI parser does not).  At present, there is no place where a QAPI
 schema requires the use of JSON numbers or null.
 
 Comments are allowed; anything between an unquoted # and the following
-newline is ignored.  Although there is not yet a documentation
-generator, a form of stylized comments has developed for consistently
-documenting details about an expression and when it was added to the
-schema.  The documentation is delimited between two lines of ##, then
-the first line names the expression, an optional overview is provided,
-then individual documentation about each member of 'data' is provided,
-and finally, a 'Since: x.y.z' tag lists the release that introduced
-the expression.  Optional members are tagged with the phrase
-'#optional', often with their default value; and extensions added
-after the expression was first released are also given a '(since
+newline is ignored.  The documentation is delimited between two lines
+of ##, then the first line names the expression, an optional overview
+is provided, then individual documentation about each member of 'data'
+is provided, and finally, a 'Since: x.y.z' tag lists the release that
+introduced the expression.  Optional members are tagged with the
+phrase '#optional', often with their default value; and extensions
+added after the expression was first released are also given a '(since
 x.y.z)' comment.  For example:
 
     ##
@@ -73,12 +70,39 @@ x.y.z)' comment.  For example:
     #           (Since 2.0)
     #
     # Since: 0.14.0
+    #
+    # Notes: You can also make a list:
+    #        - with items
+    #        - like this
+    #
+    # Example:
+    #
+    # -> { "execute": ... }
+    # <- { "return": ... }
+    #
     ##
     { 'struct': 'BlockStats',
       'data': {'*device': 'str', 'stats': 'BlockDeviceStats',
                '*parent': 'BlockStats',
                '*backing': 'BlockStats'} }
 
+It's also possible to create documentation sections, such as:
+
+    ##
+    # = Section
+    # == Subsection
+    #
+    # Some text foo with *emphasis*
+    # 1. with a list
+    # 2. like that
+    #
+    # And some code:
+    # | $ echo foo
+    # | -> do this
+    # | <- get that
+    #
+    ##
+
 The schema sets up a series of types, as well as commands and events
 that will use those types.  Forward references are allowed: the parser
 scans in two passes, where the first pass learns all type names, and
-- 
2.10.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Qemu-devel] [PATCH v3 12/14] texi2pod: learn quotation, deftp and deftypefn
  2016-11-07  7:30 [Qemu-devel] [PATCH v3 00/14] qapi doc generation (whole version, squashed) Marc-André Lureau
                   ` (10 preceding siblings ...)
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 11/14] qapi: add qapi2texi script Marc-André Lureau
@ 2016-11-07  7:30 ` Marc-André Lureau
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 13/14] qmp-commands: (SQUASHED) move doc to schema Marc-André Lureau
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 14/14] build-sys: add qapi doc generation targets Marc-André Lureau
  13 siblings, 0 replies; 28+ messages in thread
From: Marc-André Lureau @ 2016-11-07  7:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

Learn a few more markups used for API documentation.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 scripts/texi2pod.pl | 44 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 43 insertions(+), 1 deletion(-)

diff --git a/scripts/texi2pod.pl b/scripts/texi2pod.pl
index 8767662..5df4b5f 100755
--- a/scripts/texi2pod.pl
+++ b/scripts/texi2pod.pl
@@ -37,6 +37,7 @@ $inf = "";
 $ibase = "";
 @ipath = ();
 $encoding = undef;
+@args = ();
 
 while ($_ = shift) {
     if (/^-D(.*)$/) {
@@ -162,7 +163,8 @@ while(<$inf>) {
 	if ($ended =~ /^(?:ifset|ifclear|ignore|menu|iftex)$/) {
 	    $skipping = pop @skstack;
 	    next;
-	} elsif ($ended =~ /^(?:example|smallexample|display)$/) {
+	} elsif ($ended =~ /^(?:example|smallexample|display
+                            |quotation|deftp|deftypefn)$/x) {
 	    $shift = "";
 	    $_ = "";	# need a paragraph break
 	} elsif ($ended =~ /^(?:itemize|enumerate|[fv]?table)$/) {
@@ -323,6 +325,46 @@ while(<$inf>) {
 	$_ = "\n=item ".join (" : ", @columns)."\n";
     };
 
+    /^\@(quotation)\s*(.+)?$/ and do {
+        push @endwstack, $endw;
+        $endw = $1;
+        $_ = "\n$2:"
+    };
+
+    /^{(.*)}$|^(.*)$/ and $#args > 0 and do {
+        $kind = $args[0];
+        $arguments = $1 // "";
+        if ($endw eq "deftypefn") {
+            $ret = $args[1];
+            $fname = "B<$args[2]>";
+            $_ = $ret ? "$ret " : "";
+            $_ .= "$fname $arguments ($kind)";
+        } else {
+            $_ = "B<$args[1]> ($kind)\n\n$arguments";
+        }
+        @args = ();
+    };
+
+    /^\@(deftp)\s*(.+)?$/ and do {
+        push @endwstack, $endw;
+        $endw = $1;
+        $arg = $2;
+        $arg =~ s/{([^}]*)}/$1/g;
+        $arg =~ s/\@$//;
+        @args = split (/ /, $arg);
+        $_ = "";
+    };
+
+    /^\@(deftypefn)\s*(.+)?$/ and do {
+        push @endwstack, $endw;
+        $endw = $1;
+        $arg = $2;
+        $arg =~ s/{([^}]*)}/$1/g;
+        $arg =~ s/\@$//;
+        @args = split (/ /, $arg);
+        $_ = "";
+    };
+
     /^\@itemx?\s*(.+)?$/ and do {
 	if (defined $1) {
 	    # Entity escapes prevent munging by the <> processing below.
-- 
2.10.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Qemu-devel] [PATCH v3 13/14] qmp-commands: (SQUASHED) move doc to schema
  2016-11-07  7:30 [Qemu-devel] [PATCH v3 00/14] qapi doc generation (whole version, squashed) Marc-André Lureau
                   ` (11 preceding siblings ...)
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 12/14] texi2pod: learn quotation, deftp and deftypefn Marc-André Lureau
@ 2016-11-07  7:30 ` Marc-André Lureau
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 14/14] build-sys: add qapi doc generation targets Marc-André Lureau
  13 siblings, 0 replies; 28+ messages in thread
From: Marc-André Lureau @ 2016-11-07  7:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 Makefile              |    1 -
 docs/qmp-commands.txt | 3824 -------------------------------------------------
 docs/qmp-events.txt   |  731 ----------
 qapi-schema.json      | 1279 ++++++++++++++++-
 qapi/block-core.json  |  679 ++++++++-
 qapi/block.json       |   56 +-
 qapi/common.json      |   32 +
 qapi/event.json       |  240 ++++
 qapi/rocker.json      |   57 +-
 qapi/trace.json       |   14 +
 10 files changed, 2309 insertions(+), 4604 deletions(-)
 delete mode 100644 docs/qmp-commands.txt
 delete mode 100644 docs/qmp-events.txt

diff --git a/Makefile b/Makefile
index 474cc5e..3617736 100644
--- a/Makefile
+++ b/Makefile
@@ -431,7 +431,6 @@ endif
 install-doc: $(DOCS)
 	$(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
 	$(INSTALL_DATA) qemu-doc.html "$(DESTDIR)$(qemu_docdir)"
-	$(INSTALL_DATA) $(SRC_PATH)/docs/qmp-commands.txt "$(DESTDIR)$(qemu_docdir)"
 ifdef CONFIG_POSIX
 	$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
 	$(INSTALL_DATA) qemu.1 "$(DESTDIR)$(mandir)/man1"
diff --git a/docs/qmp-commands.txt b/docs/qmp-commands.txt
deleted file mode 100644
index 6afa872..0000000
--- a/docs/qmp-commands.txt
+++ /dev/null
@@ -1,3824 +0,0 @@
-                        QMP Supported Commands
-                        ----------------------
-
-This document describes all commands currently supported by QMP.
-
-Most of the time their usage is exactly the same as in the user Monitor, this
-means that any other document which also describe commands (the manpage,
-QEMU's manual, etc) can and should be consulted.
-
-QMP has two types of commands: regular and query commands. Regular commands
-usually change the Virtual Machine's state someway, while query commands just
-return information. The sections below are divided accordingly.
-
-It's important to observe that all communication examples are formatted in
-a reader-friendly way, so that they're easier to understand. However, in real
-protocol usage, they're emitted as a single line.
-
-Also, the following notation is used to denote data flow:
-
--> data issued by the Client
-<- Server data response
-
-Please, refer to the QMP specification (docs/qmp-spec.txt) for detailed
-information on the Server command and response formats.
-
-NOTE: This document is temporary and will be replaced soon.
-
-1. Stability Considerations
-===========================
-
-The current QMP command set (described in this file) may be useful for a
-number of use cases, however it's limited and several commands have bad
-defined semantics, specially with regard to command completion.
-
-These problems are going to be solved incrementally in the next QEMU releases
-and we're going to establish a deprecation policy for badly defined commands.
-
-If you're planning to adopt QMP, please observe the following:
-
-    1. The deprecation policy will take effect and be documented soon, please
-       check the documentation of each used command as soon as a new release of
-       QEMU is available
-
-    2. DO NOT rely on anything which is not explicit documented
-
-    3. Errors, in special, are not documented. Applications should NOT check
-       for specific errors classes or data (it's strongly recommended to only
-       check for the "error" key)
-
-2. Regular Commands
-===================
-
-Server's responses in the examples below are always a success response, please
-refer to the QMP specification for more details on error responses.
-
-quit
-----
-
-Quit the emulator.
-
-Arguments: None.
-
-Example:
-
--> { "execute": "quit" }
-<- { "return": {} }
-
-eject
------
-
-Eject a removable medium.
-
-Arguments:
-
-- "force": force ejection (json-bool, optional)
-- "device": block device name (deprecated, use @id instead)
-            (json-string, optional)
-- "id": the name or QOM path of the guest device (json-string, optional)
-
-Example:
-
--> { "execute": "eject", "arguments": { "id": "ide0-1-0" } }
-<- { "return": {} }
-
-Note: The "force" argument defaults to false.
-
-change
-------
-
-Change a removable medium or VNC configuration.
-
-Arguments:
-
-- "device": device name (json-string)
-- "target": filename or item (json-string)
-- "arg": additional argument (json-string, optional)
-
-Examples:
-
-1. Change a removable medium
-
--> { "execute": "change",
-             "arguments": { "device": "ide1-cd0",
-                            "target": "/srv/images/Fedora-12-x86_64-DVD.iso" } }
-<- { "return": {} }
-
-2. Change VNC password
-
--> { "execute": "change",
-             "arguments": { "device": "vnc", "target": "password",
-                            "arg": "foobar1" } }
-<- { "return": {} }
-
-screendump
-----------
-
-Save screen into PPM image.
-
-Arguments:
-
-- "filename": file path (json-string)
-
-Example:
-
--> { "execute": "screendump", "arguments": { "filename": "/tmp/image" } }
-<- { "return": {} }
-
-stop
-----
-
-Stop the emulator.
-
-Arguments: None.
-
-Example:
-
--> { "execute": "stop" }
-<- { "return": {} }
-
-cont
-----
-
-Resume emulation.
-
-Arguments: None.
-
-Example:
-
--> { "execute": "cont" }
-<- { "return": {} }
-
-system_wakeup
--------------
-
-Wakeup guest from suspend.
-
-Arguments: None.
-
-Example:
-
--> { "execute": "system_wakeup" }
-<- { "return": {} }
-
-system_reset
-------------
-
-Reset the system.
-
-Arguments: None.
-
-Example:
-
--> { "execute": "system_reset" }
-<- { "return": {} }
-
-system_powerdown
-----------------
-
-Send system power down event.
-
-Arguments: None.
-
-Example:
-
--> { "execute": "system_powerdown" }
-<- { "return": {} }
-
-device_add
-----------
-
-Add a device.
-
-Arguments:
-
-- "driver": the name of the new device's driver (json-string)
-- "bus": the device's parent bus (device tree path, json-string, optional)
-- "id": the device's ID, must be unique (json-string)
-- device properties
-
-Example:
-
--> { "execute": "device_add", "arguments": { "driver": "e1000", "id": "net1" } }
-<- { "return": {} }
-
-Notes:
-
-(1) For detailed information about this command, please refer to the
-    'docs/qdev-device-use.txt' file.
-
-(2) It's possible to list device properties by running QEMU with the
-    "-device DEVICE,\?" command-line argument, where DEVICE is the device's name
-
-device_del
-----------
-
-Remove a device.
-
-Arguments:
-
-- "id": the device's ID or QOM path (json-string)
-
-Example:
-
--> { "execute": "device_del", "arguments": { "id": "net1" } }
-<- { "return": {} }
-
-Example:
-
--> { "execute": "device_del", "arguments": { "id": "/machine/peripheral-anon/device[0]" } }
-<- { "return": {} }
-
-send-key
-----------
-
-Send keys to VM.
-
-Arguments:
-
-keys array:
-    - "key": key sequence (a json-array of key union values,
-             union can be number or qcode enum)
-
-- hold-time: time to delay key up events, milliseconds. Defaults to 100
-             (json-int, optional)
-
-Example:
-
--> { "execute": "send-key",
-     "arguments": { "keys": [ { "type": "qcode", "data": "ctrl" },
-                              { "type": "qcode", "data": "alt" },
-                              { "type": "qcode", "data": "delete" } ] } }
-<- { "return": {} }
-
-cpu
----
-
-Set the default CPU.
-
-Arguments:
-
-- "index": the CPU's index (json-int)
-
-Example:
-
--> { "execute": "cpu", "arguments": { "index": 0 } }
-<- { "return": {} }
-
-Note: CPUs' indexes are obtained with the 'query-cpus' command.
-
-cpu-add
--------
-
-Adds virtual cpu
-
-Arguments:
-
-- "id": cpu id (json-int)
-
-Example:
-
--> { "execute": "cpu-add", "arguments": { "id": 2 } }
-<- { "return": {} }
-
-memsave
--------
-
-Save to disk virtual memory dump starting at 'val' of size 'size'.
-
-Arguments:
-
-- "val": the starting address (json-int)
-- "size": the memory size, in bytes (json-int)
-- "filename": file path (json-string)
-- "cpu": virtual CPU index (json-int, optional)
-
-Example:
-
--> { "execute": "memsave",
-             "arguments": { "val": 10,
-                            "size": 100,
-                            "filename": "/tmp/virtual-mem-dump" } }
-<- { "return": {} }
-
-pmemsave
---------
-
-Save to disk physical memory dump starting at 'val' of size 'size'.
-
-Arguments:
-
-- "val": the starting address (json-int)
-- "size": the memory size, in bytes (json-int)
-- "filename": file path (json-string)
-
-Example:
-
--> { "execute": "pmemsave",
-             "arguments": { "val": 10,
-                            "size": 100,
-                            "filename": "/tmp/physical-mem-dump" } }
-<- { "return": {} }
-
-inject-nmi
-----------
-
-Inject an NMI on the default CPU (x86/s390) or all CPUs (ppc64).
-
-Arguments: None.
-
-Example:
-
--> { "execute": "inject-nmi" }
-<- { "return": {} }
-
-Note: inject-nmi fails when the guest doesn't support injecting.
-
-ringbuf-write
--------------
-
-Write to a ring buffer character device.
-
-Arguments:
-
-- "device": ring buffer character device name (json-string)
-- "data": data to write (json-string)
-- "format": data format (json-string, optional)
-          - Possible values: "utf8" (default), "base64"
-
-Example:
-
--> { "execute": "ringbuf-write",
-                "arguments": { "device": "foo",
-                               "data": "abcdefgh",
-                               "format": "utf8" } }
-<- { "return": {} }
-
-ringbuf-read
--------------
-
-Read from a ring buffer character device.
-
-Arguments:
-
-- "device": ring buffer character device name (json-string)
-- "size": how many bytes to read at most (json-int)
-          - Number of data bytes, not number of characters in encoded data
-- "format": data format (json-string, optional)
-          - Possible values: "utf8" (default), "base64"
-          - Naturally, format "utf8" works only when the ring buffer
-            contains valid UTF-8 text.  Invalid UTF-8 sequences get
-            replaced.  Bug: replacement doesn't work.  Bug: can screw
-            up on encountering NUL characters, after the ring buffer
-            lost data, and when reading stops because the size limit
-            is reached.
-
-Example:
-
--> { "execute": "ringbuf-read",
-                "arguments": { "device": "foo",
-                               "size": 1000,
-                               "format": "utf8" } }
-<- {"return": "abcdefgh"}
-
-xen-save-devices-state
--------
-
-Save the state of all devices to file. The RAM and the block devices
-of the VM are not saved by this command.
-
-Arguments:
-
-- "filename": the file to save the state of the devices to as binary
-data. See xen-save-devices-state.txt for a description of the binary
-format.
-
-Example:
-
--> { "execute": "xen-save-devices-state",
-     "arguments": { "filename": "/tmp/save" } }
-<- { "return": {} }
-
-xen-load-devices-state
-----------------------
-
-Load the state of all devices from file. The RAM and the block devices
-of the VM are not loaded by this command.
-
-Arguments:
-
-- "filename": the file to load the state of the devices from as binary
-data. See xen-save-devices-state.txt for a description of the binary
-format.
-
-Example:
-
--> { "execute": "xen-load-devices-state",
-     "arguments": { "filename": "/tmp/resume" } }
-<- { "return": {} }
-
-xen-set-global-dirty-log
--------
-
-Enable or disable the global dirty log mode.
-
-Arguments:
-
-- "enable": Enable it or disable it.
-
-Example:
-
--> { "execute": "xen-set-global-dirty-log",
-     "arguments": { "enable": true } }
-<- { "return": {} }
-
-migrate
--------
-
-Migrate to URI.
-
-Arguments:
-
-- "blk": block migration, full disk copy (json-bool, optional)
-- "inc": incremental disk copy (json-bool, optional)
-- "uri": Destination URI (json-string)
-
-Example:
-
--> { "execute": "migrate", "arguments": { "uri": "tcp:0:4446" } }
-<- { "return": {} }
-
-Notes:
-
-(1) The 'query-migrate' command should be used to check migration's progress
-    and final result (this information is provided by the 'status' member)
-(2) All boolean arguments default to false
-(3) The user Monitor's "detach" argument is invalid in QMP and should not
-    be used
-
-migrate_cancel
---------------
-
-Cancel the current migration.
-
-Arguments: None.
-
-Example:
-
--> { "execute": "migrate_cancel" }
-<- { "return": {} }
-
-migrate-incoming
-----------------
-
-Continue an incoming migration
-
-Arguments:
-
-- "uri": Source/listening URI (json-string)
-
-Example:
-
--> { "execute": "migrate-incoming", "arguments": { "uri": "tcp::4446" } }
-<- { "return": {} }
-
-Notes:
-
-(1) QEMU must be started with -incoming defer to allow migrate-incoming to
-    be used
-(2) The uri format is the same as for -incoming
-
-migrate-set-cache-size
-----------------------
-
-Set cache size to be used by XBZRLE migration, the cache size will be rounded
-down to the nearest power of 2
-
-Arguments:
-
-- "value": cache size in bytes (json-int)
-
-Example:
-
--> { "execute": "migrate-set-cache-size", "arguments": { "value": 536870912 } }
-<- { "return": {} }
-
-migrate-start-postcopy
-----------------------
-
-Switch an in-progress migration to postcopy mode. Ignored after the end of
-migration (or once already in postcopy).
-
-Example:
--> { "execute": "migrate-start-postcopy" }
-<- { "return": {} }
-
-query-migrate-cache-size
-------------------------
-
-Show cache size to be used by XBZRLE migration
-
-returns a json-object with the following information:
-- "size" : json-int
-
-Example:
-
--> { "execute": "query-migrate-cache-size" }
-<- { "return": 67108864 }
-
-migrate_set_speed
------------------
-
-Set maximum speed for migrations.
-
-Arguments:
-
-- "value": maximum speed, in bytes per second (json-int)
-
-Example:
-
--> { "execute": "migrate_set_speed", "arguments": { "value": 1024 } }
-<- { "return": {} }
-
-migrate_set_downtime
---------------------
-
-Set maximum tolerated downtime (in seconds) for migrations.
-
-Arguments:
-
-- "value": maximum downtime (json-number)
-
-Example:
-
--> { "execute": "migrate_set_downtime", "arguments": { "value": 0.1 } }
-<- { "return": {} }
-
-x-colo-lost-heartbeat
---------------------
-
-Tell COLO that heartbeat is lost, a failover or takeover is needed.
-
-Example:
-
--> { "execute": "x-colo-lost-heartbeat" }
-<- { "return": {} }
-
-client_migrate_info
--------------------
-
-Set migration information for remote display.  This makes the server
-ask the client to automatically reconnect using the new parameters
-once migration finished successfully.  Only implemented for SPICE.
-
-Arguments:
-
-- "protocol":     must be "spice" (json-string)
-- "hostname":     migration target hostname (json-string)
-- "port":         spice tcp port for plaintext channels (json-int, optional)
-- "tls-port":     spice tcp port for tls-secured channels (json-int, optional)
-- "cert-subject": server certificate subject (json-string, optional)
-
-Example:
-
--> { "execute": "client_migrate_info",
-     "arguments": { "protocol": "spice",
-                    "hostname": "virt42.lab.kraxel.org",
-                    "port": 1234 } }
-<- { "return": {} }
-
-dump
-
-
-Dump guest memory to file. The file can be processed with crash or gdb.
-
-Arguments:
-
-- "paging": do paging to get guest's memory mapping (json-bool)
-- "protocol": destination file(started with "file:") or destination file
-              descriptor (started with "fd:") (json-string)
-- "detach": if specified, command will return immediately, without waiting
-            for the dump to finish. The user can track progress using
-            "query-dump". (json-bool)
-- "begin": the starting physical address. It's optional, and should be specified
-           with length together (json-int)
-- "length": the memory size, in bytes. It's optional, and should be specified
-            with begin together (json-int)
-- "format": the format of guest memory dump. It's optional, and can be
-            elf|kdump-zlib|kdump-lzo|kdump-snappy, but non-elf formats will
-            conflict with paging and filter, ie. begin and length (json-string)
-
-Example:
-
--> { "execute": "dump-guest-memory", "arguments": { "protocol": "fd:dump" } }
-<- { "return": {} }
-
-Notes:
-
-(1) All boolean arguments default to false
-
-query-dump-guest-memory-capability
-----------
-
-Show available formats for 'dump-guest-memory'
-
-Example:
-
--> { "execute": "query-dump-guest-memory-capability" }
-<- { "return": { "formats":
-                    ["elf", "kdump-zlib", "kdump-lzo", "kdump-snappy"] }
-
-query-dump
-----------
-
-Query background dump status.
-
-Arguments: None.
-
-Example:
-
--> { "execute": "query-dump" }
-<- { "return": { "status": "active", "completed": 1024000,
-                 "total": 2048000 } }
-
-dump-skeys
-----------
-
-Save guest storage keys to file.
-
-Arguments:
-
-- "filename": file path (json-string)
-
-Example:
-
--> { "execute": "dump-skeys", "arguments": { "filename": "/tmp/skeys" } }
-<- { "return": {} }
-
-netdev_add
-----------
-
-Add host network device.
-
-Arguments:
-
-- "type": the device type, "tap", "user", ... (json-string)
-- "id": the device's ID, must be unique (json-string)
-- device options
-
-Example:
-
--> { "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'
-      command-line argument, which are listed in the '-help' output or QEMU's
-      manual
-
-netdev_del
-----------
-
-Remove host network device.
-
-Arguments:
-
-- "id": the device's ID, must be unique (json-string)
-
-Example:
-
--> { "execute": "netdev_del", "arguments": { "id": "netdev1" } }
-<- { "return": {} }
-
-
-object-add
-----------
-
-Create QOM object.
-
-Arguments:
-
-- "qom-type": the object's QOM type, i.e. the class name (json-string)
-- "id": the object's ID, must be unique (json-string)
-- "props": a dictionary of object property values (optional, json-dict)
-
-Example:
-
--> { "execute": "object-add", "arguments": { "qom-type": "rng-random", "id": "rng1",
-     "props": { "filename": "/dev/hwrng" } } }
-<- { "return": {} }
-
-object-del
-----------
-
-Remove QOM object.
-
-Arguments:
-
-- "id": the object's ID (json-string)
-
-Example:
-
--> { "execute": "object-del", "arguments": { "id": "rng1" } }
-<- { "return": {} }
-
-
-block_resize
-------------
-
-Resize a block image while a guest is running.
-
-Arguments:
-
-- "device": the device's ID, must be unique (json-string)
-- "node-name": the node name in the block driver state graph (json-string)
-- "size": new size
-
-Example:
-
--> { "execute": "block_resize", "arguments": { "device": "scratch", "size": 1073741824 } }
-<- { "return": {} }
-
-block-stream
-------------
-
-Copy data from a backing file into a block device.
-
-Arguments:
-
-- "job-id": Identifier for the newly-created block job. If omitted,
-            the device name will be used. (json-string, optional)
-- "device": The device name or node-name of a root node (json-string)
-- "base": The file name of the backing image above which copying starts.
-          It cannot be set if 'base-node' is also set (json-string, optional)
-- "base-node": the node name of the backing image above which copying starts.
-               It cannot be set if 'base' is also set.
-               (json-string, optional) (Since 2.8)
-- "backing-file": The backing file string to write into the active layer. This
-                  filename is not validated.
-
-                  If a pathname string is such that it cannot be resolved by
-                  QEMU, that means that subsequent QMP or HMP commands must use
-                  node-names for the image in question, as filename lookup
-                  methods will fail.
-
-                  If not specified, QEMU will automatically determine the
-                  backing file string to use, or error out if there is no
-                  obvious choice.  Care should be taken when specifying the
-                  string, to specify a valid filename or protocol.
-                  (json-string, optional) (Since 2.1)
-- "speed":  the maximum speed, in bytes per second (json-int, optional)
-- "on-error": the action to take on an error (default 'report').  'stop' and
-              'enospc' can only be used if the block device supports io-status.
-              (json-string, optional) (Since 2.1)
-
-Example:
-
--> { "execute": "block-stream", "arguments": { "device": "virtio0",
-                                               "base": "/tmp/master.qcow2" } }
-<- { "return": {} }
-
-block-commit
-------------
-
-Live commit of data from overlay image nodes into backing nodes - i.e., writes
-data between 'top' and 'base' into 'base'.
-
-Arguments:
-
-- "job-id": Identifier for the newly-created block job. If omitted,
-            the device name will be used. (json-string, optional)
-- "device": The device name or node-name of a root node (json-string)
-- "base": The file name of the backing image to write data into.
-          If not specified, this is the deepest backing image
-          (json-string, optional)
-- "top":  The file name of the backing image within the image chain,
-          which contains the topmost data to be committed down. If
-          not specified, this is the active layer. (json-string, optional)
-
-- backing-file:     The backing file string to write into the overlay
-                    image of 'top'.  If 'top' is the active layer,
-                    specifying a backing file string is an error. This
-                    filename is not validated.
-
-                    If a pathname string is such that it cannot be
-                    resolved by QEMU, that means that subsequent QMP or
-                    HMP commands must use node-names for the image in
-                    question, as filename lookup methods will fail.
-
-                    If not specified, QEMU will automatically determine
-                    the backing file string to use, or error out if
-                    there is no obvious choice. Care should be taken
-                    when specifying the string, to specify a valid
-                    filename or protocol.
-                    (json-string, optional) (Since 2.1)
-
-          If top == base, that is an error.
-          If top == active, the job will not be completed by itself,
-          user needs to complete the job with the block-job-complete
-          command after getting the ready event. (Since 2.0)
-
-          If the base image is smaller than top, then the base image
-          will be resized to be the same size as top.  If top is
-          smaller than the base image, the base will not be
-          truncated.  If you want the base image size to match the
-          size of the smaller top, you can safely truncate it
-          yourself once the commit operation successfully completes.
-          (json-string)
-- "speed":  the maximum speed, in bytes per second (json-int, optional)
-
-
-Example:
-
--> { "execute": "block-commit", "arguments": { "device": "virtio0",
-                                              "top": "/tmp/snap1.qcow2" } }
-<- { "return": {} }
-
-drive-backup
-------------
-
-Start a point-in-time copy of a block device to a new destination.  The
-status of ongoing drive-backup operations can be checked with
-query-block-jobs where the BlockJobInfo.type field has the value 'backup'.
-The operation can be stopped before it has completed using the
-block-job-cancel command.
-
-Arguments:
-
-- "job-id": Identifier for the newly-created block job. If omitted,
-            the device name will be used. (json-string, optional)
-- "device": the device name or node-name of a root node which should be copied.
-            (json-string)
-- "target": the target of the new image. If the file exists, or if it is a
-            device, the existing file/device will be used as the new
-            destination.  If it does not exist, a new file will be created.
-            (json-string)
-- "format": the format of the new destination, default is to probe if 'mode' is
-            'existing', else the format of the source
-            (json-string, optional)
-- "sync": what parts of the disk image should be copied to the destination;
-  possibilities include "full" for all the disk, "top" for only the sectors
-  allocated in the topmost image, "incremental" for only the dirty sectors in
-  the bitmap, or "none" to only replicate new I/O (MirrorSyncMode).
-- "bitmap": dirty bitmap name for sync==incremental. Must be present if sync
-            is "incremental", must NOT be present otherwise.
-- "mode": whether and how QEMU should create a new image
-          (NewImageMode, optional, default 'absolute-paths')
-- "speed": the maximum speed, in bytes per second (json-int, optional)
-- "compress": true to compress data, if the target format supports it.
-              (json-bool, optional, default false)
-- "on-source-error": the action to take on an error on the source, default
-                     'report'.  'stop' and 'enospc' can only be used
-                     if the block device supports io-status.
-                     (BlockdevOnError, optional)
-- "on-target-error": the action to take on an error on the target, default
-                     'report' (no limitations, since this applies to
-                     a different block device than device).
-                     (BlockdevOnError, optional)
-
-Example:
--> { "execute": "drive-backup", "arguments": { "device": "drive0",
-                                               "sync": "full",
-                                               "target": "backup.img" } }
-<- { "return": {} }
-
-blockdev-backup
----------------
-
-The device version of drive-backup: this command takes an existing named device
-as backup target.
-
-Arguments:
-
-- "job-id": Identifier for the newly-created block job. If omitted,
-            the device name will be used. (json-string, optional)
-- "device": the device name or node-name of a root node which should be copied.
-            (json-string)
-- "target": the name of the backup target device. (json-string)
-- "sync": what parts of the disk image should be copied to the destination;
-          possibilities include "full" for all the disk, "top" for only the
-          sectors allocated in the topmost image, or "none" to only replicate
-          new I/O (MirrorSyncMode).
-- "speed": the maximum speed, in bytes per second (json-int, optional)
-- "compress": true to compress data, if the target format supports it.
-              (json-bool, optional, default false)
-- "on-source-error": the action to take on an error on the source, default
-                     'report'.  'stop' and 'enospc' can only be used
-                     if the block device supports io-status.
-                     (BlockdevOnError, optional)
-- "on-target-error": the action to take on an error on the target, default
-                     'report' (no limitations, since this applies to
-                     a different block device than device).
-                     (BlockdevOnError, optional)
-
-Example:
--> { "execute": "blockdev-backup", "arguments": { "device": "src-id",
-                                                  "sync": "full",
-                                                  "target": "tgt-id" } }
-<- { "return": {} }
-
-transaction
------------
-
-Atomically operate on one or more block devices.  Operations that are
-currently supported:
-
-    - drive-backup
-    - blockdev-backup
-    - blockdev-snapshot-sync
-    - blockdev-snapshot-internal-sync
-    - abort
-    - block-dirty-bitmap-add
-    - block-dirty-bitmap-clear
-
-Refer to the qemu/qapi-schema.json file for minimum required QEMU
-versions for these operations.  A list of dictionaries is accepted,
-that contains the actions to be performed.  If there is any failure
-performing any of the operations, all operations for the group are
-abandoned.
-
-For external snapshots, the dictionary contains the device, the file to use for
-the new snapshot, and the format.  The default format, if not specified, is
-qcow2.
-
-Each new snapshot defaults to being created by QEMU (wiping any
-contents if the file already exists), but it is also possible to reuse
-an externally-created file.  In the latter case, you should ensure that
-the new image file has the same contents as the current one; QEMU cannot
-perform any meaningful check.  Typically this is achieved by using the
-current image file as the backing file for the new image.
-
-On failure, the original disks pre-snapshot attempt will be used.
-
-For internal snapshots, the dictionary contains the device and the snapshot's
-name.  If an internal snapshot matching name already exists, the request will
-be rejected.  Only some image formats support it, for example, qcow2, rbd,
-and sheepdog.
-
-On failure, qemu will try delete the newly created internal snapshot in the
-transaction.  When an I/O error occurs during deletion, the user needs to fix
-it later with qemu-img or other command.
-
-Arguments:
-
-actions array:
-    - "type": the operation to perform (json-string).  Possible
-              values: "drive-backup", "blockdev-backup",
-                      "blockdev-snapshot-sync",
-                      "blockdev-snapshot-internal-sync",
-                      "abort", "block-dirty-bitmap-add",
-                      "block-dirty-bitmap-clear"
-    - "data": a dictionary.  The contents depend on the value
-      of "type".  When "type" is "blockdev-snapshot-sync":
-      - "device": device name to snapshot (json-string)
-      - "node-name": graph node name to snapshot (json-string)
-      - "snapshot-file": name of new image file (json-string)
-      - "snapshot-node-name": graph node name of the new snapshot (json-string)
-      - "format": format of new image (json-string, optional)
-      - "mode": whether and how QEMU should create the snapshot file
-        (NewImageMode, optional, default "absolute-paths")
-      When "type" is "blockdev-snapshot-internal-sync":
-      - "device": the device name or node-name of a root node to snapshot
-                  (json-string)
-      - "name": name of the new snapshot (json-string)
-
-Example:
-
--> { "execute": "transaction",
-     "arguments": { "actions": [
-         { "type": "blockdev-snapshot-sync", "data" : { "device": "ide-hd0",
-                                         "snapshot-file": "/some/place/my-image",
-                                         "format": "qcow2" } },
-         { "type": "blockdev-snapshot-sync", "data" : { "node-name": "myfile",
-                                         "snapshot-file": "/some/place/my-image2",
-                                         "snapshot-node-name": "node3432",
-                                         "mode": "existing",
-                                         "format": "qcow2" } },
-         { "type": "blockdev-snapshot-sync", "data" : { "device": "ide-hd1",
-                                         "snapshot-file": "/some/place/my-image2",
-                                         "mode": "existing",
-                                         "format": "qcow2" } },
-         { "type": "blockdev-snapshot-internal-sync", "data" : {
-                                         "device": "ide-hd2",
-                                         "name": "snapshot0" } } ] } }
-<- { "return": {} }
-
-block-dirty-bitmap-add
-----------------------
-Since 2.4
-
-Create a dirty bitmap with a name on the device, and start tracking the writes.
-
-Arguments:
-
-- "node": device/node on which to create dirty bitmap (json-string)
-- "name": name of the new dirty bitmap (json-string)
-- "granularity": granularity to track writes with (int, optional)
-
-Example:
-
--> { "execute": "block-dirty-bitmap-add", "arguments": { "node": "drive0",
-                                                   "name": "bitmap0" } }
-<- { "return": {} }
-
-block-dirty-bitmap-remove
--------------------------
-Since 2.4
-
-Stop write tracking and remove the dirty bitmap that was created with
-block-dirty-bitmap-add.
-
-Arguments:
-
-- "node": device/node on which to remove dirty bitmap (json-string)
-- "name": name of the dirty bitmap to remove (json-string)
-
-Example:
-
--> { "execute": "block-dirty-bitmap-remove", "arguments": { "node": "drive0",
-                                                      "name": "bitmap0" } }
-<- { "return": {} }
-
-block-dirty-bitmap-clear
-------------------------
-Since 2.4
-
-Reset the dirty bitmap associated with a node so that an incremental backup
-from this point in time forward will only backup clusters modified after this
-clear operation.
-
-Arguments:
-
-- "node": device/node on which to remove dirty bitmap (json-string)
-- "name": name of the dirty bitmap to remove (json-string)
-
-Example:
-
--> { "execute": "block-dirty-bitmap-clear", "arguments": { "node": "drive0",
-                                                           "name": "bitmap0" } }
-<- { "return": {} }
-
-blockdev-snapshot-sync
-----------------------
-
-Synchronous snapshot of a block device. snapshot-file specifies the
-target of the new image. If the file exists, or if it is a device, the
-snapshot will be created in the existing file/device. If does not
-exist, a new file will be created. format specifies the format of the
-snapshot image, default is qcow2.
-
-Arguments:
-
-- "device": device name to snapshot (json-string)
-- "node-name": graph node name to snapshot (json-string)
-- "snapshot-file": name of new image file (json-string)
-- "snapshot-node-name": graph node name of the new snapshot (json-string)
-- "mode": whether and how QEMU should create the snapshot file
-  (NewImageMode, optional, default "absolute-paths")
-- "format": format of new image (json-string, optional)
-
-Example:
-
--> { "execute": "blockdev-snapshot-sync", "arguments": { "device": "ide-hd0",
-                                                         "snapshot-file":
-                                                        "/some/place/my-image",
-                                                        "format": "qcow2" } }
-<- { "return": {} }
-
-blockdev-snapshot
------------------
-Since 2.5
-
-Create a snapshot, by installing 'node' as the backing image of
-'overlay'. Additionally, if 'node' is associated with a block
-device, the block device changes to using 'overlay' as its new active
-image.
-
-Arguments:
-
-- "node": device that will have a snapshot created (json-string)
-- "overlay": device that will have 'node' as its backing image (json-string)
-
-Example:
-
--> { "execute": "blockdev-add",
-                "arguments": { "driver": "qcow2",
-                               "node-name": "node1534",
-                               "file": { "driver": "file",
-                                         "filename": "hd1.qcow2" },
-                               "backing": "" } }
-
-<- { "return": {} }
-
--> { "execute": "blockdev-snapshot", "arguments": { "node": "ide-hd0",
-                                                    "overlay": "node1534" } }
-<- { "return": {} }
-
-blockdev-snapshot-internal-sync
--------------------------------
-
-Synchronously take an internal snapshot of a block device when the format of
-image used supports it.  If the name is an empty string, or a snapshot with
-name already exists, the operation will fail.
-
-Arguments:
-
-- "device": the device name or node-name of a root node to snapshot
-            (json-string)
-- "name": name of the new snapshot (json-string)
-
-Example:
-
--> { "execute": "blockdev-snapshot-internal-sync",
-                "arguments": { "device": "ide-hd0",
-                               "name": "snapshot0" }
-   }
-<- { "return": {} }
-
-blockdev-snapshot-delete-internal-sync
---------------------------------------
-
-Synchronously delete an internal snapshot of a block device when the format of
-image used supports it.  The snapshot is identified by name or id or both.  One
-of name or id is required.  If the snapshot is not found, the operation will
-fail.
-
-Arguments:
-
-- "device": the device name or node-name of a root node (json-string)
-- "id": ID of the snapshot (json-string, optional)
-- "name": name of the snapshot (json-string, optional)
-
-Example:
-
--> { "execute": "blockdev-snapshot-delete-internal-sync",
-                "arguments": { "device": "ide-hd0",
-                               "name": "snapshot0" }
-   }
-<- { "return": {
-                   "id": "1",
-                   "name": "snapshot0",
-                   "vm-state-size": 0,
-                   "date-sec": 1000012,
-                   "date-nsec": 10,
-                   "vm-clock-sec": 100,
-                   "vm-clock-nsec": 20
-     }
-   }
-
-drive-mirror
-------------
-
-Start mirroring a block device's writes to a new destination. target
-specifies the target of the new image. If the file exists, or if it is
-a device, it will be used as the new destination for writes. If it does not
-exist, a new file will be created. format specifies the format of the
-mirror image, default is to probe if mode='existing', else the format
-of the source.
-
-Arguments:
-
-- "job-id": Identifier for the newly-created block job. If omitted,
-            the device name will be used. (json-string, optional)
-- "device": the device name or node-name of a root node whose writes should be
-            mirrored. (json-string)
-- "target": name of new image file (json-string)
-- "format": format of new image (json-string, optional)
-- "node-name": the name of the new block driver state in the node graph
-               (json-string, optional)
-- "replaces": the block driver node name to replace when finished
-              (json-string, optional)
-- "mode": how an image file should be created into the target
-  file/device (NewImageMode, optional, default 'absolute-paths')
-- "speed": maximum speed of the streaming job, in bytes per second
-  (json-int)
-- "granularity": granularity of the dirty bitmap, in bytes (json-int, optional)
-- "buf-size": maximum amount of data in flight from source to target, in bytes
-  (json-int, default 10M)
-- "sync": what parts of the disk image should be copied to the destination;
-  possibilities include "full" for all the disk, "top" for only the sectors
-  allocated in the topmost image, or "none" to only replicate new I/O
-  (MirrorSyncMode).
-- "on-source-error": the action to take on an error on the source
-  (BlockdevOnError, default 'report')
-- "on-target-error": the action to take on an error on the target
-  (BlockdevOnError, default 'report')
-- "unmap": whether the target sectors should be discarded where source has only
-  zeroes. (json-bool, optional, default true)
-
-The default value of the granularity is the image cluster size clamped
-between 4096 and 65536, if the image format defines one.  If the format
-does not define a cluster size, the default value of the granularity
-is 65536.
-
-
-Example:
-
--> { "execute": "drive-mirror", "arguments": { "device": "ide-hd0",
-                                               "target": "/some/place/my-image",
-                                               "sync": "full",
-                                               "format": "qcow2" } }
-<- { "return": {} }
-
-blockdev-mirror
-------------
-
-Start mirroring a block device's writes to another block device. target
-specifies the target of mirror operation.
-
-Arguments:
-
-- "job-id": Identifier for the newly-created block job. If omitted,
-            the device name will be used. (json-string, optional)
-- "device": The device name or node-name of a root node whose writes should be
-            mirrored (json-string)
-- "target": device name to mirror to (json-string)
-- "replaces": the block driver node name to replace when finished
-              (json-string, optional)
-- "speed": maximum speed of the streaming job, in bytes per second
-  (json-int)
-- "granularity": granularity of the dirty bitmap, in bytes (json-int, optional)
-- "buf_size": maximum amount of data in flight from source to target, in bytes
-  (json-int, default 10M)
-- "sync": what parts of the disk image should be copied to the destination;
-  possibilities include "full" for all the disk, "top" for only the sectors
-  allocated in the topmost image, or "none" to only replicate new I/O
-  (MirrorSyncMode).
-- "on-source-error": the action to take on an error on the source
-  (BlockdevOnError, default 'report')
-- "on-target-error": the action to take on an error on the target
-  (BlockdevOnError, default 'report')
-
-The default value of the granularity is the image cluster size clamped
-between 4096 and 65536, if the image format defines one.  If the format
-does not define a cluster size, the default value of the granularity
-is 65536.
-
-Example:
-
--> { "execute": "blockdev-mirror", "arguments": { "device": "ide-hd0",
-                                                  "target": "target0",
-                                                  "sync": "full" } }
-<- { "return": {} }
-
-change-backing-file
--------------------
-Since: 2.1
-
-Change the backing file in the image file metadata.  This does not cause
-QEMU to reopen the image file to reparse the backing filename (it may,
-however, perform a reopen to change permissions from r/o -> r/w -> r/o,
-if needed). The new backing file string is written into the image file
-metadata, and the QEMU internal strings are updated.
-
-Arguments:
-
-- "image-node-name":    The name of the block driver state node of the
-                        image to modify.  The "device" is argument is used to
-                        verify "image-node-name" is in the chain described by
-                        "device".
-                        (json-string, optional)
-
-- "device":             The device name or node-name of the root node that owns
-                        image-node-name.
-                        (json-string)
-
-- "backing-file":       The string to write as the backing file.  This string is
-                        not validated, so care should be taken when specifying
-                        the string or the image chain may not be able to be
-                        reopened again.
-                        (json-string)
-
-Returns: Nothing on success
-         If "device" does not exist or cannot be determined, DeviceNotFound
-
-balloon
--------
-
-Request VM to change its memory allocation (in bytes).
-
-Arguments:
-
-- "value": New memory allocation (json-int)
-
-Example:
-
--> { "execute": "balloon", "arguments": { "value": 536870912 } }
-<- { "return": {} }
-
-set_link
---------
-
-Change the link status of a network adapter.
-
-Arguments:
-
-- "name": network device name (json-string)
-- "up": status is up (json-bool)
-
-Example:
-
--> { "execute": "set_link", "arguments": { "name": "e1000.0", "up": false } }
-<- { "return": {} }
-
-getfd
------
-
-Receive a file descriptor via SCM rights and assign it a name.
-
-Arguments:
-
-- "fdname": file descriptor name (json-string)
-
-Example:
-
--> { "execute": "getfd", "arguments": { "fdname": "fd1" } }
-<- { "return": {} }
-
-Notes:
-
-(1) If the name specified by the "fdname" argument already exists,
-    the file descriptor assigned to it will be closed and replaced
-    by the received file descriptor.
-(2) The 'closefd' command can be used to explicitly close the file
-    descriptor when it is no longer needed.
-
-closefd
--------
-
-Close a file descriptor previously passed via SCM rights.
-
-Arguments:
-
-- "fdname": file descriptor name (json-string)
-
-Example:
-
--> { "execute": "closefd", "arguments": { "fdname": "fd1" } }
-<- { "return": {} }
-
-add-fd
--------
-
-Add a file descriptor, that was passed via SCM rights, to an fd set.
-
-Arguments:
-
-- "fdset-id": The ID of the fd set to add the file descriptor to.
-              (json-int, optional)
-- "opaque": A free-form string that can be used to describe the fd.
-            (json-string, optional)
-
-Return a json-object with the following information:
-
-- "fdset-id": The ID of the fd set that the fd was added to. (json-int)
-- "fd": The file descriptor that was received via SCM rights and added to the
-        fd set. (json-int)
-
-Example:
-
--> { "execute": "add-fd", "arguments": { "fdset-id": 1 } }
-<- { "return": { "fdset-id": 1, "fd": 3 } }
-
-Notes:
-
-(1) The list of fd sets is shared by all monitor connections.
-(2) If "fdset-id" is not specified, a new fd set will be created.
-
-remove-fd
----------
-
-Remove a file descriptor from an fd set.
-
-Arguments:
-
-- "fdset-id": The ID of the fd set that the file descriptor belongs to.
-              (json-int)
-- "fd": The file descriptor that is to be removed. (json-int, optional)
-
-Example:
-
--> { "execute": "remove-fd", "arguments": { "fdset-id": 1, "fd": 3 } }
-<- { "return": {} }
-
-Notes:
-
-(1) The list of fd sets is shared by all monitor connections.
-(2) If "fd" is not specified, all file descriptors in "fdset-id" will be
-    removed.
-
-query-fdsets
--------------
-
-Return information describing all fd sets.
-
-Arguments: None
-
-Example:
-
--> { "execute": "query-fdsets" }
-<- { "return": [
-       {
-         "fds": [
-           {
-             "fd": 30,
-             "opaque": "rdonly:/path/to/file"
-           },
-           {
-             "fd": 24,
-             "opaque": "rdwr:/path/to/file"
-           }
-         ],
-         "fdset-id": 1
-       },
-       {
-         "fds": [
-           {
-             "fd": 28
-           },
-           {
-             "fd": 29
-           }
-         ],
-         "fdset-id": 0
-       }
-     ]
-   }
-
-Note: The list of fd sets is shared by all monitor connections.
-
-block_passwd
-------------
-
-Set the password of encrypted block devices.
-
-Arguments:
-
-- "device": device name (json-string)
-- "node-name": name in the block driver state graph (json-string)
-- "password": password (json-string)
-
-Example:
-
--> { "execute": "block_passwd", "arguments": { "device": "ide0-hd0",
-                                               "password": "12345" } }
-<- { "return": {} }
-
-block_set_io_throttle
-------------
-
-Change I/O throttle limits for a block drive.
-
-Arguments:
-
-- "device": block device name (deprecated, use @id instead)
-            (json-string, optional)
-- "id": the name or QOM path of the guest device (json-string, optional)
-- "bps": total throughput limit in bytes per second (json-int)
-- "bps_rd": read throughput limit in bytes per second (json-int)
-- "bps_wr": write throughput limit in bytes per second (json-int)
-- "iops": total I/O operations per second (json-int)
-- "iops_rd": read I/O operations per second (json-int)
-- "iops_wr": write I/O operations per second (json-int)
-- "bps_max": total throughput limit during bursts, in bytes (json-int, optional)
-- "bps_rd_max": read throughput limit during bursts, in bytes (json-int, optional)
-- "bps_wr_max": write throughput limit during bursts, in bytes (json-int, optional)
-- "iops_max": total I/O operations per second during bursts (json-int, optional)
-- "iops_rd_max": read I/O operations per second during bursts (json-int, optional)
-- "iops_wr_max": write I/O operations per second during bursts (json-int, optional)
-- "bps_max_length": maximum length of the @bps_max burst period, in seconds (json-int, optional)
-- "bps_rd_max_length": maximum length of the @bps_rd_max burst period, in seconds (json-int, optional)
-- "bps_wr_max_length": maximum length of the @bps_wr_max burst period, in seconds (json-int, optional)
-- "iops_max_length": maximum length of the @iops_max burst period, in seconds (json-int, optional)
-- "iops_rd_max_length": maximum length of the @iops_rd_max burst period, in seconds (json-int, optional)
-- "iops_wr_max_length": maximum length of the @iops_wr_max burst period, in seconds (json-int, optional)
-- "iops_size":  I/O size in bytes when limiting (json-int, optional)
-- "group": throttle group name (json-string, optional)
-
-Example:
-
--> { "execute": "block_set_io_throttle", "arguments": { "id": "ide0-1-0",
-                                               "bps": 1000000,
-                                               "bps_rd": 0,
-                                               "bps_wr": 0,
-                                               "iops": 0,
-                                               "iops_rd": 0,
-                                               "iops_wr": 0,
-                                               "bps_max": 8000000,
-                                               "bps_rd_max": 0,
-                                               "bps_wr_max": 0,
-                                               "iops_max": 0,
-                                               "iops_rd_max": 0,
-                                               "iops_wr_max": 0,
-                                               "bps_max_length": 60,
-                                               "iops_size": 0 } }
-<- { "return": {} }
-
-set_password
-------------
-
-Set the password for vnc/spice protocols.
-
-Arguments:
-
-- "protocol": protocol name (json-string)
-- "password": password (json-string)
-- "connected": [ keep | disconnect | fail ] (json-string, optional)
-
-Example:
-
--> { "execute": "set_password", "arguments": { "protocol": "vnc",
-                                               "password": "secret" } }
-<- { "return": {} }
-
-expire_password
----------------
-
-Set the password expire time for vnc/spice protocols.
-
-Arguments:
-
-- "protocol": protocol name (json-string)
-- "time": [ now | never | +secs | secs ] (json-string)
-
-Example:
-
--> { "execute": "expire_password", "arguments": { "protocol": "vnc",
-                                                  "time": "+60" } }
-<- { "return": {} }
-
-add_client
-----------
-
-Add a graphics client
-
-Arguments:
-
-- "protocol": protocol name (json-string)
-- "fdname": file descriptor name (json-string)
-- "skipauth": whether to skip authentication (json-bool, optional)
-- "tls": whether to perform TLS (json-bool, optional)
-
-Example:
-
--> { "execute": "add_client", "arguments": { "protocol": "vnc",
-                                             "fdname": "myclient" } }
-<- { "return": {} }
-
-qmp_capabilities
-----------------
-
-Enable QMP capabilities.
-
-Arguments: None.
-
-Example:
-
--> { "execute": "qmp_capabilities" }
-<- { "return": {} }
-
-Note: This command must be issued before issuing any other command.
-
-human-monitor-command
----------------------
-
-Execute a Human Monitor command.
-
-Arguments:
-
-- command-line: the command name and its arguments, just like the
-                Human Monitor's shell (json-string)
-- cpu-index: select the CPU number to be used by commands which access CPU
-             data, like 'info registers'. The Monitor selects CPU 0 if this
-             argument is not provided (json-int, optional)
-
-Example:
-
--> { "execute": "human-monitor-command", "arguments": { "command-line": "info kvm" } }
-<- { "return": "kvm support: enabled\r\n" }
-
-Notes:
-
-(1) The Human Monitor is NOT an stable interface, this means that command
-    names, arguments and responses can change or be removed at ANY time.
-    Applications that rely on long term stability guarantees should NOT
-    use this command
-
-(2) Limitations:
-
-    o This command is stateless, this means that commands that depend
-      on state information (such as getfd) might not work
-
-    o Commands that prompt the user for data (eg. 'cont' when the block
-      device is encrypted) don't currently work
-
-3. Query Commands
-=================
-
-
-query-version
--------------
-
-Show QEMU version.
-
-Return a json-object with the following information:
-
-- "qemu": A json-object containing three integer values:
-    - "major": QEMU's major version (json-int)
-    - "minor": QEMU's minor version (json-int)
-    - "micro": QEMU's micro version (json-int)
-- "package": package's version (json-string)
-
-Example:
-
--> { "execute": "query-version" }
-<- {
-      "return":{
-         "qemu":{
-            "major":0,
-            "minor":11,
-            "micro":5
-         },
-         "package":""
-      }
-   }
-
-query-commands
---------------
-
-List QMP available commands.
-
-Each command is represented by a json-object, the returned value is a json-array
-of all commands.
-
-Each json-object contain:
-
-- "name": command's name (json-string)
-
-Example:
-
--> { "execute": "query-commands" }
-<- {
-      "return":[
-         {
-            "name":"query-balloon"
-         },
-         {
-            "name":"system_powerdown"
-         }
-      ]
-   }
-
-Note: This example has been shortened as the real response is too long.
-
-query-events
---------------
-
-List QMP available events.
-
-Each event is represented by a json-object, the returned value is a json-array
-of all events.
-
-Each json-object contains:
-
-- "name": event's name (json-string)
-
-Example:
-
--> { "execute": "query-events" }
-<- {
-      "return":[
-         {
-            "name":"SHUTDOWN"
-         },
-         {
-            "name":"RESET"
-         }
-      ]
-   }
-
-Note: This example has been shortened as the real response is too long.
-
-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.
-
-query-chardev
--------------
-
-Each device is represented by a json-object. The returned value is a json-array
-of all devices.
-
-Each json-object contain the following:
-
-- "label": device's label (json-string)
-- "filename": device's file (json-string)
-- "frontend-open": open/closed state of the frontend device attached to this
-                   backend (json-bool)
-
-Example:
-
--> { "execute": "query-chardev" }
-<- {
-      "return": [
-         {
-            "label": "charchannel0",
-            "filename": "unix:/var/lib/libvirt/qemu/seabios.rhel6.agent,server",
-            "frontend-open": false
-         },
-         {
-            "label": "charmonitor",
-            "filename": "unix:/var/lib/libvirt/qemu/seabios.rhel6.monitor,server",
-            "frontend-open": true
-         },
-         {
-            "label": "charserial0",
-            "filename": "pty:/dev/pts/2",
-            "frontend-open": true
-         }
-      ]
-   }
-
-query-chardev-backends
--------------
-
-List available character device backends.
-
-Each backend is represented by a json-object, the returned value is a json-array
-of all backends.
-
-Each json-object contains:
-
-- "name": backend name (json-string)
-
-Example:
-
--> { "execute": "query-chardev-backends" }
-<- {
-      "return":[
-         {
-            "name":"udp"
-         },
-         {
-            "name":"tcp"
-         },
-         {
-            "name":"unix"
-         },
-         {
-            "name":"spiceport"
-         }
-      ]
-   }
-
-query-block
------------
-
-Show the block devices.
-
-Each block device information is stored in a json-object and the returned value
-is a json-array of all devices.
-
-Each json-object contain the following:
-
-- "device": device name (json-string)
-- "type": device type (json-string)
-         - deprecated, retained for backward compatibility
-         - Possible values: "unknown"
-- "removable": true if the device is removable, false otherwise (json-bool)
-- "locked": true if the device is locked, false otherwise (json-bool)
-- "tray_open": only present if removable, true if the device has a tray,
-               and it is open (json-bool)
-- "inserted": only present if the device is inserted, it is a json-object
-   containing the following:
-         - "file": device file name (json-string)
-         - "ro": true if read-only, false otherwise (json-bool)
-         - "drv": driver format name (json-string)
-             - Possible values: "blkdebug", "bochs", "cloop", "dmg",
-                                "file", "file", "ftp", "ftps", "host_cdrom",
-                                "host_device", "http", "https",
-                                "nbd", "parallels", "qcow", "qcow2", "raw",
-                                "tftp", "vdi", "vmdk", "vpc", "vvfat"
-         - "backing_file": backing file name (json-string, optional)
-         - "backing_file_depth": number of files in the backing file chain (json-int)
-         - "encrypted": true if encrypted, false otherwise (json-bool)
-         - "bps": limit total bytes per second (json-int)
-         - "bps_rd": limit read bytes per second (json-int)
-         - "bps_wr": limit write bytes per second (json-int)
-         - "iops": limit total I/O operations per second (json-int)
-         - "iops_rd": limit read operations per second (json-int)
-         - "iops_wr": limit write operations per second (json-int)
-         - "bps_max":  total max in bytes (json-int)
-         - "bps_rd_max":  read max in bytes (json-int)
-         - "bps_wr_max":  write max in bytes (json-int)
-         - "iops_max":  total I/O operations max (json-int)
-         - "iops_rd_max":  read I/O operations max (json-int)
-         - "iops_wr_max":  write I/O operations max (json-int)
-         - "iops_size": I/O size when limiting by iops (json-int)
-         - "detect_zeroes": detect and optimize zero writing (json-string)
-             - Possible values: "off", "on", "unmap"
-         - "write_threshold": write offset threshold in bytes, a event will be
-                              emitted if crossed. Zero if disabled (json-int)
-         - "image": the detail of the image, it is a json-object containing
-            the following:
-             - "filename": image file name (json-string)
-             - "format": image format (json-string)
-             - "virtual-size": image capacity in bytes (json-int)
-             - "dirty-flag": true if image is not cleanly closed, not present
-                             means clean (json-bool, optional)
-             - "actual-size": actual size on disk in bytes of the image, not
-                              present when image does not support thin
-                              provision (json-int, optional)
-             - "cluster-size": size of a cluster in bytes, not present if image
-                               format does not support it (json-int, optional)
-             - "encrypted": true if the image is encrypted, not present means
-                            false or the image format does not support
-                            encryption (json-bool, optional)
-             - "backing_file": backing file name, not present means no backing
-                               file is used or the image format does not
-                               support backing file chain
-                               (json-string, optional)
-             - "full-backing-filename": full path of the backing file, not
-                                        present if it equals backing_file or no
-                                        backing file is used
-                                        (json-string, optional)
-             - "backing-filename-format": the format of the backing file, not
-                                          present means unknown or no backing
-                                          file (json-string, optional)
-             - "snapshots": the internal snapshot info, it is an optional list
-                of json-object containing the following:
-                 - "id": unique snapshot id (json-string)
-                 - "name": snapshot name (json-string)
-                 - "vm-state-size": size of the VM state in bytes (json-int)
-                 - "date-sec": UTC date of the snapshot in seconds (json-int)
-                 - "date-nsec": fractional part in nanoseconds to be used with
-                                date-sec (json-int)
-                 - "vm-clock-sec": VM clock relative to boot in seconds
-                                   (json-int)
-                 - "vm-clock-nsec": fractional part in nanoseconds to be used
-                                    with vm-clock-sec (json-int)
-             - "backing-image": the detail of the backing image, it is an
-                                optional json-object only present when a
-                                backing image present for this image
-
-- "io-status": I/O operation status, only present if the device supports it
-               and the VM is configured to stop on errors. It's always reset
-               to "ok" when the "cont" command is issued (json_string, optional)
-             - Possible values: "ok", "failed", "nospace"
-
-Example:
-
--> { "execute": "query-block" }
-<- {
-      "return":[
-         {
-            "io-status": "ok",
-            "device":"ide0-hd0",
-            "locked":false,
-            "removable":false,
-            "inserted":{
-               "ro":false,
-               "drv":"qcow2",
-               "encrypted":false,
-               "file":"disks/test.qcow2",
-               "backing_file_depth":1,
-               "bps":1000000,
-               "bps_rd":0,
-               "bps_wr":0,
-               "iops":1000000,
-               "iops_rd":0,
-               "iops_wr":0,
-               "bps_max": 8000000,
-               "bps_rd_max": 0,
-               "bps_wr_max": 0,
-               "iops_max": 0,
-               "iops_rd_max": 0,
-               "iops_wr_max": 0,
-               "iops_size": 0,
-               "detect_zeroes": "on",
-               "write_threshold": 0,
-               "image":{
-                  "filename":"disks/test.qcow2",
-                  "format":"qcow2",
-                  "virtual-size":2048000,
-                  "backing_file":"base.qcow2",
-                  "full-backing-filename":"disks/base.qcow2",
-                  "backing-filename-format":"qcow2",
-                  "snapshots":[
-                     {
-                        "id": "1",
-                        "name": "snapshot1",
-                        "vm-state-size": 0,
-                        "date-sec": 10000200,
-                        "date-nsec": 12,
-                        "vm-clock-sec": 206,
-                        "vm-clock-nsec": 30
-                     }
-                  ],
-                  "backing-image":{
-                      "filename":"disks/base.qcow2",
-                      "format":"qcow2",
-                      "virtual-size":2048000
-                  }
-               }
-            },
-            "type":"unknown"
-         },
-         {
-            "io-status": "ok",
-            "device":"ide1-cd0",
-            "locked":false,
-            "removable":true,
-            "type":"unknown"
-         },
-         {
-            "device":"floppy0",
-            "locked":false,
-            "removable":true,
-            "type":"unknown"
-         },
-         {
-            "device":"sd0",
-            "locked":false,
-            "removable":true,
-            "type":"unknown"
-         }
-      ]
-   }
-
-query-blockstats
-----------------
-
-Show block device statistics.
-
-Each device statistic information is stored in a json-object and the returned
-value is a json-array of all devices.
-
-Each json-object contain the following:
-
-- "device": device name (json-string)
-- "stats": A json-object with the statistics information, it contains:
-    - "rd_bytes": bytes read (json-int)
-    - "wr_bytes": bytes written (json-int)
-    - "rd_operations": read operations (json-int)
-    - "wr_operations": write operations (json-int)
-    - "flush_operations": cache flush operations (json-int)
-    - "wr_total_time_ns": total time spend on writes in nano-seconds (json-int)
-    - "rd_total_time_ns": total time spend on reads in nano-seconds (json-int)
-    - "flush_total_time_ns": total time spend on cache flushes in nano-seconds (json-int)
-    - "wr_highest_offset": The offset after the greatest byte written to the
-                           BlockDriverState since it has been opened (json-int)
-    - "rd_merged": number of read requests that have been merged into
-                   another request (json-int)
-    - "wr_merged": number of write requests that have been merged into
-                   another request (json-int)
-    - "idle_time_ns": time since the last I/O operation, in
-                      nanoseconds. If the field is absent it means
-                      that there haven't been any operations yet
-                      (json-int, optional)
-    - "failed_rd_operations": number of failed read operations
-                              (json-int)
-    - "failed_wr_operations": number of failed write operations
-                              (json-int)
-    - "failed_flush_operations": number of failed flush operations
-                               (json-int)
-    - "invalid_rd_operations": number of invalid read operations
-                               (json-int)
-    - "invalid_wr_operations": number of invalid write operations
-                               (json-int)
-    - "invalid_flush_operations": number of invalid flush operations
-                                  (json-int)
-    - "account_invalid": whether invalid operations are included in
-                         the last access statistics (json-bool)
-    - "account_failed": whether failed operations are included in the
-                         latency and last access statistics
-                         (json-bool)
-    - "timed_stats": A json-array containing statistics collected in
-                     specific intervals, with the following members:
-        - "interval_length": interval used for calculating the
-                             statistics, in seconds (json-int)
-        - "min_rd_latency_ns": minimum latency of read operations in
-                               the defined interval, in nanoseconds
-                               (json-int)
-        - "min_wr_latency_ns": minimum latency of write operations in
-                               the defined interval, in nanoseconds
-                               (json-int)
-        - "min_flush_latency_ns": minimum latency of flush operations
-                                  in the defined interval, in
-                                  nanoseconds (json-int)
-        - "max_rd_latency_ns": maximum latency of read operations in
-                               the defined interval, in nanoseconds
-                               (json-int)
-        - "max_wr_latency_ns": maximum latency of write operations in
-                               the defined interval, in nanoseconds
-                               (json-int)
-        - "max_flush_latency_ns": maximum latency of flush operations
-                                  in the defined interval, in
-                                  nanoseconds (json-int)
-        - "avg_rd_latency_ns": average latency of read operations in
-                               the defined interval, in nanoseconds
-                               (json-int)
-        - "avg_wr_latency_ns": average latency of write operations in
-                               the defined interval, in nanoseconds
-                               (json-int)
-        - "avg_flush_latency_ns": average latency of flush operations
-                                  in the defined interval, in
-                                  nanoseconds (json-int)
-        - "avg_rd_queue_depth": average number of pending read
-                                operations in the defined interval
-                                (json-number)
-        - "avg_wr_queue_depth": average number of pending write
-                                operations in the defined interval
-                                (json-number).
-- "parent": Contains recursively the statistics of the underlying
-            protocol (e.g. the host file for a qcow2 image). If there is
-            no underlying protocol, this field is omitted
-            (json-object, optional)
-
-Example:
-
--> { "execute": "query-blockstats" }
-<- {
-      "return":[
-         {
-            "device":"ide0-hd0",
-            "parent":{
-               "stats":{
-                  "wr_highest_offset":3686448128,
-                  "wr_bytes":9786368,
-                  "wr_operations":751,
-                  "rd_bytes":122567168,
-                  "rd_operations":36772
-                  "wr_total_times_ns":313253456
-                  "rd_total_times_ns":3465673657
-                  "flush_total_times_ns":49653
-                  "flush_operations":61,
-                  "rd_merged":0,
-                  "wr_merged":0,
-                  "idle_time_ns":2953431879,
-                  "account_invalid":true,
-                  "account_failed":false
-               }
-            },
-            "stats":{
-               "wr_highest_offset":2821110784,
-               "wr_bytes":9786368,
-               "wr_operations":692,
-               "rd_bytes":122739200,
-               "rd_operations":36604
-               "flush_operations":51,
-               "wr_total_times_ns":313253456
-               "rd_total_times_ns":3465673657
-               "flush_total_times_ns":49653,
-               "rd_merged":0,
-               "wr_merged":0,
-               "idle_time_ns":2953431879,
-               "account_invalid":true,
-               "account_failed":false
-            }
-         },
-         {
-            "device":"ide1-cd0",
-            "stats":{
-               "wr_highest_offset":0,
-               "wr_bytes":0,
-               "wr_operations":0,
-               "rd_bytes":0,
-               "rd_operations":0
-               "flush_operations":0,
-               "wr_total_times_ns":0
-               "rd_total_times_ns":0
-               "flush_total_times_ns":0,
-               "rd_merged":0,
-               "wr_merged":0,
-               "account_invalid":false,
-               "account_failed":false
-            }
-         },
-         {
-            "device":"floppy0",
-            "stats":{
-               "wr_highest_offset":0,
-               "wr_bytes":0,
-               "wr_operations":0,
-               "rd_bytes":0,
-               "rd_operations":0
-               "flush_operations":0,
-               "wr_total_times_ns":0
-               "rd_total_times_ns":0
-               "flush_total_times_ns":0,
-               "rd_merged":0,
-               "wr_merged":0,
-               "account_invalid":false,
-               "account_failed":false
-            }
-         },
-         {
-            "device":"sd0",
-            "stats":{
-               "wr_highest_offset":0,
-               "wr_bytes":0,
-               "wr_operations":0,
-               "rd_bytes":0,
-               "rd_operations":0
-               "flush_operations":0,
-               "wr_total_times_ns":0
-               "rd_total_times_ns":0
-               "flush_total_times_ns":0,
-               "rd_merged":0,
-               "wr_merged":0,
-               "account_invalid":false,
-               "account_failed":false
-            }
-         }
-      ]
-   }
-
-query-cpus
-----------
-
-Show CPU information.
-
-Return a json-array. Each CPU is represented by a json-object, which contains:
-
-- "CPU": CPU index (json-int)
-- "current": true if this is the current CPU, false otherwise (json-bool)
-- "halted": true if the cpu is halted, false otherwise (json-bool)
-- "qom_path": path to the CPU object in the QOM tree (json-str)
-- "arch": architecture of the cpu, which determines what additional
-          keys will be present (json-str)
-- Current program counter. The key's name depends on the architecture:
-     "pc": i386/x86_64 (json-int)
-     "nip": PPC (json-int)
-     "pc" and "npc": sparc (json-int)
-     "PC": mips (json-int)
-- "thread_id": ID of the underlying host thread (json-int)
-
-Example:
-
--> { "execute": "query-cpus" }
-<- {
-      "return":[
-         {
-            "CPU":0,
-            "current":true,
-            "halted":false,
-            "qom_path":"/machine/unattached/device[0]",
-            "arch":"x86",
-            "pc":3227107138,
-            "thread_id":3134
-         },
-         {
-            "CPU":1,
-            "current":false,
-            "halted":true,
-            "qom_path":"/machine/unattached/device[2]",
-            "arch":"x86",
-            "pc":7108165,
-            "thread_id":3135
-         }
-      ]
-   }
-
-query-iothreads
----------------
-
-Returns a list of information about each iothread.
-
-Note this list excludes the QEMU main loop thread, which is not declared
-using the -object iothread command-line option.  It is always the main thread
-of the process.
-
-Return a json-array. Each iothread is represented by a json-object, which contains:
-
-- "id": name of iothread (json-str)
-- "thread-id": ID of the underlying host thread (json-int)
-
-Example:
-
--> { "execute": "query-iothreads" }
-<- {
-      "return":[
-         {
-            "id":"iothread0",
-            "thread-id":3134
-         },
-         {
-            "id":"iothread1",
-            "thread-id":3135
-         }
-      ]
-   }
-
-query-pci
----------
-
-PCI buses and devices information.
-
-The returned value is a json-array of all buses. Each bus is represented by
-a json-object, which has a key with a json-array of all PCI devices attached
-to it. Each device is represented by a json-object.
-
-The bus json-object contains the following:
-
-- "bus": bus number (json-int)
-- "devices": a json-array of json-objects, each json-object represents a
-             PCI device
-
-The PCI device json-object contains the following:
-
-- "bus": identical to the parent's bus number (json-int)
-- "slot": slot number (json-int)
-- "function": function number (json-int)
-- "class_info": a json-object containing:
-     - "desc": device class description (json-string, optional)
-     - "class": device class number (json-int)
-- "id": a json-object containing:
-     - "device": device ID (json-int)
-     - "vendor": vendor ID (json-int)
-- "irq": device's IRQ if assigned (json-int, optional)
-- "qdev_id": qdev id string (json-string)
-- "pci_bridge": It's a json-object, only present if this device is a
-                PCI bridge, contains:
-     - "bus": bus number (json-int)
-     - "secondary": secondary bus number (json-int)
-     - "subordinate": subordinate bus number (json-int)
-     - "io_range": I/O memory range information, a json-object with the
-                   following members:
-                 - "base": base address, in bytes (json-int)
-                 - "limit": limit address, in bytes (json-int)
-     - "memory_range": memory range information, a json-object with the
-                       following members:
-                 - "base": base address, in bytes (json-int)
-                 - "limit": limit address, in bytes (json-int)
-     - "prefetchable_range": Prefetchable memory range information, a
-                             json-object with the following members:
-                 - "base": base address, in bytes (json-int)
-                 - "limit": limit address, in bytes (json-int)
-     - "devices": a json-array of PCI devices if there's any attached, each
-                  each element is represented by a json-object, which contains
-                  the same members of the 'PCI device json-object' described
-                  above (optional)
-- "regions": a json-array of json-objects, each json-object represents a
-             memory region of this device
-
-The memory range json-object contains the following:
-
-- "base": base memory address (json-int)
-- "limit": limit value (json-int)
-
-The region json-object can be an I/O region or a memory region, an I/O region
-json-object contains the following:
-
-- "type": "io" (json-string, fixed)
-- "bar": BAR number (json-int)
-- "address": memory address (json-int)
-- "size": memory size (json-int)
-
-A memory region json-object contains the following:
-
-- "type": "memory" (json-string, fixed)
-- "bar": BAR number (json-int)
-- "address": memory address (json-int)
-- "size": memory size (json-int)
-- "mem_type_64": true or false (json-bool)
-- "prefetch": true or false (json-bool)
-
-Example:
-
--> { "execute": "query-pci" }
-<- {
-      "return":[
-         {
-            "bus":0,
-            "devices":[
-               {
-                  "bus":0,
-                  "qdev_id":"",
-                  "slot":0,
-                  "class_info":{
-                     "class":1536,
-                     "desc":"Host bridge"
-                  },
-                  "id":{
-                     "device":32902,
-                     "vendor":4663
-                  },
-                  "function":0,
-                  "regions":[
-
-                  ]
-               },
-               {
-                  "bus":0,
-                  "qdev_id":"",
-                  "slot":1,
-                  "class_info":{
-                     "class":1537,
-                     "desc":"ISA bridge"
-                  },
-                  "id":{
-                     "device":32902,
-                     "vendor":28672
-                  },
-                  "function":0,
-                  "regions":[
-
-                  ]
-               },
-               {
-                  "bus":0,
-                  "qdev_id":"",
-                  "slot":1,
-                  "class_info":{
-                     "class":257,
-                     "desc":"IDE controller"
-                  },
-                  "id":{
-                     "device":32902,
-                     "vendor":28688
-                  },
-                  "function":1,
-                  "regions":[
-                     {
-                        "bar":4,
-                        "size":16,
-                        "address":49152,
-                        "type":"io"
-                     }
-                  ]
-               },
-               {
-                  "bus":0,
-                  "qdev_id":"",
-                  "slot":2,
-                  "class_info":{
-                     "class":768,
-                     "desc":"VGA controller"
-                  },
-                  "id":{
-                     "device":4115,
-                     "vendor":184
-                  },
-                  "function":0,
-                  "regions":[
-                     {
-                        "prefetch":true,
-                        "mem_type_64":false,
-                        "bar":0,
-                        "size":33554432,
-                        "address":4026531840,
-                        "type":"memory"
-                     },
-                     {
-                        "prefetch":false,
-                        "mem_type_64":false,
-                        "bar":1,
-                        "size":4096,
-                        "address":4060086272,
-                        "type":"memory"
-                     },
-                     {
-                        "prefetch":false,
-                        "mem_type_64":false,
-                        "bar":6,
-                        "size":65536,
-                        "address":-1,
-                        "type":"memory"
-                     }
-                  ]
-               },
-               {
-                  "bus":0,
-                  "qdev_id":"",
-                  "irq":11,
-                  "slot":4,
-                  "class_info":{
-                     "class":1280,
-                     "desc":"RAM controller"
-                  },
-                  "id":{
-                     "device":6900,
-                     "vendor":4098
-                  },
-                  "function":0,
-                  "regions":[
-                     {
-                        "bar":0,
-                        "size":32,
-                        "address":49280,
-                        "type":"io"
-                     }
-                  ]
-               }
-            ]
-         }
-      ]
-   }
-
-Note: This example has been shortened as the real response is too long.
-
-query-kvm
----------
-
-Show KVM information.
-
-Return a json-object with the following information:
-
-- "enabled": true if KVM support is enabled, false otherwise (json-bool)
-- "present": true if QEMU has KVM support, false otherwise (json-bool)
-
-Example:
-
--> { "execute": "query-kvm" }
-<- { "return": { "enabled": true, "present": true } }
-
-query-status
-------------
-
-Return a json-object with the following information:
-
-- "running": true if the VM is running, or false if it is paused (json-bool)
-- "singlestep": true if the VM is in single step mode,
-                false otherwise (json-bool)
-- "status": one of the following values (json-string)
-    "debug" - QEMU is running on a debugger
-    "inmigrate" - guest is paused waiting for an incoming migration
-    "internal-error" - An internal error that prevents further guest
-    execution has occurred
-    "io-error" - the last IOP has failed and the device is configured
-    to pause on I/O errors
-    "paused" - guest has been paused via the 'stop' command
-    "postmigrate" - guest is paused following a successful 'migrate'
-    "prelaunch" - QEMU was started with -S and guest has not started
-    "finish-migrate" - guest is paused to finish the migration process
-    "restore-vm" - guest is paused to restore VM state
-    "running" - guest is actively running
-    "save-vm" - guest is paused to save the VM state
-    "shutdown" - guest is shut down (and -no-shutdown is in use)
-    "watchdog" - the watchdog action is configured to pause and
-     has been triggered
-
-Example:
-
--> { "execute": "query-status" }
-<- { "return": { "running": true, "singlestep": false, "status": "running" } }
-
-query-mice
-----------
-
-Show VM mice information.
-
-Each mouse is represented by a json-object, the returned value is a json-array
-of all mice.
-
-The mouse json-object contains the following:
-
-- "name": mouse's name (json-string)
-- "index": mouse's index (json-int)
-- "current": true if this mouse is receiving events, false otherwise (json-bool)
-- "absolute": true if the mouse generates absolute input events (json-bool)
-
-Example:
-
--> { "execute": "query-mice" }
-<- {
-      "return":[
-         {
-            "name":"QEMU Microsoft Mouse",
-            "index":0,
-            "current":false,
-            "absolute":false
-         },
-         {
-            "name":"QEMU PS/2 Mouse",
-            "index":1,
-            "current":true,
-            "absolute":true
-         }
-      ]
-   }
-
-query-vnc
----------
-
-Show VNC server information.
-
-Return a json-object with server information. Connected clients are returned
-as a json-array of json-objects.
-
-The main json-object contains the following:
-
-- "enabled": true or false (json-bool)
-- "host": server's IP address (json-string)
-- "family": address family (json-string)
-         - Possible values: "ipv4", "ipv6", "unix", "unknown"
-- "service": server's port number (json-string)
-- "auth": authentication method (json-string)
-         - Possible values: "invalid", "none", "ra2", "ra2ne", "sasl", "tight",
-                            "tls", "ultra", "unknown", "vencrypt", "vencrypt",
-                            "vencrypt+plain", "vencrypt+tls+none",
-                            "vencrypt+tls+plain", "vencrypt+tls+sasl",
-                            "vencrypt+tls+vnc", "vencrypt+x509+none",
-                            "vencrypt+x509+plain", "vencrypt+x509+sasl",
-                            "vencrypt+x509+vnc", "vnc"
-- "clients": a json-array of all connected clients
-
-Clients are described by a json-object, each one contain the following:
-
-- "host": client's IP address (json-string)
-- "family": address family (json-string)
-         - Possible values: "ipv4", "ipv6", "unix", "unknown"
-- "service": client's port number (json-string)
-- "x509_dname": TLS dname (json-string, optional)
-- "sasl_username": SASL username (json-string, optional)
-
-Example:
-
--> { "execute": "query-vnc" }
-<- {
-      "return":{
-         "enabled":true,
-         "host":"0.0.0.0",
-         "service":"50402",
-         "auth":"vnc",
-         "family":"ipv4",
-         "clients":[
-            {
-               "host":"127.0.0.1",
-               "service":"50401",
-               "family":"ipv4"
-            }
-         ]
-      }
-   }
-
-query-spice
------------
-
-Show SPICE server information.
-
-Return a json-object with server information. Connected clients are returned
-as a json-array of json-objects.
-
-The main json-object contains the following:
-
-- "enabled": true or false (json-bool)
-- "host": server's IP address (json-string)
-- "port": server's port number (json-int, optional)
-- "tls-port": server's port number (json-int, optional)
-- "auth": authentication method (json-string)
-         - Possible values: "none", "spice"
-- "channels": a json-array of all active channels clients
-
-Channels are described by a json-object, each one contain the following:
-
-- "host": client's IP address (json-string)
-- "family": address family (json-string)
-         - Possible values: "ipv4", "ipv6", "unix", "unknown"
-- "port": client's port number (json-string)
-- "connection-id": spice connection id.  All channels with the same id
-                   belong to the same spice session (json-int)
-- "channel-type": channel type.  "1" is the main control channel, filter for
-                  this one if you want track spice sessions only (json-int)
-- "channel-id": channel id.  Usually "0", might be different needed when
-                multiple channels of the same type exist, such as multiple
-                display channels in a multihead setup (json-int)
-- "tls": whether the channel is encrypted (json-bool)
-
-Example:
-
--> { "execute": "query-spice" }
-<- {
-      "return": {
-         "enabled": true,
-         "auth": "spice",
-         "port": 5920,
-         "tls-port": 5921,
-         "host": "0.0.0.0",
-         "channels": [
-            {
-               "port": "54924",
-               "family": "ipv4",
-               "channel-type": 1,
-               "connection-id": 1804289383,
-               "host": "127.0.0.1",
-               "channel-id": 0,
-               "tls": true
-            },
-            {
-               "port": "36710",
-               "family": "ipv4",
-               "channel-type": 4,
-               "connection-id": 1804289383,
-               "host": "127.0.0.1",
-               "channel-id": 0,
-               "tls": false
-            },
-            [ ... more channels follow ... ]
-         ]
-      }
-   }
-
-query-name
-----------
-
-Show VM name.
-
-Return a json-object with the following information:
-
-- "name": VM's name (json-string, optional)
-
-Example:
-
--> { "execute": "query-name" }
-<- { "return": { "name": "qemu-name" } }
-
-query-uuid
-----------
-
-Show VM UUID.
-
-Return a json-object with the following information:
-
-- "UUID": Universally Unique Identifier (json-string)
-
-Example:
-
--> { "execute": "query-uuid" }
-<- { "return": { "UUID": "550e8400-e29b-41d4-a716-446655440000" } }
-
-query-command-line-options
---------------------------
-
-Show command line option schema.
-
-Return a json-array of command line option schema for all options (or for
-the given option), returning an error if the given option doesn't exist.
-
-Each array entry contains the following:
-
-- "option": option name (json-string)
-- "parameters": a json-array describes all parameters of the option:
-    - "name": parameter name (json-string)
-    - "type": parameter type (one of 'string', 'boolean', 'number',
-              or 'size')
-    - "help": human readable description of the parameter
-              (json-string, optional)
-    - "default": default value string for the parameter
-                 (json-string, optional)
-
-Example:
-
--> { "execute": "query-command-line-options", "arguments": { "option": "option-rom" } }
-<- { "return": [
-        {
-            "parameters": [
-                {
-                    "name": "romfile",
-                    "type": "string"
-                },
-                {
-                    "name": "bootindex",
-                    "type": "number"
-                }
-            ],
-            "option": "option-rom"
-        }
-     ]
-   }
-
-query-migrate
--------------
-
-Migration status.
-
-Return a json-object. If migration is active there will be another json-object
-with RAM migration status and if block migration is active another one with
-block migration status.
-
-The main json-object contains the following:
-
-- "status": migration status (json-string)
-     - Possible values: "setup", "active", "completed", "failed", "cancelled"
-- "total-time": total amount of ms since migration started.  If
-                migration has ended, it returns the total migration
-                time (json-int)
-- "setup-time" amount of setup time in milliseconds _before_ the
-               iterations begin but _after_ the QMP command is issued.
-               This is designed to provide an accounting of any activities
-               (such as RDMA pinning) which may be expensive, but do not
-               actually occur during the iterative migration rounds
-               themselves. (json-int)
-- "downtime": only present when migration has finished correctly
-              total amount in ms for downtime that happened (json-int)
-- "expected-downtime": only present while migration is active
-                total amount in ms for downtime that was calculated on
-                the last bitmap round (json-int)
-- "ram": only present if "status" is "active", it is a json-object with the
-  following RAM information:
-         - "transferred": amount transferred in bytes (json-int)
-         - "remaining": amount remaining to transfer in bytes (json-int)
-         - "total": total amount of memory in bytes (json-int)
-         - "duplicate": number of pages filled entirely with the same
-            byte (json-int)
-            These are sent over the wire much more efficiently.
-         - "skipped": number of skipped zero pages (json-int)
-         - "normal" : number of whole pages transferred.  I.e. they
-            were not sent as duplicate or xbzrle pages (json-int)
-         - "normal-bytes" : number of bytes transferred in whole
-            pages. This is just normal pages times size of one page,
-            but this way upper levels don't need to care about page
-            size (json-int)
-         - "dirty-sync-count": times that dirty ram was synchronized (json-int)
-- "disk": only present if "status" is "active" and it is a block migration,
-  it is a json-object with the following disk information:
-         - "transferred": amount transferred in bytes (json-int)
-         - "remaining": amount remaining to transfer in bytes json-int)
-         - "total": total disk size in bytes (json-int)
-- "xbzrle-cache": only present if XBZRLE is active.
-  It is a json-object with the following XBZRLE information:
-         - "cache-size": XBZRLE cache size in bytes
-         - "bytes": number of bytes transferred for XBZRLE compressed pages
-         - "pages": number of XBZRLE compressed pages
-         - "cache-miss": number of XBRZRLE page cache misses
-         - "cache-miss-rate": rate of XBRZRLE page cache misses
-         - "overflow": number of times XBZRLE overflows.  This means
-           that the XBZRLE encoding was bigger than just sent the
-           whole page, and then we sent the whole page instead (as as
-           normal page).
-
-Examples:
-
-1. Before the first migration
-
--> { "execute": "query-migrate" }
-<- { "return": {} }
-
-2. Migration is done and has succeeded
-
--> { "execute": "query-migrate" }
-<- { "return": {
-        "status": "completed",
-        "ram":{
-          "transferred":123,
-          "remaining":123,
-          "total":246,
-          "total-time":12345,
-          "setup-time":12345,
-          "downtime":12345,
-          "duplicate":123,
-          "normal":123,
-          "normal-bytes":123456,
-          "dirty-sync-count":15
-        }
-     }
-   }
-
-3. Migration is done and has failed
-
--> { "execute": "query-migrate" }
-<- { "return": { "status": "failed" } }
-
-4. Migration is being performed and is not a block migration:
-
--> { "execute": "query-migrate" }
-<- {
-      "return":{
-         "status":"active",
-         "ram":{
-            "transferred":123,
-            "remaining":123,
-            "total":246,
-            "total-time":12345,
-            "setup-time":12345,
-            "expected-downtime":12345,
-            "duplicate":123,
-            "normal":123,
-            "normal-bytes":123456,
-            "dirty-sync-count":15
-         }
-      }
-   }
-
-5. Migration is being performed and is a block migration:
-
--> { "execute": "query-migrate" }
-<- {
-      "return":{
-         "status":"active",
-         "ram":{
-            "total":1057024,
-            "remaining":1053304,
-            "transferred":3720,
-            "total-time":12345,
-            "setup-time":12345,
-            "expected-downtime":12345,
-            "duplicate":123,
-            "normal":123,
-            "normal-bytes":123456,
-            "dirty-sync-count":15
-         },
-         "disk":{
-            "total":20971520,
-            "remaining":20880384,
-            "transferred":91136
-         }
-      }
-   }
-
-6. Migration is being performed and XBZRLE is active:
-
--> { "execute": "query-migrate" }
-<- {
-      "return":{
-         "status":"active",
-         "capabilities" : [ { "capability": "xbzrle", "state" : true } ],
-         "ram":{
-            "total":1057024,
-            "remaining":1053304,
-            "transferred":3720,
-            "total-time":12345,
-            "setup-time":12345,
-            "expected-downtime":12345,
-            "duplicate":10,
-            "normal":3333,
-            "normal-bytes":3412992,
-            "dirty-sync-count":15
-         },
-         "xbzrle-cache":{
-            "cache-size":67108864,
-            "bytes":20971520,
-            "pages":2444343,
-            "cache-miss":2244,
-            "cache-miss-rate":0.123,
-            "overflow":34434
-         }
-      }
-   }
-
-migrate-set-capabilities
-------------------------
-
-Enable/Disable migration capabilities
-
-- "xbzrle": XBZRLE support
-- "rdma-pin-all": pin all pages when using RDMA during migration
-- "auto-converge": throttle down guest to help convergence of migration
-- "zero-blocks": compress zero blocks during block migration
-- "compress": use multiple compression threads to accelerate live migration
-- "events": generate events for each migration state change
-- "postcopy-ram": postcopy mode for live migration
-- "x-colo": COarse-Grain LOck Stepping (COLO) for Non-stop Service
-
-Arguments:
-
-Example:
-
--> { "execute": "migrate-set-capabilities" , "arguments":
-     { "capabilities": [ { "capability": "xbzrle", "state": true } ] } }
-
-query-migrate-capabilities
---------------------------
-
-Query current migration capabilities
-
-- "capabilities": migration capabilities state
-         - "xbzrle" : XBZRLE state (json-bool)
-         - "rdma-pin-all" : RDMA Pin Page state (json-bool)
-         - "auto-converge" : Auto Converge state (json-bool)
-         - "zero-blocks" : Zero Blocks state (json-bool)
-         - "compress": Multiple compression threads state (json-bool)
-         - "events": Migration state change event state (json-bool)
-         - "postcopy-ram": postcopy ram state (json-bool)
-         - "x-colo": COarse-Grain LOck Stepping for Non-stop Service (json-bool)
-
-Arguments:
-
-Example:
-
--> { "execute": "query-migrate-capabilities" }
-<- {"return": [
-     {"state": false, "capability": "xbzrle"},
-     {"state": false, "capability": "rdma-pin-all"},
-     {"state": false, "capability": "auto-converge"},
-     {"state": false, "capability": "zero-blocks"},
-     {"state": false, "capability": "compress"},
-     {"state": true, "capability": "events"},
-     {"state": false, "capability": "postcopy-ram"},
-     {"state": false, "capability": "x-colo"}
-   ]}
-
-migrate-set-parameters
-----------------------
-
-Set migration parameters
-
-- "compress-level": set compression level during migration (json-int)
-- "compress-threads": set compression thread count for migration (json-int)
-- "decompress-threads": set decompression thread count for migration (json-int)
-- "cpu-throttle-initial": set initial percentage of time guest cpus are
-                          throttled for auto-converge (json-int)
-- "cpu-throttle-increment": set throttle increasing percentage for
-                            auto-converge (json-int)
-- "max-bandwidth": set maximum speed for migrations (in bytes/sec) (json-int)
-- "downtime-limit": set maximum tolerated downtime (in milliseconds) for
-                    migrations (json-int)
-- "x-checkpoint-delay": set the delay time for periodic checkpoint (json-int)
-
-Arguments:
-
-Example:
-
--> { "execute": "migrate-set-parameters" , "arguments":
-      { "compress-level": 1 } }
-
-query-migrate-parameters
-------------------------
-
-Query current migration parameters
-
-- "parameters": migration parameters value
-         - "compress-level" : compression level value (json-int)
-         - "compress-threads" : compression thread count value (json-int)
-         - "decompress-threads" : decompression thread count value (json-int)
-         - "cpu-throttle-initial" : initial percentage of time guest cpus are
-                                    throttled (json-int)
-         - "cpu-throttle-increment" : throttle increasing percentage for
-                                      auto-converge (json-int)
-         - "max-bandwidth" : maximium migration speed in bytes per second
-                             (json-int)
-         - "downtime-limit" : maximum tolerated downtime of migration in
-                              milliseconds (json-int)
-Arguments:
-
-Example:
-
--> { "execute": "query-migrate-parameters" }
-<- {
-      "return": {
-         "decompress-threads": 2,
-         "cpu-throttle-increment": 10,
-         "compress-threads": 8,
-         "compress-level": 1,
-         "cpu-throttle-initial": 20,
-         "max-bandwidth": 33554432,
-         "downtime-limit": 300
-      }
-   }
-
-query-balloon
--------------
-
-Show balloon information.
-
-Make an asynchronous request for balloon info. When the request completes a
-json-object will be returned containing the following data:
-
-- "actual": current balloon value in bytes (json-int)
-
-Example:
-
--> { "execute": "query-balloon" }
-<- {
-      "return":{
-         "actual":1073741824,
-      }
-   }
-
-query-tpm
----------
-
-Return information about the TPM device.
-
-Arguments: None
-
-Example:
-
--> { "execute": "query-tpm" }
-<- { "return":
-     [
-       { "model": "tpm-tis",
-         "options":
-           { "type": "passthrough",
-             "data":
-               { "cancel-path": "/sys/class/misc/tpm0/device/cancel",
-                 "path": "/dev/tpm0"
-               }
-           },
-         "id": "tpm0"
-       }
-     ]
-   }
-
-query-tpm-models
-----------------
-
-Return a list of supported TPM models.
-
-Arguments: None
-
-Example:
-
--> { "execute": "query-tpm-models" }
-<- { "return": [ "tpm-tis" ] }
-
-query-tpm-types
----------------
-
-Return a list of supported TPM types.
-
-Arguments: None
-
-Example:
-
--> { "execute": "query-tpm-types" }
-<- { "return": [ "passthrough" ] }
-
-chardev-add
-----------------
-
-Add a chardev.
-
-Arguments:
-
-- "id": the chardev's ID, must be unique (json-string)
-- "backend": chardev backend type + parameters
-
-Examples:
-
--> { "execute" : "chardev-add",
-     "arguments" : { "id" : "foo",
-                     "backend" : { "type" : "null", "data" : {} } } }
-<- { "return": {} }
-
--> { "execute" : "chardev-add",
-     "arguments" : { "id" : "bar",
-                     "backend" : { "type" : "file",
-                                   "data" : { "out" : "/tmp/bar.log" } } } }
-<- { "return": {} }
-
--> { "execute" : "chardev-add",
-     "arguments" : { "id" : "baz",
-                     "backend" : { "type" : "pty", "data" : {} } } }
-<- { "return": { "pty" : "/dev/pty/42" } }
-
-chardev-remove
---------------
-
-Remove a chardev.
-
-Arguments:
-
-- "id": the chardev's ID, must exist and not be in use (json-string)
-
-Example:
-
--> { "execute": "chardev-remove", "arguments": { "id" : "foo" } }
-<- { "return": {} }
-
-query-rx-filter
----------------
-
-Show rx-filter information.
-
-Returns a json-array of rx-filter information for all NICs (or for the
-given NIC), returning an error if the given NIC doesn't exist, or
-given NIC doesn't support rx-filter querying, or given net client
-isn't a NIC.
-
-The query will clear the event notification flag of each NIC, then qemu
-will start to emit event to QMP monitor.
-
-Each array entry contains the following:
-
-- "name": net client name (json-string)
-- "promiscuous": promiscuous mode is enabled (json-bool)
-- "multicast": multicast receive state (one of 'normal', 'none', 'all')
-- "unicast": unicast receive state  (one of 'normal', 'none', 'all')
-- "vlan": vlan receive state (one of 'normal', 'none', 'all') (Since 2.0)
-- "broadcast-allowed": allow to receive broadcast (json-bool)
-- "multicast-overflow": multicast table is overflowed (json-bool)
-- "unicast-overflow": unicast table is overflowed (json-bool)
-- "main-mac": main macaddr string (json-string)
-- "vlan-table": a json-array of active vlan id
-- "unicast-table": a json-array of unicast macaddr string
-- "multicast-table": a json-array of multicast macaddr string
-
-Example:
-
--> { "execute": "query-rx-filter", "arguments": { "name": "vnet0" } }
-<- { "return": [
-        {
-            "promiscuous": true,
-            "name": "vnet0",
-            "main-mac": "52:54:00:12:34:56",
-            "unicast": "normal",
-            "vlan": "normal",
-            "vlan-table": [
-                4,
-                0
-            ],
-            "unicast-table": [
-            ],
-            "multicast": "normal",
-            "multicast-overflow": false,
-            "unicast-overflow": false,
-            "multicast-table": [
-                "01:00:5e:00:00:01",
-                "33:33:00:00:00:01",
-                "33:33:ff:12:34:56"
-            ],
-            "broadcast-allowed": false
-        }
-      ]
-   }
-
-blockdev-add
-------------
-
-Add a block device.
-
-This command is still a work in progress.  It doesn't support all
-block drivers among other things.  Stay away from it unless you want
-to help with its development.
-
-For the arguments, see the QAPI schema documentation of BlockdevOptions.
-
-Example (1):
-
--> { "execute": "blockdev-add",
-    "arguments": { "driver": "qcow2",
-                   "file": { "driver": "file",
-                             "filename": "test.qcow2" } } }
-<- { "return": {} }
-
-Example (2):
-
--> { "execute": "blockdev-add",
-     "arguments": {
-         "driver": "qcow2",
-         "node-name": "my_disk",
-         "discard": "unmap",
-         "cache": {
-             "direct": true,
-             "writeback": true
-         },
-         "file": {
-             "driver": "file",
-             "filename": "/tmp/test.qcow2"
-         },
-         "backing": {
-             "driver": "raw",
-             "file": {
-                 "driver": "file",
-                 "filename": "/dev/fdset/4"
-             }
-         }
-       }
-     }
-
-<- { "return": {} }
-
-x-blockdev-del
-------------
-Since 2.5
-
-Deletes a block device that has been added using blockdev-add.
-The command will fail if the node is attached to a device or is
-otherwise being used.
-
-This command is still a work in progress and is considered
-experimental. Stay away from it unless you want to help with its
-development.
-
-Arguments:
-
-- "node-name": Name of the graph node to delete (json-string)
-
-Example:
-
--> { "execute": "blockdev-add",
-     "arguments": {
-         "driver": "qcow2",
-         "node-name": "node0",
-         "file": {
-             "driver": "file",
-             "filename": "test.qcow2"
-         }
-     }
-   }
-
-<- { "return": {} }
-
--> { "execute": "x-blockdev-del",
-     "arguments": { "node-name": "node0" }
-   }
-<- { "return": {} }
-
-blockdev-open-tray
-------------------
-
-Opens a block device's tray. If there is a block driver state tree inserted as a
-medium, it will become inaccessible to the guest (but it will remain associated
-to the block device, so closing the tray will make it accessible again).
-
-If the tray was already open before, this will be a no-op.
-
-Once the tray opens, a DEVICE_TRAY_MOVED event is emitted. There are cases in
-which no such event will be generated, these include:
-- if the guest has locked the tray, @force is false and the guest does not
-  respond to the eject request
-- if the BlockBackend denoted by @device does not have a guest device attached
-  to it
-- if the guest device does not have an actual tray and is empty, for instance
-  for floppy disk drives
-
-Arguments:
-
-- "device": block device name (deprecated, use @id instead)
-            (json-string, optional)
-- "id": the name or QOM path of the guest device (json-string, optional)
-- "force": if false (the default), an eject request will be sent to the guest if
-           it has locked the tray (and the tray will not be opened immediately);
-           if true, the tray will be opened regardless of whether it is locked
-           (json-bool, optional)
-
-Example:
-
--> { "execute": "blockdev-open-tray",
-     "arguments": { "id": "ide0-1-0" } }
-
-<- { "timestamp": { "seconds": 1418751016,
-                    "microseconds": 716996 },
-     "event": "DEVICE_TRAY_MOVED",
-     "data": { "device": "ide1-cd0",
-               "id": "ide0-1-0",
-               "tray-open": true } }
-
-<- { "return": {} }
-
-blockdev-close-tray
--------------------
-
-Closes a block device's tray. If there is a block driver state tree associated
-with the block device (which is currently ejected), that tree will be loaded as
-the medium.
-
-If the tray was already closed before, this will be a no-op.
-
-Arguments:
-
-- "device": block device name (deprecated, use @id instead)
-            (json-string, optional)
-- "id": the name or QOM path of the guest device (json-string, optional)
-
-Example:
-
--> { "execute": "blockdev-close-tray",
-     "arguments": { "id": "ide0-1-0" } }
-
-<- { "timestamp": { "seconds": 1418751345,
-                    "microseconds": 272147 },
-     "event": "DEVICE_TRAY_MOVED",
-     "data": { "device": "ide1-cd0",
-               "id": "ide0-1-0",
-               "tray-open": false } }
-
-<- { "return": {} }
-
-x-blockdev-remove-medium
-------------------------
-
-Removes a medium (a block driver state tree) from a block device. That block
-device's tray must currently be open (unless there is no attached guest device).
-
-If the tray is open and there is no medium inserted, this will be a no-op.
-
-This command is still a work in progress and is considered experimental.
-Stay away from it unless you want to help with its development.
-
-Arguments:
-
-- "device": block device name (deprecated, use @id instead)
-            (json-string, optional)
-- "id": the name or QOM path of the guest device (json-string, optional)
-
-Example:
-
--> { "execute": "x-blockdev-remove-medium",
-     "arguments": { "id": "ide0-1-0" } }
-
-<- { "error": { "class": "GenericError",
-                "desc": "Tray of device 'ide0-1-0' is not open" } }
-
--> { "execute": "blockdev-open-tray",
-     "arguments": { "id": "ide0-1-0" } }
-
-<- { "timestamp": { "seconds": 1418751627,
-                    "microseconds": 549958 },
-     "event": "DEVICE_TRAY_MOVED",
-     "data": { "device": "ide1-cd0",
-               "id": "ide0-1-0",
-               "tray-open": true } }
-
-<- { "return": {} }
-
--> { "execute": "x-blockdev-remove-medium",
-     "arguments": { "device": "ide0-1-0" } }
-
-<- { "return": {} }
-
-x-blockdev-insert-medium
-------------------------
-
-Inserts a medium (a block driver state tree) into a block device. That block
-device's tray must currently be open (unless there is no attached guest device)
-and there must be no medium inserted already.
-
-This command is still a work in progress and is considered experimental.
-Stay away from it unless you want to help with its development.
-
-Arguments:
-
-- "device": block device name (deprecated, use @id instead)
-            (json-string, optional)
-- "id": the name or QOM path of the guest device (json-string, optional)
-- "node-name": root node of the BDS tree to insert into the block device
-
-Example:
-
--> { "execute": "blockdev-add",
-     "arguments": { { "node-name": "node0",
-                      "driver": "raw",
-                      "file": { "driver": "file",
-                                "filename": "fedora.iso" } } }
-
-<- { "return": {} }
-
--> { "execute": "x-blockdev-insert-medium",
-     "arguments": { "id": "ide0-1-0",
-                    "node-name": "node0" } }
-
-<- { "return": {} }
-
-x-blockdev-change
------------------
-
-Dynamically reconfigure the block driver state graph. It can be used
-to add, remove, insert or replace a graph node. Currently only the
-Quorum driver implements this feature to add or remove its child. This
-is useful to fix a broken quorum child.
-
-If @node is specified, it will be inserted under @parent. @child
-may not be specified in this case. If both @parent and @child are
-specified but @node is not, @child will be detached from @parent.
-
-Arguments:
-- "parent": the id or name of the parent node (json-string)
-- "child": the name of a child under the given parent node (json-string, optional)
-- "node": the name of the node that will be added (json-string, optional)
-
-Note: this command is experimental, and not a stable API. It doesn't
-support all kinds of operations, all kinds of children, nor all block
-drivers.
-
-Warning: The data in a new quorum child MUST be consistent with that of
-the rest of the array.
-
-Example:
-
-Add a new node to a quorum
--> { "execute": "blockdev-add",
-     "arguments": { "driver": "raw",
-                    "node-name": "new_node",
-                    "file": { "driver": "file",
-                              "filename": "test.raw" } } }
-<- { "return": {} }
--> { "execute": "x-blockdev-change",
-     "arguments": { "parent": "disk1",
-                    "node": "new_node" } }
-<- { "return": {} }
-
-Delete a quorum's node
--> { "execute": "x-blockdev-change",
-     "arguments": { "parent": "disk1",
-                    "child": "children.1" } }
-<- { "return": {} }
-
-query-named-block-nodes
------------------------
-
-Return a list of BlockDeviceInfo for all the named block driver nodes
-
-Example:
-
--> { "execute": "query-named-block-nodes" }
-<- { "return": [ { "ro":false,
-                   "drv":"qcow2",
-                   "encrypted":false,
-                   "file":"disks/test.qcow2",
-                   "node-name": "my-node",
-                   "backing_file_depth":1,
-                   "bps":1000000,
-                   "bps_rd":0,
-                   "bps_wr":0,
-                   "iops":1000000,
-                   "iops_rd":0,
-                   "iops_wr":0,
-                   "bps_max": 8000000,
-                   "bps_rd_max": 0,
-                   "bps_wr_max": 0,
-                   "iops_max": 0,
-                   "iops_rd_max": 0,
-                   "iops_wr_max": 0,
-                   "iops_size": 0,
-                   "write_threshold": 0,
-                   "image":{
-                      "filename":"disks/test.qcow2",
-                      "format":"qcow2",
-                      "virtual-size":2048000,
-                      "backing_file":"base.qcow2",
-                      "full-backing-filename":"disks/base.qcow2",
-                      "backing-filename-format":"qcow2",
-                      "snapshots":[
-                         {
-                            "id": "1",
-                            "name": "snapshot1",
-                            "vm-state-size": 0,
-                            "date-sec": 10000200,
-                            "date-nsec": 12,
-                            "vm-clock-sec": 206,
-                            "vm-clock-nsec": 30
-                         }
-                      ],
-                      "backing-image":{
-                          "filename":"disks/base.qcow2",
-                          "format":"qcow2",
-                          "virtual-size":2048000
-                      }
-                   } } ] }
-
-blockdev-change-medium
-----------------------
-
-Changes the medium inserted into a block device by ejecting the current medium
-and loading a new image file which is inserted as the new medium.
-
-Arguments:
-
-- "device": block device name (deprecated, use @id instead)
-            (json-string, optional)
-- "id": the name or QOM path of the guest device (json-string, optional)
-- "filename": filename of the new image (json-string)
-- "format": format of the new image (json-string, optional)
-- "read-only-mode": new read-only mode (json-string, optional)
-          - Possible values: "retain" (default), "read-only", "read-write"
-
-Examples:
-
-1. Change a removable medium
-
--> { "execute": "blockdev-change-medium",
-             "arguments": { "id": "ide0-1-0",
-                            "filename": "/srv/images/Fedora-12-x86_64-DVD.iso",
-                            "format": "raw" } }
-<- { "return": {} }
-
-2. Load a read-only medium into a writable drive
-
--> { "execute": "blockdev-change-medium",
-             "arguments": { "id": "floppyA",
-                            "filename": "/srv/images/ro.img",
-                            "format": "raw",
-                            "read-only-mode": "retain" } }
-
-<- { "error":
-     { "class": "GenericError",
-       "desc": "Could not open '/srv/images/ro.img': Permission denied" } }
-
--> { "execute": "blockdev-change-medium",
-             "arguments": { "id": "floppyA",
-                            "filename": "/srv/images/ro.img",
-                            "format": "raw",
-                            "read-only-mode": "read-only" } }
-
-<- { "return": {} }
-
-query-memdev
-------------
-
-Show memory devices information.
-
-
-Example (1):
-
--> { "execute": "query-memdev" }
-<- { "return": [
-       {
-         "size": 536870912,
-         "merge": false,
-         "dump": true,
-         "prealloc": false,
-         "host-nodes": [0, 1],
-         "policy": "bind"
-       },
-       {
-         "size": 536870912,
-         "merge": false,
-         "dump": true,
-         "prealloc": true,
-         "host-nodes": [2, 3],
-         "policy": "preferred"
-       }
-     ]
-   }
-
-query-memory-devices
---------------------
-
-Return a list of memory devices.
-
-Example:
--> { "execute": "query-memory-devices" }
-<- { "return": [ { "data":
-                      { "addr": 5368709120,
-                        "hotpluggable": true,
-                        "hotplugged": true,
-                        "id": "d1",
-                        "memdev": "/objects/memX",
-                        "node": 0,
-                        "size": 1073741824,
-                        "slot": 0},
-                   "type": "dimm"
-                 } ] }
-
-query-acpi-ospm-status
-----------------------
-
-Return list of ACPIOSTInfo for devices that support status reporting
-via ACPI _OST method.
-
-Example:
--> { "execute": "query-acpi-ospm-status" }
-<- { "return": [ { "device": "d1", "slot": "0", "slot-type": "DIMM", "source": 1, "status": 0},
-                 { "slot": "1", "slot-type": "DIMM", "source": 0, "status": 0},
-                 { "slot": "2", "slot-type": "DIMM", "source": 0, "status": 0},
-                 { "slot": "3", "slot-type": "DIMM", "source": 0, "status": 0}
-   ]}
-
-rtc-reset-reinjection
----------------------
-
-Reset the RTC interrupt reinjection backlog.
-
-Arguments: None.
-
-Example:
-
--> { "execute": "rtc-reset-reinjection" }
-<- { "return": {} }
-
-trace-event-get-state
----------------------
-
-Query the state of events.
-
-Arguments:
-
-- "name": Event name pattern (json-string).
-- "vcpu": The vCPU to query, any vCPU by default (json-int, optional).
-
-An event is returned if:
-- its name matches the "name" pattern, and
-- if "vcpu" is given, the event has the "vcpu" property.
-
-Therefore, if "vcpu" is given, the operation will only match per-vCPU events,
-returning their state on the specified vCPU. Special case: if "name" is an exact
-match, "vcpu" is given and the event does not have the "vcpu" property, an error
-is returned.
-
-Example:
-
--> { "execute": "trace-event-get-state", "arguments": { "name": "qemu_memalign" } }
-<- { "return": [ { "name": "qemu_memalign", "state": "disabled" } ] }
-
-trace-event-set-state
----------------------
-
-Set the state of events.
-
-Arguments:
-
-- "name": Event name pattern (json-string).
-- "enable": Whether to enable or disable the event (json-bool).
-- "ignore-unavailable": Whether to ignore errors for events that cannot be
-  changed (json-bool, optional).
-- "vcpu": The vCPU to act upon, all vCPUs by default (json-int, optional).
-
-An event's state is modified if:
-- its name matches the "name" pattern, and
-- if "vcpu" is given, the event has the "vcpu" property.
-
-Therefore, if "vcpu" is given, the operation will only match per-vCPU events,
-setting their state on the specified vCPU. Special case: if "name" is an exact
-match, "vcpu" is given and the event does not have the "vcpu" property, an error
-is returned.
-
-Example:
-
--> { "execute": "trace-event-set-state", "arguments": { "name": "qemu_memalign", "enable": "true" } }
-<- { "return": {} }
-
-input-send-event
-----------------
-
-Send input event to guest.
-
-Arguments:
-
-- "device": display device (json-string, optional)
-- "head": display head (json-int, optional)
-- "events": list of input events
-
-The consoles are visible in the qom tree, under
-/backend/console[$index]. They have a device link and head property, so
-it is possible to map which console belongs to which device and display.
-
-Example (1):
-
-Press left mouse button.
-
--> { "execute": "input-send-event",
-    "arguments": { "device": "video0",
-                   "events": [ { "type": "btn",
-                   "data" : { "down": true, "button": "left" } } ] } }
-<- { "return": {} }
-
--> { "execute": "input-send-event",
-    "arguments": { "device": "video0",
-                   "events": [ { "type": "btn",
-                   "data" : { "down": false, "button": "left" } } ] } }
-<- { "return": {} }
-
-Example (2):
-
-Press ctrl-alt-del.
-
--> { "execute": "input-send-event",
-     "arguments": { "events": [
-        { "type": "key", "data" : { "down": true,
-          "key": {"type": "qcode", "data": "ctrl" } } },
-        { "type": "key", "data" : { "down": true,
-          "key": {"type": "qcode", "data": "alt" } } },
-        { "type": "key", "data" : { "down": true,
-          "key": {"type": "qcode", "data": "delete" } } } ] } }
-<- { "return": {} }
-
-Example (3):
-
-Move mouse pointer to absolute coordinates (20000, 400).
-
--> { "execute": "input-send-event" ,
-  "arguments": { "events": [
-               { "type": "abs", "data" : { "axis": "x", "value" : 20000 } },
-               { "type": "abs", "data" : { "axis": "y", "value" : 400 } } ] } }
-<- { "return": {} }
-
-block-set-write-threshold
-------------
-
-Change the write threshold for a block drive. The threshold is an offset,
-thus must be non-negative. Default is no write threshold.
-Setting the threshold to zero disables it.
-
-Arguments:
-
-- "node-name": the node name in the block driver state graph (json-string)
-- "write-threshold": the write threshold in bytes (json-int)
-
-Example:
-
--> { "execute": "block-set-write-threshold",
-  "arguments": { "node-name": "mydev",
-                 "write-threshold": 17179869184 } }
-<- { "return": {} }
-
-Show rocker switch
-------------------
-
-Arguments:
-
-- "name": switch name
-
-Example:
-
--> { "execute": "query-rocker", "arguments": { "name": "sw1" } }
-<- { "return": {"name": "sw1", "ports": 2, "id": 1327446905938}}
-
-Show rocker switch ports
-------------------------
-
-Arguments:
-
-- "name": switch name
-
-Example:
-
--> { "execute": "query-rocker-ports", "arguments": { "name": "sw1" } }
-<- { "return": [ {"duplex": "full", "enabled": true, "name": "sw1.1",
-                  "autoneg": "off", "link-up": true, "speed": 10000},
-                 {"duplex": "full", "enabled": true, "name": "sw1.2",
-                  "autoneg": "off", "link-up": true, "speed": 10000}
-   ]}
-
-Show rocker switch OF-DPA flow tables
--------------------------------------
-
-Arguments:
-
-- "name": switch name
-- "tbl-id": (optional) flow table ID
-
-Example:
-
--> { "execute": "query-rocker-of-dpa-flows", "arguments": { "name": "sw1" } }
-<- { "return": [ {"key": {"in-pport": 0, "priority": 1, "tbl-id": 0},
-                  "hits": 138,
-                  "cookie": 0,
-                  "action": {"goto-tbl": 10},
-                  "mask": {"in-pport": 4294901760}
-                 },
-                 {...more...},
-   ]}
-
-Show rocker OF-DPA group tables
--------------------------------
-
-Arguments:
-
-- "name": switch name
-- "type": (optional) group type
-
-Example:
-
--> { "execute": "query-rocker-of-dpa-groups", "arguments": { "name": "sw1" } }
-<- { "return": [ {"type": 0, "out-pport": 2, "pport": 2, "vlan-id": 3841,
-                  "pop-vlan": 1, "id": 251723778},
-                 {"type": 0, "out-pport": 0, "pport": 0, "vlan-id": 3841,
-                  "pop-vlan": 1, "id": 251723776},
-                 {"type": 0, "out-pport": 1, "pport": 1, "vlan-id": 3840,
-                  "pop-vlan": 1, "id": 251658241},
-                 {"type": 0, "out-pport": 0, "pport": 0, "vlan-id": 3840,
-                  "pop-vlan": 1, "id": 251658240}
-   ]}
-
-query-gic-capabilities
----------------
-
-Return a list of GICCapability objects, describing supported GIC
-(Generic Interrupt Controller) versions.
-
-Arguments: None
-
-Example:
-
--> { "execute": "query-gic-capabilities" }
-<- { "return": [{ "version": 2, "emulated": true, "kernel": false },
-                { "version": 3, "emulated": false, "kernel": true } ] }
-
-Show existing/possible CPUs
----------------------------
-
-Arguments: None.
-
-Example for pseries machine type started with
--smp 2,cores=2,maxcpus=4 -cpu POWER8:
-
--> { "execute": "query-hotpluggable-cpus" }
-<- {"return": [
-     { "props": { "core-id": 8 }, "type": "POWER8-spapr-cpu-core",
-       "vcpus-count": 1 },
-     { "props": { "core-id": 0 }, "type": "POWER8-spapr-cpu-core",
-       "vcpus-count": 1, "qom-path": "/machine/unattached/device[0]"}
-   ]}'
-
-Example for pc machine type started with
--smp 1,maxcpus=2:
-    -> { "execute": "query-hotpluggable-cpus" }
-    <- {"return": [
-         {
-            "type": "qemu64-x86_64-cpu", "vcpus-count": 1,
-            "props": {"core-id": 0, "socket-id": 1, "thread-id": 0}
-         },
-         {
-            "qom-path": "/machine/unattached/device[0]",
-            "type": "qemu64-x86_64-cpu", "vcpus-count": 1,
-            "props": {"core-id": 0, "socket-id": 0, "thread-id": 0}
-         }
-       ]}
diff --git a/docs/qmp-events.txt b/docs/qmp-events.txt
deleted file mode 100644
index e0a2365..0000000
--- a/docs/qmp-events.txt
+++ /dev/null
@@ -1,731 +0,0 @@
-                   QEMU Machine Protocol Events
-                   ============================
-
-ACPI_DEVICE_OST
----------------
-
-Emitted when guest executes ACPI _OST method.
-
- - data: ACPIOSTInfo type as described in qapi-schema.json
-
-{ "event": "ACPI_DEVICE_OST",
-     "data": { "device": "d1", "slot": "0", "slot-type": "DIMM", "source": 1, "status": 0 } }
-
-BALLOON_CHANGE
---------------
-
-Emitted when the guest changes the actual BALLOON level. This
-value is equivalent to the 'actual' field return by the
-'query-balloon' command
-
-Data:
-
-- "actual": actual level of the guest memory balloon in bytes (json-number)
-
-Example:
-
-{ "event": "BALLOON_CHANGE",
-    "data": { "actual": 944766976 },
-    "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
-
-Note: this event is rate-limited.
-
-BLOCK_IMAGE_CORRUPTED
----------------------
-
-Emitted when a disk image is being marked corrupt. The image can be
-identified by its device or node name. The 'device' field is always
-present for compatibility reasons, but it can be empty ("") if the
-image does not have a device name associated.
-
-Data:
-
-- "device":    Device name (json-string)
-- "node-name": Node name (json-string, optional)
-- "msg":       Informative message (e.g., reason for the corruption)
-               (json-string)
-- "offset":    If the corruption resulted from an image access, this
-               is the host's access offset into the image
-               (json-int, optional)
-- "size":      If the corruption resulted from an image access, this
-               is the access size (json-int, optional)
-
-Example:
-
-{ "event": "BLOCK_IMAGE_CORRUPTED",
-    "data": { "device": "ide0-hd0", "node-name": "node0",
-        "msg": "Prevented active L1 table overwrite", "offset": 196608,
-        "size": 65536 },
-    "timestamp": { "seconds": 1378126126, "microseconds": 966463 } }
-
-BLOCK_IO_ERROR
---------------
-
-Emitted when a disk I/O error occurs.
-
-Data:
-
-- "device": device name. This is always present for compatibility
-            reasons, but it can be empty ("") if the image does not
-            have a device name associated. (json-string)
-- "node-name": node name. Note that errors may be reported for the root node
-               that is directly attached to a guest device rather than for the
-               node where the error occurred. (json-string)
-- "operation": I/O operation (json-string, "read" or "write")
-- "action": action that has been taken, it's one of the following (json-string):
-    "ignore": error has been ignored
-    "report": error has been reported to the device
-    "stop": the VM is going to stop because of the error
-
-Example:
-
-{ "event": "BLOCK_IO_ERROR",
-    "data": { "device": "ide0-hd1",
-              "node-name": "#block212",
-              "operation": "write",
-              "action": "stop" },
-    "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
-
-Note: If action is "stop", a STOP event will eventually follow the
-BLOCK_IO_ERROR event.
-
-BLOCK_JOB_CANCELLED
--------------------
-
-Emitted when a block job has been cancelled.
-
-Data:
-
-- "type":     Job type (json-string; "stream" for image streaming
-                                     "commit" for block commit)
-- "device":   Job identifier. Originally the device name but other
-              values are allowed since QEMU 2.7 (json-string)
-- "len":      Maximum progress value (json-int)
-- "offset":   Current progress value (json-int)
-              On success this is equal to len.
-              On failure this is less than len.
-- "speed":    Rate limit, bytes per second (json-int)
-
-Example:
-
-{ "event": "BLOCK_JOB_CANCELLED",
-     "data": { "type": "stream", "device": "virtio-disk0",
-               "len": 10737418240, "offset": 134217728,
-               "speed": 0 },
-     "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
-
-BLOCK_JOB_COMPLETED
--------------------
-
-Emitted when a block job has completed.
-
-Data:
-
-- "type":     Job type (json-string; "stream" for image streaming
-                                     "commit" for block commit)
-- "device":   Job identifier. Originally the device name but other
-              values are allowed since QEMU 2.7 (json-string)
-- "len":      Maximum progress value (json-int)
-- "offset":   Current progress value (json-int)
-              On success this is equal to len.
-              On failure this is less than len.
-- "speed":    Rate limit, bytes per second (json-int)
-- "error":    Error message (json-string, optional)
-              Only present on failure.  This field contains a human-readable
-              error message.  There are no semantics other than that streaming
-              has failed and clients should not try to interpret the error
-              string.
-
-Example:
-
-{ "event": "BLOCK_JOB_COMPLETED",
-     "data": { "type": "stream", "device": "virtio-disk0",
-               "len": 10737418240, "offset": 10737418240,
-               "speed": 0 },
-     "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
-
-BLOCK_JOB_ERROR
----------------
-
-Emitted when a block job encounters an error.
-
-Data:
-
-- "device": Job identifier. Originally the device name but other
-            values are allowed since QEMU 2.7 (json-string)
-- "operation": I/O operation (json-string, "read" or "write")
-- "action": action that has been taken, it's one of the following (json-string):
-    "ignore": error has been ignored, the job may fail later
-    "report": error will be reported and the job canceled
-    "stop": error caused job to be paused
-
-Example:
-
-{ "event": "BLOCK_JOB_ERROR",
-    "data": { "device": "ide0-hd1",
-              "operation": "write",
-              "action": "stop" },
-    "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
-
-BLOCK_JOB_READY
----------------
-
-Emitted when a block job is ready to complete.
-
-Data:
-
-- "type":     Job type (json-string; "stream" for image streaming
-                                     "commit" for block commit)
-- "device":   Job identifier. Originally the device name but other
-              values are allowed since QEMU 2.7 (json-string)
-- "len":      Maximum progress value (json-int)
-- "offset":   Current progress value (json-int)
-              On success this is equal to len.
-              On failure this is less than len.
-- "speed":    Rate limit, bytes per second (json-int)
-
-Example:
-
-{ "event": "BLOCK_JOB_READY",
-    "data": { "device": "drive0", "type": "mirror", "speed": 0,
-              "len": 2097152, "offset": 2097152 }
-    "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
-
-Note: The "ready to complete" status is always reset by a BLOCK_JOB_ERROR
-event.
-
-DEVICE_DELETED
---------------
-
-Emitted whenever the device removal completion is acknowledged
-by the guest.
-At this point, it's safe to reuse the specified device ID.
-Device removal can be initiated by the guest or by HMP/QMP commands.
-
-Data:
-
-- "device": device name (json-string, optional)
-- "path": device path (json-string)
-
-{ "event": "DEVICE_DELETED",
-  "data": { "device": "virtio-net-pci-0",
-            "path": "/machine/peripheral/virtio-net-pci-0" },
-  "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
-
-DEVICE_TRAY_MOVED
------------------
-
-It's emitted whenever the tray of a removable device is moved by the guest
-or by HMP/QMP commands.
-
-Data:
-
-- "device": Block device name. This is always present for compatibility
-            reasons, but it can be empty ("") if the image does not have a
-            device name associated. (json-string)
-- "id": The name or QOM path of the guest device (json-string)
-- "tray-open": true if the tray has been opened or false if it has been closed
-               (json-bool)
-
-{ "event": "DEVICE_TRAY_MOVED",
-  "data": { "device": "ide1-cd0",
-            "id": "/machine/unattached/device[22]",
-            "tray-open": true
-  },
-  "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
-
-DUMP_COMPLETED
---------------
-
-Emitted when the guest has finished one memory dump.
-
-Data:
-
-- "result": DumpQueryResult type described in qapi-schema.json
-- "error": Error message when dump failed. This is only a
-  human-readable string provided when dump failed. It should not be
-  parsed in any way (json-string, optional)
-
-Example:
-
-{ "event": "DUMP_COMPLETED",
-  "data": {"result": {"total": 1090650112, "status": "completed",
-                      "completed": 1090650112} } }
-
-GUEST_PANICKED
---------------
-
-Emitted when guest OS panic is detected.
-
-Data:
-
-- "action": Action that has been taken (json-string, currently always "pause").
-
-Example:
-
-{ "event": "GUEST_PANICKED",
-     "data": { "action": "pause" } }
-
-MEM_UNPLUG_ERROR
---------------------
-Emitted when memory hot unplug error occurs.
-
-Data:
-
-- "device": device name (json-string)
-- "msg": Informative message (e.g., reason for the error) (json-string)
-
-Example:
-
-{ "event": "MEM_UNPLUG_ERROR"
-  "data": { "device": "dimm1",
-            "msg": "acpi: device unplug for unsupported device"
-  },
-  "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
-
-NIC_RX_FILTER_CHANGED
----------------------
-
-The event is emitted once until the query command is executed,
-the first event will always be emitted.
-
-Data:
-
-- "name": net client name (json-string)
-- "path": device path (json-string)
-
-{ "event": "NIC_RX_FILTER_CHANGED",
-  "data": { "name": "vnet0",
-            "path": "/machine/peripheral/vnet0/virtio-backend" },
-  "timestamp": { "seconds": 1368697518, "microseconds": 326866 } }
-}
-
-POWERDOWN
----------
-
-Emitted when the Virtual Machine is powered down through the power
-control system, such as via ACPI.
-
-Data: None.
-
-Example:
-
-{ "event": "POWERDOWN",
-    "timestamp": { "seconds": 1267040730, "microseconds": 682951 } }
-
-QUORUM_FAILURE
---------------
-
-Emitted by the Quorum block driver if it fails to establish a quorum.
-
-Data:
-
-- "reference":     device name if defined else node name.
-- "sector-num":    Number of the first sector of the failed read operation.
-- "sectors-count": Failed read operation sector count.
-
-Example:
-
-{ "event": "QUORUM_FAILURE",
-     "data": { "reference": "usr1", "sector-num": 345435, "sectors-count": 5 },
-     "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
-
-Note: this event is rate-limited.
-
-QUORUM_REPORT_BAD
------------------
-
-Emitted to report a corruption of a Quorum file.
-
-Data:
-
-- "type":          Quorum operation type
-- "error":         Error message (json-string, optional)
-                   Only present on failure.  This field contains a human-readable
-                   error message.  There are no semantics other than that the
-                   block layer reported an error and clients should not try to
-                   interpret the error string.
-- "node-name":     The graph node name of the block driver state.
-- "sector-num":    Number of the first sector of the failed read operation.
-- "sectors-count": Failed read operation sector count.
-
-Example:
-
-Read operation:
-{ "event": "QUORUM_REPORT_BAD",
-     "data": { "node-name": "node0", "sector-num": 345435, "sectors-count": 5,
-               "type": "read" },
-     "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
-
-Flush operation:
-{ "event": "QUORUM_REPORT_BAD",
-     "data": { "node-name": "node0", "sector-num": 0, "sectors-count": 2097120,
-               "type": "flush", "error": "Broken pipe" },
-     "timestamp": { "seconds": 1456406829, "microseconds": 291763 } }
-
-Note: this event is rate-limited.
-
-RESET
------
-
-Emitted when the Virtual Machine is reset.
-
-Data: None.
-
-Example:
-
-{ "event": "RESET",
-    "timestamp": { "seconds": 1267041653, "microseconds": 9518 } }
-
-RESUME
-------
-
-Emitted when the Virtual Machine resumes execution.
-
-Data: None.
-
-Example:
-
-{ "event": "RESUME",
-    "timestamp": { "seconds": 1271770767, "microseconds": 582542 } }
-
-RTC_CHANGE
-----------
-
-Emitted when the guest changes the RTC time.
-
-Data:
-
-- "offset": Offset between base RTC clock (as specified by -rtc base), and
-new RTC clock value (json-number)
-
-Example:
-
-{ "event": "RTC_CHANGE",
-    "data": { "offset": 78 },
-    "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
-
-Note: this event is rate-limited.
-
-SHUTDOWN
---------
-
-Emitted when the Virtual Machine has shut down, indicating that qemu
-is about to exit.
-
-Data: None.
-
-Example:
-
-{ "event": "SHUTDOWN",
-    "timestamp": { "seconds": 1267040730, "microseconds": 682951 } }
-
-Note: If the command-line option "-no-shutdown" has been specified, a STOP
-event will eventually follow the SHUTDOWN event.
-
-SPICE_CONNECTED
----------------
-
-Emitted when a SPICE client connects.
-
-Data:
-
-- "server": Server information (json-object)
-  - "host": IP address (json-string)
-  - "port": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-- "client": Client information (json-object)
-  - "host": IP address (json-string)
-  - "port": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-
-Example:
-
-{ "timestamp": {"seconds": 1290688046, "microseconds": 388707},
-  "event": "SPICE_CONNECTED",
-  "data": {
-    "server": { "port": "5920", "family": "ipv4", "host": "127.0.0.1"},
-    "client": {"port": "52873", "family": "ipv4", "host": "127.0.0.1"}
-}}
-
-SPICE_DISCONNECTED
-------------------
-
-Emitted when a SPICE client disconnects.
-
-Data:
-
-- "server": Server information (json-object)
-  - "host": IP address (json-string)
-  - "port": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-- "client": Client information (json-object)
-  - "host": IP address (json-string)
-  - "port": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-
-Example:
-
-{ "timestamp": {"seconds": 1290688046, "microseconds": 388707},
-  "event": "SPICE_DISCONNECTED",
-  "data": {
-    "server": { "port": "5920", "family": "ipv4", "host": "127.0.0.1"},
-    "client": {"port": "52873", "family": "ipv4", "host": "127.0.0.1"}
-}}
-
-SPICE_INITIALIZED
------------------
-
-Emitted after initial handshake and authentication takes place (if any)
-and the SPICE channel is up and running
-
-Data:
-
-- "server": Server information (json-object)
-  - "host": IP address (json-string)
-  - "port": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-  - "auth": authentication method (json-string, optional)
-- "client": Client information (json-object)
-  - "host": IP address (json-string)
-  - "port": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-  - "connection-id": spice connection id.  All channels with the same id
-                     belong to the same spice session (json-int)
-  - "channel-type": channel type.  "1" is the main control channel, filter for
-                    this one if you want track spice sessions only (json-int)
-  - "channel-id": channel id.  Usually "0", might be different needed when
-                  multiple channels of the same type exist, such as multiple
-                  display channels in a multihead setup (json-int)
-  - "tls": whevener the channel is encrypted (json-bool)
-
-Example:
-
-{ "timestamp": {"seconds": 1290688046, "microseconds": 417172},
-  "event": "SPICE_INITIALIZED",
-  "data": {"server": {"auth": "spice", "port": "5921",
-                      "family": "ipv4", "host": "127.0.0.1"},
-           "client": {"port": "49004", "family": "ipv4", "channel-type": 3,
-                      "connection-id": 1804289383, "host": "127.0.0.1",
-                      "channel-id": 0, "tls": true}
-}}
-
-SPICE_MIGRATE_COMPLETED
------------------------
-
-Emitted when SPICE migration has completed
-
-Data: None.
-
-Example:
-
-{ "timestamp": {"seconds": 1290688046, "microseconds": 417172},
-  "event": "SPICE_MIGRATE_COMPLETED" }
-
-MIGRATION
----------
-
-Emitted when a migration event happens
-
-Data: None.
-
- - "status": migration status
-     See MigrationStatus in ~/qapi-schema.json for possible values
-
-Example:
-
-{"timestamp": {"seconds": 1432121972, "microseconds": 744001},
- "event": "MIGRATION", "data": {"status": "completed"}}
-
-MIGRATION_PASS
---------------
-
-Emitted from the source side of a migration at the start of each pass
-(when it syncs the dirty bitmap)
-
-Data: None.
-
-  - "pass": An incrementing count (starting at 1 on the first pass)
-
-Example:
-{"timestamp": {"seconds": 1449669631, "microseconds": 239225},
- "event": "MIGRATION_PASS", "data": {"pass": 2}}
-
-STOP
-----
-
-Emitted when the Virtual Machine is stopped.
-
-Data: None.
-
-Example:
-
-{ "event": "STOP",
-    "timestamp": { "seconds": 1267041730, "microseconds": 281295 } }
-
-SUSPEND
--------
-
-Emitted when guest enters S3 state.
-
-Data: None.
-
-Example:
-
-{ "event": "SUSPEND",
-     "timestamp": { "seconds": 1344456160, "microseconds": 309119 } }
-
-SUSPEND_DISK
-------------
-
-Emitted when the guest makes a request to enter S4 state.
-
-Data: None.
-
-Example:
-
-{ "event": "SUSPEND_DISK",
-     "timestamp": { "seconds": 1344456160, "microseconds": 309119 } }
-
-Note: QEMU shuts down when entering S4 state.
-
-VNC_CONNECTED
--------------
-
-Emitted when a VNC client establishes a connection.
-
-Data:
-
-- "server": Server information (json-object)
-  - "host": IP address (json-string)
-  - "service": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-  - "auth": authentication method (json-string, optional)
-- "client": Client information (json-object)
-  - "host": IP address (json-string)
-  - "service": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-
-Example:
-
-{ "event": "VNC_CONNECTED",
-    "data": {
-        "server": { "auth": "sasl", "family": "ipv4",
-                    "service": "5901", "host": "0.0.0.0" },
-        "client": { "family": "ipv4", "service": "58425",
-                    "host": "127.0.0.1" } },
-    "timestamp": { "seconds": 1262976601, "microseconds": 975795 } }
-
-
-Note: This event is emitted before any authentication takes place, thus
-the authentication ID is not provided.
-
-VNC_DISCONNECTED
-----------------
-
-Emitted when the connection is closed.
-
-Data:
-
-- "server": Server information (json-object)
-  - "host": IP address (json-string)
-  - "service": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-  - "auth": authentication method (json-string, optional)
-- "client": Client information (json-object)
-  - "host": IP address (json-string)
-  - "service": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-  - "x509_dname": TLS dname (json-string, optional)
-  - "sasl_username": SASL username (json-string, optional)
-
-Example:
-
-{ "event": "VNC_DISCONNECTED",
-    "data": {
-        "server": { "auth": "sasl", "family": "ipv4",
-                    "service": "5901", "host": "0.0.0.0" },
-        "client": { "family": "ipv4", "service": "58425",
-                    "host": "127.0.0.1", "sasl_username": "luiz" } },
-    "timestamp": { "seconds": 1262976601, "microseconds": 975795 } }
-
-VNC_INITIALIZED
----------------
-
-Emitted after authentication takes place (if any) and the VNC session is
-made active.
-
-Data:
-
-- "server": Server information (json-object)
-  - "host": IP address (json-string)
-  - "service": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-  - "auth": authentication method (json-string, optional)
-- "client": Client information (json-object)
-  - "host": IP address (json-string)
-  - "service": port number (json-string)
-  - "family": address family (json-string, "ipv4" or "ipv6")
-  - "x509_dname": TLS dname (json-string, optional)
-  - "sasl_username": SASL username (json-string, optional)
-
-Example:
-
-{ "event": "VNC_INITIALIZED",
-    "data": {
-        "server": { "auth": "sasl", "family": "ipv4",
-                    "service": "5901", "host": "0.0.0.0"},
-        "client": { "family": "ipv4", "service": "46089",
-                    "host": "127.0.0.1", "sasl_username": "luiz" } },
-        "timestamp": { "seconds": 1263475302, "microseconds": 150772 } }
-
-VSERPORT_CHANGE
----------------
-
-Emitted when the guest opens or closes a virtio-serial port.
-
-Data:
-
-- "id": device identifier of the virtio-serial port (json-string)
-- "open": true if the guest has opened the virtio-serial port (json-bool)
-
-Example:
-
-{ "event": "VSERPORT_CHANGE",
-    "data": { "id": "channel0", "open": true },
-    "timestamp": { "seconds": 1401385907, "microseconds": 422329 } }
-
-Note: this event is rate-limited separately for each "id".
-
-WAKEUP
-------
-
-Emitted when the guest has woken up from S3 and is running.
-
-Data: None.
-
-Example:
-
-{ "event": "WAKEUP",
-     "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
-
-WATCHDOG
---------
-
-Emitted when the watchdog device's timer is expired.
-
-Data:
-
-- "action": Action that has been taken, it's one of the following (json-string):
-            "reset", "shutdown", "poweroff", "pause", "debug", or "none"
-
-Example:
-
-{ "event": "WATCHDOG",
-     "data": { "action": "reset" },
-     "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
-
-Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is
-followed respectively by the RESET, SHUTDOWN, or STOP events.
-
-Note: this event is rate-limited.
diff --git a/qapi-schema.json b/qapi-schema.json
index b7dff19..72ed6f6 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1,6 +1,53 @@
 # -*- Mode: Python -*-
+##
+# = Introduction
+#
+# This document describes all commands currently supported by QMP.
+#
+# Most of the time their usage is exactly the same as in the user Monitor, this
+# means that any other document which also describe commands (the manpage,
+# QEMU's manual, etc) can and should be consulted.
+#
+# QMP has two types of commands: regular and query commands. Regular commands
+# usually change the Virtual Machine's state someway, while query commands just
+# return information. The sections below are divided accordingly.
+#
+# It's important to observe that all communication examples are formatted in
+# a reader-friendly way, so that they're easier to understand. However, in real
+# protocol usage, they're emitted as a single line.
+#
+# Also, the following notation is used to denote data flow:
+#
+# Example:
+#
+# | -> data issued by the Client
+# | <- Server data response
+#
+# Please, refer to the QMP specification (QMP/qmp-spec.txt) for detailed
+# information on the Server command and response formats.
+#
+# = Stability Considerations
+#
+# The current QMP command set (described in this file) may be useful for a
+# number of use cases, however it's limited and several commands have bad
+# defined semantics, specially with regard to command completion.
+#
+# These problems are going to be solved incrementally in the next QEMU releases
+# and we're going to establish a deprecation policy for badly defined commands.
+#
+# If you're planning to adopt QMP, please observe the following:
 #
-# QAPI Schema
+#     1. The deprecation policy will take effect and be documented soon, please
+#        check the documentation of each used command as soon as a new release of
+#        QEMU is available
+#
+#     2. DO NOT rely on anything which is not explicit documented
+#
+#     3. Errors, in special, are not documented. Applications should NOT check
+#        for specific errors classes or data (it's strongly recommended to only
+#        check for the "error" key)
+#
+##
 
 # QAPI common definitions
 { 'include': 'qapi/common.json' }
@@ -89,6 +136,13 @@
 # Returns: nothing on success.
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "add_client", "arguments": { "protocol": "vnc",
+#                                              "fdname": "myclient" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'add_client',
   'data': { 'protocol': 'str', 'fdname': 'str', '*skipauth': 'bool',
@@ -113,6 +167,12 @@
 # Returns: @NameInfo of the guest
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-name" }
+# <- { "return": { "name": "qemu-name" } }
+#
 ##
 { 'command': 'query-name', 'returns': 'NameInfo' }
 
@@ -137,6 +197,12 @@
 # Returns: @KvmInfo
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-kvm" }
+# <- { "return": { "enabled": true, "present": true } }
+#
 ##
 { 'command': 'query-kvm', 'returns': 'KvmInfo' }
 
@@ -216,13 +282,21 @@
 # Returns: @StatusInfo reflecting all VCPUs
 #
 # Since:  0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-status" }
+# <- { "return": { "running": true,
+#                  "singlestep": false,
+#                  "status": "running" } }
+#
 ##
 { 'command': 'query-status', 'returns': 'StatusInfo' }
 
 ##
 # @UuidInfo:
 #
-# Guest UUID information.
+# Guest UUID information (Universally Unique Identifier).
 #
 # @UUID: the UUID of the guest
 #
@@ -240,6 +314,12 @@
 # Returns: The @UuidInfo for the guest
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-uuid" }
+# <- { "return": { "UUID": "550e8400-e29b-41d4-a716-446655440000" } }
+#
 ##
 { 'command': 'query-uuid', 'returns': 'UuidInfo' }
 
@@ -273,6 +353,30 @@
 # Returns: a list of @ChardevInfo
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-chardev" }
+# <- {
+#       "return": [
+#          {
+#             "label": "charchannel0",
+#             "filename": "unix:/var/lib/libvirt/qemu/seabios.rhel6.agent,server",
+#             "frontend-open": false
+#          },
+#          {
+#             "label": "charmonitor",
+#             "filename": "unix:/var/lib/libvirt/qemu/seabios.rhel6.monitor,server",
+#             "frontend-open": true
+#          },
+#          {
+#             "label": "charserial0",
+#             "filename": "pty:/dev/pts/2",
+#             "frontend-open": true
+#          }
+#       ]
+#    }
+#
 ##
 { 'command': 'query-chardev', 'returns': ['ChardevInfo'] }
 
@@ -295,6 +399,27 @@
 # Returns: a list of @ChardevBackendInfo
 #
 # Since: 2.0
+#
+# Example:
+#
+# -> { "execute": "query-chardev-backends" }
+# <- {
+#       "return":[
+#          {
+#             "name":"udp"
+#          },
+#          {
+#             "name":"tcp"
+#          },
+#          {
+#             "name":"unix"
+#          },
+#          {
+#             "name":"spiceport"
+#          }
+#       ]
+#    }
+#
 ##
 { 'command': 'query-chardev-backends', 'returns': ['ChardevBackendInfo'] }
 
@@ -331,6 +456,15 @@
 # Returns: Nothing on success
 #
 # Since: 1.4
+#
+# Example:
+#
+# -> { "execute": "ringbuf-write",
+#      "arguments": { "device": "foo",
+#                     "data": "abcdefgh",
+#                     "format": "utf8" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'ringbuf-write',
   'data': {'device': 'str', 'data': 'str',
@@ -358,6 +492,15 @@
 # Returns: data read from the device
 #
 # Since: 1.4
+#
+# Example:
+#
+# -> { "execute": "ringbuf-read",
+#      "arguments": { "device": "foo",
+#                     "size": 1000,
+#                     "format": "utf8" } }
+# <- { "return": "abcdefgh" }
+#
 ##
 { 'command': 'ringbuf-read',
   'data': {'device': 'str', 'size': 'int', '*format': 'DataFormat'},
@@ -382,6 +525,23 @@
 # Returns: A list of @EventInfo for all supported events
 #
 # Since: 1.2.0
+#
+# Example:
+#
+# -> { "execute": "query-events" }
+# <- {
+#      "return": [
+#          {
+#             "name":"SHUTDOWN"
+#          },
+#          {
+#             "name":"RESET"
+#          }
+#       ]
+#    }
+#
+# Note: This example has been shortened as the real response is too long.
+#
 ##
 { 'command': 'query-events', 'returns': ['EventInfo'] }
 
@@ -540,11 +700,124 @@
 ##
 # @query-migrate:
 #
-# Returns information about current migration process.
+# Returns information about current migration process. If migration
+# is active there will be another json-object with RAM migration
+# status and if block migration is active another one with block
+# migration status.
 #
 # Returns: @MigrationInfo
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# 1. Before the first migration
+#
+# -> { "execute": "query-migrate" }
+# <- { "return": {} }
+#
+# 2. Migration is done and has succeeded
+#
+# -> { "execute": "query-migrate" }
+# <- { "return": {
+#         "status": "completed",
+#         "ram":{
+#           "transferred":123,
+#           "remaining":123,
+#           "total":246,
+#           "total-time":12345,
+#           "setup-time":12345,
+#           "downtime":12345,
+#           "duplicate":123,
+#           "normal":123,
+#           "normal-bytes":123456,
+#           "dirty-sync-count":15
+#         }
+#      }
+#    }
+#
+# 3. Migration is done and has failed
+#
+# -> { "execute": "query-migrate" }
+# <- { "return": { "status": "failed" } }
+#
+# 4. Migration is being performed and is not a block migration:
+#
+# -> { "execute": "query-migrate" }
+# <- {
+#       "return":{
+#          "status":"active",
+#          "ram":{
+#             "transferred":123,
+#             "remaining":123,
+#             "total":246,
+#             "total-time":12345,
+#             "setup-time":12345,
+#             "expected-downtime":12345,
+#             "duplicate":123,
+#             "normal":123,
+#             "normal-bytes":123456,
+#             "dirty-sync-count":15
+#          }
+#       }
+#    }
+#
+# 5. Migration is being performed and is a block migration:
+#
+# -> { "execute": "query-migrate" }
+# <- {
+#       "return":{
+#          "status":"active",
+#          "ram":{
+#             "total":1057024,
+#             "remaining":1053304,
+#             "transferred":3720,
+#             "total-time":12345,
+#             "setup-time":12345,
+#             "expected-downtime":12345,
+#             "duplicate":123,
+#             "normal":123,
+#             "normal-bytes":123456,
+#             "dirty-sync-count":15
+#          },
+#          "disk":{
+#             "total":20971520,
+#             "remaining":20880384,
+#             "transferred":91136
+#          }
+#       }
+#    }
+#
+# 6. Migration is being performed and XBZRLE is active:
+#
+# -> { "execute": "query-migrate" }
+# <- {
+#       "return":{
+#          "status":"active",
+#          "capabilities" : [ { "capability": "xbzrle", "state" : true } ],
+#          "ram":{
+#             "total":1057024,
+#             "remaining":1053304,
+#             "transferred":3720,
+#             "total-time":12345,
+#             "setup-time":12345,
+#             "expected-downtime":12345,
+#             "duplicate":10,
+#             "normal":3333,
+#             "normal-bytes":3412992,
+#             "dirty-sync-count":15
+#          },
+#          "xbzrle-cache":{
+#             "cache-size":67108864,
+#             "bytes":20971520,
+#             "pages":2444343,
+#             "cache-miss":2244,
+#             "cache-miss-rate":0.123,
+#             "overflow":34434
+#          }
+#       }
+#    }
+#
 ##
 { 'command': 'query-migrate', 'returns': 'MigrationInfo' }
 
@@ -618,6 +891,12 @@
 # @capabilities: json array of capability modifications to make
 #
 # Since: 1.2
+#
+# Example:
+#
+# -> { "execute": "migrate-set-capabilities" , "arguments":
+#      { "capabilities": [ { "capability": "xbzrle", "state": true } ] } }
+#
 ##
 { 'command': 'migrate-set-capabilities',
   'data': { 'capabilities': ['MigrationCapabilityStatus'] } }
@@ -630,6 +909,21 @@
 # Returns: @MigrationCapabilitiesStatus
 #
 # Since: 1.2
+#
+# Example:
+#
+# -> { "execute": "query-migrate-capabilities" }
+# <- { "return": [
+#       {"state": false, "capability": "xbzrle"},
+#       {"state": false, "capability": "rdma-pin-all"},
+#       {"state": false, "capability": "auto-converge"},
+#       {"state": false, "capability": "zero-blocks"},
+#       {"state": false, "capability": "compress"},
+#       {"state": true, "capability": "events"},
+#       {"state": false, "capability": "postcopy-ram"},
+#       {"state": false, "capability": "x-colo"}
+#    ]}
+#
 ##
 { 'command': 'query-migrate-capabilities', 'returns':   ['MigrationCapabilityStatus']}
 
@@ -698,6 +992,12 @@
 # Set various migration parameters.  See MigrationParameters for details.
 #
 # Since: 2.4
+#
+# Example:
+#
+# -> { "execute": "migrate-set-parameters" ,
+#      "arguments": { "compress-level": 1 } }
+#
 ##
 { 'command': 'migrate-set-parameters', 'boxed': true,
   'data': 'MigrationParameters' }
@@ -769,6 +1069,21 @@
 # Returns: @MigrationParameters
 #
 # Since: 2.4
+#
+# Example:
+#
+# -> { "execute": "query-migrate-parameters" }
+# <- { "return": {
+#          "decompress-threads": 2,
+#          "cpu-throttle-increment": 10,
+#          "compress-threads": 8,
+#          "compress-level": 1,
+#          "cpu-throttle-initial": 20,
+#          "max-bandwidth": 33554432,
+#          "downtime-limit": 300
+#       }
+#    }
+#
 ##
 { 'command': 'query-migrate-parameters',
   'returns': 'MigrationParameters' }
@@ -787,6 +1102,15 @@
 # @cert-subject: #optional server certificate subject
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "client_migrate_info",
+#      "arguments": { "protocol": "spice",
+#                     "hostname": "virt42.lab.kraxel.org",
+#                     "port": 1234 } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'client_migrate_info',
   'data': { 'protocol': 'str', 'hostname': 'str', '*port': 'int',
@@ -800,6 +1124,12 @@
 # command.
 #
 # Since: 2.5
+#
+# Example:
+#
+# -> { "execute": "migrate-start-postcopy" }
+# <- { "return": {} }
+#
 ##
 { 'command': 'migrate-start-postcopy' }
 
@@ -872,6 +1202,12 @@
 # then takes over server operation to become the service VM.
 #
 # Since: 2.8
+#
+# Example:
+#
+# -> { "execute": "x-colo-lost-heartbeat" }
+# <- { "return": {} }
+#
 ##
 { 'command': 'x-colo-lost-heartbeat' }
 
@@ -902,6 +1238,26 @@
 # Returns: a list of @MouseInfo for each device
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-mice" }
+# <- { "return": [
+#          {
+#             "name":"QEMU Microsoft Mouse",
+#             "index":0,
+#             "current":false,
+#             "absolute":false
+#          },
+#          {
+#             "name":"QEMU PS/2 Mouse",
+#             "index":1,
+#             "current":true,
+#             "absolute":true
+#          }
+#       ]
+#    }
+#
 ##
 { 'command': 'query-mice', 'returns': ['MouseInfo'] }
 
@@ -1026,6 +1382,32 @@
 # Returns: a list of @CpuInfo for each virtual CPU
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-cpus" }
+# <- { "return": [
+#          {
+#             "CPU":0,
+#             "current":true,
+#             "halted":false,
+#             "qom_path":"/machine/unattached/device[0]",
+#             "arch":"x86",
+#             "pc":3227107138,
+#             "thread_id":3134
+#          },
+#          {
+#             "CPU":1,
+#             "current":false,
+#             "halted":true,
+#             "qom_path":"/machine/unattached/device[2]",
+#             "arch":"x86",
+#             "pc":7108165,
+#             "thread_id":3135
+#          }
+#       ]
+#    }
+#
 ##
 { 'command': 'query-cpus', 'returns': ['CpuInfo'] }
 
@@ -1055,6 +1437,22 @@
 # Returns: a list of @IOThreadInfo for each iothread
 #
 # Since: 2.0
+#
+# Example:
+#
+# -> { "execute": "query-iothreads" }
+# <- { "return": [
+#          {
+#             "id":"iothread0",
+#             "thread-id":3134
+#          },
+#          {
+#             "id":"iothread1",
+#             "thread-id":3135
+#          }
+#       ]
+#    }
+#
 ##
 { 'command': 'query-iothreads', 'returns': ['IOThreadInfo'] }
 
@@ -1237,6 +1635,26 @@
 # Returns: @VncInfo
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-vnc" }
+# <- { "return": {
+#          "enabled":true,
+#          "host":"0.0.0.0",
+#          "service":"50402",
+#          "auth":"vnc",
+#          "family":"ipv4",
+#          "clients":[
+#             {
+#                "host":"127.0.0.1",
+#                "service":"50401",
+#                "family":"ipv4"
+#             }
+#          ]
+#       }
+#    }
+#
 ##
 { 'command': 'query-vnc', 'returns': 'VncInfo' }
 
@@ -1334,7 +1752,7 @@
 # @enabled: true if the SPICE server is enabled, false otherwise
 #
 # @migrated: true if the last guest migration completed and spice
-#            migration had completed as well. false otherwise.
+#            migration had completed as well. false otherwise. (since 1.4)
 #
 # @host: #optional The hostname the SPICE server is bound to.  This depends on
 #        the name resolution on the host and may be an IP address.
@@ -1352,9 +1770,7 @@
 #
 # @mouse-mode: The mode in which the mouse cursor is displayed currently. Can
 #              be determined by the client or the server, or unknown if spice
-#              server doesn't provide this information.
-#
-#              Since: 1.1
+#              server doesn't provide this information. (since: 1.1)
 #
 # @channels: a list of @SpiceChannel for each active spice channel
 #
@@ -1373,6 +1789,40 @@
 # Returns: @SpiceInfo
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-spice" }
+# <- { "return": {
+#          "enabled": true,
+#          "auth": "spice",
+#          "port": 5920,
+#          "tls-port": 5921,
+#          "host": "0.0.0.0",
+#          "channels": [
+#             {
+#                "port": "54924",
+#                "family": "ipv4",
+#                "channel-type": 1,
+#                "connection-id": 1804289383,
+#                "host": "127.0.0.1",
+#                "channel-id": 0,
+#                "tls": true
+#             },
+#             {
+#                "port": "36710",
+#                "family": "ipv4",
+#                "channel-type": 4,
+#                "connection-id": 1804289383,
+#                "host": "127.0.0.1",
+#                "channel-id": 0,
+#                "tls": false
+#             },
+#             [ ... more channels follow ... ]
+#          ]
+#       }
+#    }
+#
 ##
 { 'command': 'query-spice', 'returns': 'SpiceInfo' }
 
@@ -1394,11 +1844,22 @@
 # Return information about the balloon device.
 #
 # Returns: @BalloonInfo on success
+#
 #          If the balloon driver is enabled but not functional because the KVM
 #          kernel module cannot support it, KvmMissingCap
+#
 #          If no balloon device is present, DeviceNotActive
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-balloon" }
+# <- { "return": {
+#          "actual": 1073741824,
+#       }
+#    }
+#
 ##
 { 'command': 'query-balloon', 'returns': 'BalloonInfo' }
 
@@ -1425,6 +1886,8 @@
 # @type: 'io' if the region is a PIO region
 #        'memory' if the region is a MMIO region
 #
+# @size: memory size
+#
 # @prefetch: #optional if @type is 'memory', true if the memory is prefetchable
 #
 # @mem_type_64: #optional if @type is 'memory', true if the BAR is 64-bit
@@ -1558,9 +2021,144 @@
 #
 # Return information about the PCI bus topology of the guest.
 #
-# Returns: a list of @PciInfo for each PCI bus
+# Returns: a list of @PciInfo for each PCI bus. Each bus is
+# represented by a json-object, which has a key with a json-array of
+# all PCI devices attached to it. Each device is represented by a
+# json-object.
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-pci" }
+# <- { "return": [
+#          {
+#             "bus": 0,
+#             "devices": [
+#                {
+#                   "bus": 0,
+#                   "qdev_id": "",
+#                   "slot": 0,
+#                   "class_info": {
+#                      "class": 1536,
+#                      "desc": "Host bridge"
+#                   },
+#                   "id": {
+#                      "device": 32902,
+#                      "vendor": 4663
+#                   },
+#                   "function": 0,
+#                   "regions": [
+#                   ]
+#                },
+#                {
+#                   "bus": 0,
+#                   "qdev_id": "",
+#                   "slot": 1,
+#                   "class_info": {
+#                      "class": 1537,
+#                      "desc": "ISA bridge"
+#                   },
+#                   "id": {
+#                      "device": 32902,
+#                      "vendor": 28672
+#                   },
+#                   "function": 0,
+#                   "regions": [
+#                   ]
+#                },
+#                {
+#                   "bus": 0,
+#                   "qdev_id": "",
+#                   "slot": 1,
+#                   "class_info": {
+#                      "class": 257,
+#                      "desc": "IDE controller"
+#                   },
+#                   "id": {
+#                      "device": 32902,
+#                      "vendor": 28688
+#                   },
+#                   "function": 1,
+#                   "regions": [
+#                      {
+#                         "bar": 4,
+#                         "size": 16,
+#                         "address": 49152,
+#                         "type": "io"
+#                      }
+#                   ]
+#                },
+#                {
+#                   "bus": 0,
+#                   "qdev_id": "",
+#                   "slot": 2,
+#                   "class_info": {
+#                      "class": 768,
+#                      "desc": "VGA controller"
+#                   },
+#                   "id": {
+#                      "device": 4115,
+#                      "vendor": 184
+#                   },
+#                   "function": 0,
+#                   "regions": [
+#                      {
+#                         "prefetch": true,
+#                         "mem_type_64": false,
+#                         "bar": 0,
+#                         "size": 33554432,
+#                         "address": 4026531840,
+#                         "type": "memory"
+#                      },
+#                      {
+#                         "prefetch": false,
+#                         "mem_type_64": false,
+#                         "bar": 1,
+#                         "size": 4096,
+#                         "address": 4060086272,
+#                         "type": "memory"
+#                      },
+#                      {
+#                         "prefetch": false,
+#                         "mem_type_64": false,
+#                         "bar": 6,
+#                         "size": 65536,
+#                         "address": -1,
+#                         "type": "memory"
+#                      }
+#                   ]
+#                },
+#                {
+#                   "bus": 0,
+#                   "qdev_id": "",
+#                   "irq": 11,
+#                   "slot": 4,
+#                   "class_info": {
+#                      "class": 1280,
+#                      "desc": "RAM controller"
+#                   },
+#                   "id": {
+#                      "device": 6900,
+#                      "vendor": 4098
+#                   },
+#                   "function": 0,
+#                   "regions": [
+#                      {
+#                         "bar": 0,
+#                         "size": 32,
+#                         "address": 49280,
+#                         "type": "io"
+#                      }
+#                   ]
+#                }
+#             ]
+#          }
+#       ]
+#    }
+#
+# Note: This example has been shortened as the real response is too long.
+#
 ##
 { 'command': 'query-pci', 'returns': ['PciInfo'] }
 
@@ -1573,6 +2171,11 @@
 # unexpected.
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "quit" }
+# <- { "return": {} }
 ##
 { 'command': 'quit' }
 
@@ -1587,6 +2190,12 @@
 #         state.  In "inmigrate" state, it will ensure that the guest
 #         remains paused once migration finishes, as if the -S option was
 #         passed on the command line.
+#
+# Example:
+#
+# -> { "execute": "stop" }
+# <- { "return": {} }
+#
 ##
 { 'command': 'stop' }
 
@@ -1596,6 +2205,12 @@
 # Performs a hard reset of a guest.
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "system_reset" }
+# <- { "return": {} }
+#
 ##
 { 'command': 'system_reset' }
 
@@ -1610,6 +2225,11 @@
 #        returning does not indicate that a guest has accepted the request or
 #        that it has shut down.  Many guests will respond to this command by
 #        prompting the user in some way.
+# Example:
+#
+# -> { "execute": "system_powerdown" }
+# <- { "return": {} }
+#
 ##
 { 'command': 'system_powerdown' }
 
@@ -1634,6 +2254,12 @@
 # Returns: Nothing on success
 #
 # Since: 1.5
+#
+# Example:
+#
+# -> { "execute": "cpu-add", "arguments": { "id": 2 } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'cpu-add', 'data': {'id': 'int'} }
 
@@ -1656,6 +2282,15 @@
 # Since: 0.14.0
 #
 # Notes: Errors were not reliably returned until 1.1
+#
+# Example:
+#
+# -> { "execute": "memsave",
+#      "arguments": { "val": 10,
+#                     "size": 100,
+#                     "filename": "/tmp/virtual-mem-dump" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'memsave',
   'data': {'val': 'int', 'size': 'int', 'filename': 'str', '*cpu-index': 'int'} }
@@ -1676,6 +2311,15 @@
 # Since: 0.14.0
 #
 # Notes: Errors were not reliably returned until 1.1
+#
+# Example:
+#
+# -> { "execute": "pmemsave",
+#      "arguments": { "val": 10,
+#                     "size": 100,
+#                     "filename": "/tmp/physical-mem-dump" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'pmemsave',
   'data': {'val': 'int', 'size': 'int', 'filename': 'str'} }
@@ -1696,6 +2340,12 @@
 #         this case, the effect of the command is to make sure the guest
 #         starts once migration finishes, removing the effect of the -S
 #         command line option if it was passed.
+#
+# Example:
+#
+# -> { "execute": "cont" }
+# <- { "return": {} }
+#
 ##
 { 'command': 'cont' }
 
@@ -1707,6 +2357,12 @@
 # Since:  1.1
 #
 # Returns:  nothing.
+#
+# Example:
+#
+# -> { "execute": "system_wakeup" }
+# <- { "return": {} }
+#
 ##
 { 'command': 'system_wakeup' }
 
@@ -1714,12 +2370,19 @@
 # @inject-nmi:
 #
 # Injects a Non-Maskable Interrupt into the default CPU (x86/s390) or all CPUs (ppc64).
+# The command fails when the guest doesn't support injecting.
 #
 # Returns:  If successful, nothing
 #
 # Since:  0.14.0
 #
 # Note: prior to 2.1, this command was only supported for x86 and s390 VMs
+#
+# Example:
+#
+# -> { "execute": "inject-nmi" }
+# <- { "return": {} }
+#
 ##
 { 'command': 'inject-nmi' }
 
@@ -1740,6 +2403,13 @@
 # Notes: Not all network adapters support setting link status.  This command
 #        will succeed even if the network adapter does not support link status
 #        notification.
+#
+# Example:
+#
+# -> { "execute": "set_link",
+#      "arguments": { "name": "e1000.0", "up": false } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'set_link', 'data': {'name': 'str', 'up': 'bool'} }
 
@@ -1760,6 +2430,12 @@
 #        size independent of this command.
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "balloon", "arguments": { "value": 536870912 } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'balloon', 'data': {'value': 'int'} }
 
@@ -1845,6 +2521,28 @@
 # operation fails, then the entire set of actions will be abandoned and the
 # appropriate error returned.
 #
+# For external snapshots, the dictionary contains the device, the file to use for
+# the new snapshot, and the format.  The default format, if not specified, is
+# qcow2.
+#
+# Each new snapshot defaults to being created by QEMU (wiping any
+# contents if the file already exists), but it is also possible to reuse
+# an externally-created file.  In the latter case, you should ensure that
+# the new image file has the same contents as the current one; QEMU cannot
+# perform any meaningful check.  Typically this is achieved by using the
+# current image file as the backing file for the new image.
+#
+# On failure, the original disks pre-snapshot attempt will be used.
+#
+# For internal snapshots, the dictionary contains the device and the snapshot's
+# name.  If an internal snapshot matching name already exists, the request will
+# be rejected.  Only some image formats support it, for example, qcow2, rbd,
+# and sheepdog.
+#
+# On failure, qemu will try delete the newly created internal snapshot in the
+# transaction.  When an I/O error occurs during deletion, the user needs to fix
+# it later with qemu-img or other command.
+#
 # @actions: List of @TransactionAction;
 #           information needed for the respective operations.
 #
@@ -1853,6 +2551,7 @@
 #              for additional detail.
 #
 # Returns: nothing on success
+#
 #          Errors depend on the operations of the transaction
 #
 # Note: The transaction aborts on the first failure.  Therefore, there will be
@@ -1860,6 +2559,28 @@
 # subsequent actions will not have been attempted.
 #
 # Since: 1.1
+#
+# Example:
+#
+# -> { "execute": "transaction",
+#      "arguments": { "actions": [
+#          { "type": "blockdev-snapshot-sync", "data" : { "device": "ide-hd0",
+#                                      "snapshot-file": "/some/place/my-image",
+#                                      "format": "qcow2" } },
+#          { "type": "blockdev-snapshot-sync", "data" : { "node-name": "myfile",
+#                                      "snapshot-file": "/some/place/my-image2",
+#                                      "snapshot-node-name": "node3432",
+#                                      "mode": "existing",
+#                                      "format": "qcow2" } },
+#          { "type": "blockdev-snapshot-sync", "data" : { "device": "ide-hd1",
+#                                      "snapshot-file": "/some/place/my-image2",
+#                                      "mode": "existing",
+#                                      "format": "qcow2" } },
+#          { "type": "blockdev-snapshot-internal-sync", "data" : {
+#                                      "device": "ide-hd2",
+#                                      "name": "snapshot0" } } ] } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'transaction',
   'data': { 'actions': [ 'TransactionAction' ],
@@ -1881,15 +2602,26 @@
 # Since: 0.14.0
 #
 # Notes: This command only exists as a stop-gap.  Its use is highly
-#        discouraged.  The semantics of this command are not guaranteed.
+#        discouraged.  The semantics of this command are not
+#        guaranteed: this means that command names, arguments and
+#        responses can change or be removed at ANY time.  Applications
+#        that rely on long term stability guarantees should NOT
+#        use this command.
 #
 #        Known limitations:
 #
 #        o This command is stateless, this means that commands that depend
 #          on state information (such as getfd) might not work
 #
-#       o Commands that prompt the user for data (eg. 'cont' when the block
-#         device is encrypted) don't currently work
+#        o Commands that prompt the user for data (eg. 'cont' when the block
+#          device is encrypted) don't currently work
+#
+# Example:
+#
+# -> { "execute": "human-monitor-command",
+#      "arguments": { "command-line": "info kvm" } }
+# <- { "return": "kvm support: enabled\r\n" }
+#
 ##
 { 'command': 'human-monitor-command',
   'data': {'command-line': 'str', '*cpu-index': 'int'},
@@ -1905,6 +2637,12 @@
 # Notes: This command succeeds even if there is no migration process running.
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "migrate_cancel" }
+# <- { "return": {} }
+#
 ##
 { 'command': 'migrate_cancel' }
 
@@ -1920,6 +2658,12 @@
 # Notes: This command is deprecated in favor of 'migrate-set-parameters'
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "migrate_set_downtime", "arguments": { "value": 0.1 } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'migrate_set_downtime', 'data': {'value': 'number'} }
 
@@ -1928,20 +2672,26 @@
 #
 # Set maximum speed for migration.
 #
-# @value: maximum speed in bytes.
+# @value: maximum speed in bytes per second.
 #
 # Returns: nothing on success
 #
 # Notes: This command is deprecated in favor of 'migrate-set-parameters'
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "migrate_set_speed", "arguments": { "value": 1024 } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'migrate_set_speed', 'data': {'value': 'int'} }
 
 ##
 # @migrate-set-cache-size:
 #
-# Set XBZRLE cache size
+# Set cache size to be used by XBZRLE migration
 #
 # @value: cache size in bytes
 #
@@ -1951,17 +2701,30 @@
 # Returns: nothing on success
 #
 # Since: 1.2
+#
+# Example:
+#
+# -> { "execute": "migrate-set-cache-size",
+#      "arguments": { "value": 536870912 } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'migrate-set-cache-size', 'data': {'value': 'int'} }
 
 ##
 # @query-migrate-cache-size:
 #
-# query XBZRLE cache size
+# Query migration XBZRLE cache size
 #
 # Returns: XBZRLE cache size in bytes
 #
 # Since: 1.2
+#
+# Example:
+#
+# -> { "execute": "query-migrate-cache-size" }
+# <- { "return": 67108864 }
+#
 ##
 { 'command': 'query-migrate-cache-size', 'returns': 'int' }
 
@@ -2078,6 +2841,13 @@
 #          If Spice is not enabled, DeviceNotFound
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "set_password", "arguments": { "protocol": "vnc",
+#                                                "password": "secret" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'set_password',
   'data': {'protocol': 'str', 'password': 'str', '*connected': 'str'} }
@@ -2104,6 +2874,13 @@
 #        coordinate server time with client time.  It is not recommended to
 #        use the absolute time version of the @time parameter unless you're
 #        sure you are on the same machine as the QEMU instance.
+#
+# Example:
+#
+# -> { "execute": "expire_password", "arguments": { "protocol": "vnc",
+#                                                   "time": "+60" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'expire_password', 'data': {'protocol': 'str', 'time': 'str'} }
 
@@ -2154,6 +2931,23 @@
 #         change-vnc-password.
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# 1. Change a removable medium
+#
+# -> { "execute": "change",
+#      "arguments": { "device": "ide1-cd0",
+#                     "target": "/srv/images/Fedora-12-x86_64-DVD.iso" } }
+# <- { "return": {} }
+#
+# 2. Change VNC password
+#
+# -> { "execute": "change",
+#      "arguments": { "device": "vnc", "target": "password",
+#                     "arg": "foobar1" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'change',
   'data': {'device': 'str', 'target': 'str', '*arg': 'str'} }
@@ -2236,6 +3030,22 @@
 # Returns: nothing on success
 #
 # Since: 0.14.0
+#
+# Notes:
+#
+# 1. The 'query-migrate' command should be used to check migration's progress
+#    and final result (this information is provided by the 'status' member)
+#
+# 2. All boolean arguments default to false
+#
+# 3. The user Monitor's "detach" argument is invalid in QMP and should not
+#    be used
+#
+# Example:
+#
+# -> { "execute": "migrate", "arguments": { "uri": "tcp:0:4446" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'migrate',
   'data': {'uri': 'str', '*blk': 'bool', '*inc': 'bool', '*detach': 'bool' } }
@@ -2252,9 +3062,24 @@
 # Returns: nothing on success
 #
 # Since: 2.3
-# Note: It's a bad idea to use a string for the uri, but it needs to stay
-# compatible with -incoming and the format of the uri is already exposed
-# above libvirt
+#
+# Notes:
+#
+# 1. It's a bad idea to use a string for the uri, but it needs to stay
+#    compatible with -incoming and the format of the uri is already exposed
+#    above libvirt.
+#
+# 2. QEMU must be started with -incoming defer to allow migrate-incoming to
+#    be used.
+#
+# 3. The uri format is the same as for -incoming
+#
+# Example:
+#
+# -> { "execute": "migrate-incoming",
+#      "arguments": { "uri": "tcp::4446" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'migrate-incoming', 'data': {'uri': 'str' } }
 
@@ -2271,6 +3096,13 @@
 # Returns: Nothing on success
 #
 # Since: 1.1
+#
+# Example:
+#
+# -> { "execute": "xen-save-devices-state",
+#      "arguments": { "filename": "/tmp/save" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'xen-save-devices-state', 'data': {'filename': 'str'} }
 
@@ -2284,12 +3116,21 @@
 # Returns: nothing
 #
 # Since: 1.3
+#
+# Example:
+#
+# -> { "execute": "xen-set-global-dirty-log",
+#      "arguments": { "enable": true } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'xen-set-global-dirty-log', 'data': { 'enable': 'bool' } }
 
 ##
 # @device_add:
 #
+# Add a device.
+#
 # @driver: the name of the new device's driver
 #
 # @bus: #optional the device's parent bus (device tree path)
@@ -2298,8 +3139,6 @@
 #
 # Additional arguments depend on the type.
 #
-# Add a device.
-#
 # Notes:
 # 1. For detailed information about this command, please refer to the
 #    'docs/qdev-device-use.txt' file.
@@ -2332,7 +3171,7 @@
 #
 # Remove a device from a guest
 #
-# @id: the name or QOM path of the device
+# @id: the device's ID or QOM path
 #
 # Returns: Nothing on success
 #          If @id is not a valid device, DeviceNotFound
@@ -2345,6 +3184,17 @@
 #        for all devices.
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "device_del",
+#      "arguments": { "id": "net1" } }
+# <- { "return": {} }
+#
+# -> { "execute": "device_del",
+#      "arguments": { "id": "/machine/peripheral-anon/device[0]" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'device_del', 'data': {'id': 'str'} }
 
@@ -2411,9 +3261,18 @@
 #          @length is not allowed to be specified with non-elf @format at the
 #          same time (since 2.0)
 #
+# Note: All boolean arguments default to false
+#
 # Returns: nothing on success
 #
 # Since: 1.2
+#
+# Example:
+#
+# -> { "execute": "dump-guest-memory",
+#      "arguments": { "protocol": "fd:dump" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'dump-guest-memory',
   'data': { 'paging': 'bool', 'protocol': 'str', '*detach': 'bool',
@@ -2464,6 +3323,13 @@
 # Returns: A @DumpStatus object showing the dump status.
 #
 # Since: 2.6
+#
+# Example:
+#
+# -> { "execute": "query-dump" }
+# <- { "return": { "status": "active", "completed": 1024000,
+#                  "total": 2048000 } }
+#
 ##
 { 'command': 'query-dump', 'returns': 'DumpQueryResult' }
 
@@ -2487,6 +3353,13 @@
 #           dump-guest-memory
 #
 # Since: 2.0
+#
+# Example:
+#
+# -> { "execute": "query-dump-guest-memory-capability" }
+# <- { "return": { "formats":
+#                  ["elf", "kdump-zlib", "kdump-lzo", "kdump-snappy"] }
+#
 ##
 { 'command': 'query-dump-guest-memory-capability',
   'returns': 'DumpGuestMemoryCapability' }
@@ -2501,6 +3374,13 @@
 # This command is only supported on s390 architecture.
 #
 # Since: 2.5
+#
+# Example:
+#
+# -> { "execute": "dump-skeys",
+#      "arguments": { "filename": "/tmp/skeys" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'dump-skeys',
   'data': { 'filename': 'str' } }
@@ -2526,6 +3406,14 @@
 #
 # Returns: Nothing on success
 #          If @type is not a valid network backend, DeviceNotFound
+#
+# Example:
+#
+# -> { "execute": "netdev_add",
+#      "arguments": { "type": "user", "id": "netdev1",
+#                     "dnssearch": "example.org" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'netdev_add',
   'data': {'type': 'str', 'id': 'str'},
@@ -2542,6 +3430,12 @@
 #          If @id is not a valid network backend, DeviceNotFound
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "netdev_del", "arguments": { "id": "netdev1" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'netdev_del', 'data': {'id': 'str'} }
 
@@ -2560,6 +3454,14 @@
 #          Error if @qom-type is not a valid class name
 #
 # Since: 2.0
+#
+# Example:
+#
+# -> { "execute": "object-add",
+#      "arguments": { "qom-type": "rng-random", "id": "rng1",
+#                     "props": { "filename": "/dev/hwrng" } } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'object-add',
   'data': {'qom-type': 'str', 'id': 'str', '*props': 'any'} }
@@ -2575,6 +3477,12 @@
 #          Error if @id is not a valid id for a QOM object
 #
 # Since: 2.0
+#
+# Example:
+#
+# -> { "execute": "object-del", "arguments": { "id": "rng1" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'object-del', 'data': {'id': 'str'} }
 
@@ -3149,8 +4057,15 @@
 # Notes: If @fdname already exists, the file descriptor assigned to
 #        it will be closed and replaced by the received file
 #        descriptor.
+#
 #        The 'closefd' command can be used to explicitly close the
 #        file descriptor when it is no longer needed.
+#
+# Example:
+#
+# -> { "execute": "getfd", "arguments": { "fdname": "fd1" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'getfd', 'data': {'fdname': 'str'} }
 
@@ -3164,6 +4079,12 @@
 # Returns: Nothing on success
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "closefd", "arguments": { "fdname": "fd1" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'closefd', 'data': {'fdname': 'str'} }
 
@@ -3513,7 +4434,9 @@
 # @opaque: #optional A free-form string that can be used to describe the fd.
 #
 # Returns: @AddfdInfo on success
+#
 #          If file descriptor was not received, FdNotSupplied
+#
 #          If @fdset-id is a negative value, InvalidParameterValue
 #
 # Notes: The list of fd sets is shared by all monitor connections.
@@ -3521,6 +4444,12 @@
 #        If @fdset-id is not specified, a new fd set will be created.
 #
 # Since: 1.2.0
+#
+# Example:
+#
+# -> { "execute": "add-fd", "arguments": { "fdset-id": 1 } }
+# <- { "return": { "fdset-id": 1, "fd": 3 } }
+#
 ##
 { 'command': 'add-fd', 'data': {'*fdset-id': 'int', '*opaque': 'str'},
   'returns': 'AddfdInfo' }
@@ -3543,6 +4472,12 @@
 #
 #        If @fd is not specified, all file descriptors in @fdset-id
 #        will be removed.
+#
+# Example:
+#
+# -> { "execute": "remove-fd", "arguments": { "fdset-id": 1, "fd": 3 } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'remove-fd', 'data': {'fdset-id': 'int', '*fd': 'int'} }
 
@@ -3585,6 +4520,37 @@
 #
 # Note: The list of fd sets is shared by all monitor connections.
 #
+# Example:
+#
+# -> { "execute": "query-fdsets" }
+# <- { "return": [
+#        {
+#          "fds": [
+#            {
+#              "fd": 30,
+#              "opaque": "rdonly:/path/to/file"
+#            },
+#            {
+#              "fd": 24,
+#              "opaque": "rdwr:/path/to/file"
+#            }
+#          ],
+#          "fdset-id": 1
+#        },
+#        {
+#          "fds": [
+#            {
+#              "fd": 28
+#            },
+#            {
+#              "fd": 29
+#            }
+#          ],
+#          "fdset-id": 0
+#        }
+#      ]
+#    }
+#
 ##
 { 'command': 'query-fdsets', 'returns': ['FdsetInfo'] }
 
@@ -3673,6 +4639,14 @@
 #
 # Since: 1.3.0
 #
+# Example:
+#
+# -> { "execute": "send-key",
+#      "arguments": { "keys": [ { "type": "qcode", "data": "ctrl" },
+#                               { "type": "qcode", "data": "alt" },
+#                               { "type": "qcode", "data": "delete" } ] } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'send-key',
   'data': { 'keys': ['KeyValue'], '*hold-time': 'int' } }
@@ -3687,6 +4661,13 @@
 # Returns: Nothing on success
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "screendump",
+#      "arguments": { "filename": "/tmp/image" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'screendump', 'data': {'filename': 'str'} }
 
@@ -3911,6 +4892,25 @@
 # Returns: ChardevReturn.
 #
 # Since: 1.4
+#
+# Example:
+#
+# -> { "execute" : "chardev-add",
+#      "arguments" : { "id" : "foo",
+#                      "backend" : { "type" : "null", "data" : {} } } }
+# <- { "return": {} }
+#
+# -> { "execute" : "chardev-add",
+#      "arguments" : { "id" : "bar",
+#                      "backend" : { "type" : "file",
+#                                    "data" : { "out" : "/tmp/bar.log" } } } }
+# <- { "return": {} }
+#
+# -> { "execute" : "chardev-add",
+#      "arguments" : { "id" : "baz",
+#                      "backend" : { "type" : "pty", "data" : {} } } }
+# <- { "return": { "pty" : "/dev/pty/42" } }
+#
 ##
 { 'command': 'chardev-add', 'data': {'id'      : 'str',
                                      'backend' : 'ChardevBackend' },
@@ -3926,6 +4926,12 @@
 # Returns: Nothing on success
 #
 # Since: 1.4
+#
+# Example:
+#
+# -> { "execute": "chardev-remove", "arguments": { "id" : "foo" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'chardev-remove', 'data': {'id': 'str'} }
 
@@ -3948,6 +4954,12 @@
 # Returns: a list of TpmModel
 #
 # Since: 1.5
+#
+# Example:
+#
+# -> { "execute": "query-tpm-models" }
+# <- { "return": [ "tpm-tis" ] }
+#
 ##
 { 'command': 'query-tpm-models', 'returns': ['TpmModel'] }
 
@@ -3970,6 +4982,12 @@
 # Returns: a list of TpmType
 #
 # Since: 1.5
+#
+# Example:
+#
+# -> { "execute": "query-tpm-types" }
+# <- { "return": [ "passthrough" ] }
+#
 ##
 { 'command': 'query-tpm-types', 'returns': ['TpmType'] }
 
@@ -4026,6 +5044,25 @@
 # Returns: @TPMInfo on success
 #
 # Since: 1.5
+#
+# Example:
+#
+# -> { "execute": "query-tpm" }
+# <- { "return":
+#      [
+#        { "model": "tpm-tis",
+#          "options":
+#            { "type": "passthrough",
+#              "data":
+#                { "cancel-path": "/sys/class/misc/tpm0/device/cancel",
+#                  "path": "/dev/tpm0"
+#                }
+#            },
+#          "id": "tpm0"
+#        }
+#      ]
+#    }
+#
 ##
 { 'command': 'query-tpm', 'returns': ['TPMInfo'] }
 
@@ -4152,6 +5189,28 @@
 #          @option).  Returns an error if the given @option doesn't exist.
 #
 # Since: 1.5
+#
+# Example:
+#
+# -> { "execute": "query-command-line-options",
+#      "arguments": { "option": "option-rom" } }
+# <- { "return": [
+#         {
+#             "parameters": [
+#                 {
+#                     "name": "romfile",
+#                     "type": "string"
+#                 },
+#                 {
+#                     "name": "bootindex",
+#                     "type": "number"
+#                 }
+#             ],
+#             "option": "option-rom"
+#         }
+#      ]
+#    }
+#
 ##
 {'command': 'query-command-line-options', 'data': { '*option': 'str' },
  'returns': ['CommandLineOptionInfo'] }
@@ -4273,6 +5332,36 @@
 #          isn't a NIC.
 #
 # Since: 1.6
+#
+# Example:
+#
+# -> { "execute": "query-rx-filter", "arguments": { "name": "vnet0" } }
+# <- { "return": [
+#         {
+#             "promiscuous": true,
+#             "name": "vnet0",
+#             "main-mac": "52:54:00:12:34:56",
+#             "unicast": "normal",
+#             "vlan": "normal",
+#             "vlan-table": [
+#                 4,
+#                 0
+#             ],
+#             "unicast-table": [
+#             ],
+#             "multicast": "normal",
+#             "multicast-overflow": false,
+#             "unicast-overflow": false,
+#             "multicast-table": [
+#                 "01:00:5e:00:00:01",
+#                 "33:33:00:00:00:01",
+#                 "33:33:ff:12:34:56"
+#             ],
+#             "broadcast-allowed": false
+#         }
+#       ]
+#    }
+#
 ##
 { 'command': 'query-rx-filter', 'data': { '*name': 'str' },
   'returns': ['RxFilterInfo'] }
@@ -4371,9 +5460,9 @@
 #
 # Returns: Nothing on success.
 #
-# The @display and @head parameters can be used to send the input
-# event to specific input devices in case (a) multiple input devices
-# of the same kind are added to the virtual machine and (b) you have
+# The @device and @head parameters can be used to send the input event
+# to specific input devices in case (a) multiple input devices of the
+# same kind are added to the virtual machine and (b) you have
 # configured input routing (see docs/multiseat.txt) for those input
 # devices.  The parameters work exactly like the device and head
 # properties of input devices.  If @device is missing, only devices
@@ -4383,6 +5472,48 @@
 # precedence.
 #
 # Since: 2.6
+#
+# Note: The consoles are visible in the qom tree, under
+# /backend/console[$index]. They have a device link and head property,
+# so it is possible to map which console belongs to which device and
+# display.
+#
+# Example:
+#
+# 1. Press left mouse button.
+#
+# -> { "execute": "input-send-event",
+#     "arguments": { "device": "video0",
+#                    "events": [ { "type": "btn",
+#                    "data" : { "down": true, "button": "left" } } ] } }
+# <- { "return": {} }
+#
+# -> { "execute": "input-send-event",
+#     "arguments": { "device": "video0",
+#                    "events": [ { "type": "btn",
+#                    "data" : { "down": false, "button": "left" } } ] } }
+# <- { "return": {} }
+#
+# 2. Press ctrl-alt-del.
+#
+# -> { "execute": "input-send-event",
+#      "arguments": { "events": [
+#         { "type": "key", "data" : { "down": true,
+#           "key": {"type": "qcode", "data": "ctrl" } } },
+#         { "type": "key", "data" : { "down": true,
+#           "key": {"type": "qcode", "data": "alt" } } },
+#         { "type": "key", "data" : { "down": true,
+#           "key": {"type": "qcode", "data": "delete" } } } ] } }
+# <- { "return": {} }
+#
+# 3. Move mouse pointer to absolute coordinates (20000, 400).
+#
+# -> { "execute": "input-send-event" ,
+#   "arguments": { "events": [
+#                { "type": "abs", "data" : { "axis": "x", "value" : 20000 } },
+#                { "type": "abs", "data" : { "axis": "y", "value" : 400 } } ] } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'input-send-event',
   'data': { '*device': 'str',
@@ -4482,6 +5613,30 @@
 # Returns: a list of @Memdev.
 #
 # Since: 2.1
+#
+# Example:
+#
+# -> { "execute": "query-memdev" }
+# <- { "return": [
+#        {
+#          "size": 536870912,
+#          "merge": false,
+#          "dump": true,
+#          "prealloc": false,
+#          "host-nodes": [0, 1],
+#          "policy": "bind"
+#        },
+#        {
+#          "size": 536870912,
+#          "merge": false,
+#          "dump": true,
+#          "prealloc": true,
+#          "host-nodes": [2, 3],
+#          "policy": "preferred"
+#        }
+#      ]
+#    }
+#
 ##
 { 'command': 'query-memdev', 'returns': ['Memdev'] }
 
@@ -4535,6 +5690,22 @@
 # Lists available memory devices and their state
 #
 # Since: 2.1
+#
+# Example:
+#
+# -> { "execute": "query-memory-devices" }
+# <- { "return": [ { "data":
+#                       { "addr": 5368709120,
+#                         "hotpluggable": true,
+#                         "hotplugged": true,
+#                         "id": "d1",
+#                         "memdev": "/objects/memX",
+#                         "node": 0,
+#                         "size": 1073741824,
+#                         "slot": 0},
+#                    "type": "dimm"
+#                  } ] }
+#
 ##
 { 'command': 'query-memory-devices', 'returns': ['MemoryDeviceInfo'] }
 
@@ -4575,10 +5746,20 @@
 ##
 # @query-acpi-ospm-status:
 #
-# Lists ACPI OSPM status of ACPI device objects,
-# which might be reported via _OST method
+# Return a list of ACPIOSTInfo for devices that support status
+# reporting via ACPI _OST method.
 #
 # Since: 2.1
+#
+# Example:
+#
+# -> { "execute": "query-acpi-ospm-status" }
+# <- { "return": [ { "device": "d1", "slot": "0", "slot-type": "DIMM", "source": 1, "status": 0},
+#                  { "slot": "1", "slot-type": "DIMM", "source": 0, "status": 0},
+#                  { "slot": "2", "slot-type": "DIMM", "source": 0, "status": 0},
+#                  { "slot": "3", "slot-type": "DIMM", "source": 0, "status": 0}
+#    ]}
+#
 ##
 { 'command': 'query-acpi-ospm-status', 'returns': ['ACPIOSTInfo'] }
 
@@ -4645,6 +5826,12 @@
 # command.
 #
 # Since: 2.1
+#
+# Example:
+#
+# -> { "execute": "rtc-reset-reinjection" }
+# <- { "return": {} }
+#
 ##
 { 'command': 'rtc-reset-reinjection' }
 
@@ -4680,6 +5867,13 @@
 # format.
 #
 # Since: 2.7
+#
+# Example:
+#
+# -> { "execute": "xen-load-devices-state",
+#      "arguments": { "filename": "/tmp/resume" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'xen-load-devices-state', 'data': {'filename': 'str'} }
 
@@ -4716,6 +5910,13 @@
 # Returns: a list of GICCapability objects.
 #
 # Since: 2.6
+#
+# Example:
+#
+# -> { "execute": "query-gic-capabilities" }
+# <- { "return": [{ "version": 2, "emulated": true, "kernel": false },
+#                 { "version": 3, "emulated": false, "kernel": true } ] }
+#
 ##
 { 'command': 'query-gic-capabilities', 'returns': ['GICCapability'] }
 
@@ -4772,5 +5973,33 @@
 # Returns: a list of HotpluggableCPU objects.
 #
 # Since: 2.7
+#
+# Example:
+#
+# For pseries machine type started with -smp 2,cores=2,maxcpus=4 -cpu POWER8:
+#
+# -> { "execute": "query-hotpluggable-cpus" }
+# <- {"return": [
+#      { "props": { "core": 8 }, "type": "POWER8-spapr-cpu-core",
+#        "vcpus-count": 1 },
+#      { "props": { "core": 0 }, "type": "POWER8-spapr-cpu-core",
+#        "vcpus-count": 1, "qom-path": "/machine/unattached/device[0]"}
+#    ]}'
+#
+# For pc machine type started with -smp 1,maxcpus=2:
+#
+# -> { "execute": "query-hotpluggable-cpus" }
+# <- {"return": [
+#      {
+#         "type": "qemu64-x86_64-cpu", "vcpus-count": 1,
+#         "props": {"core-id": 0, "socket-id": 1, "thread-id": 0}
+#      },
+#      {
+#         "qom-path": "/machine/unattached/device[0]",
+#         "type": "qemu64-x86_64-cpu", "vcpus-count": 1,
+#         "props": {"core-id": 0, "socket-id": 0, "thread-id": 0}
+#      }
+#    ]}
+#
 ##
 { 'command': 'query-hotpluggable-cpus', 'returns': ['HotpluggableCPU'] }
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 91febed..e4db63e 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -469,6 +469,87 @@
 # Returns: a list of @BlockInfo describing each virtual block device
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-block" }
+# <- {
+#       "return":[
+#          {
+#             "io-status": "ok",
+#             "device":"ide0-hd0",
+#             "locked":false,
+#             "removable":false,
+#             "inserted":{
+#                "ro":false,
+#                "drv":"qcow2",
+#                "encrypted":false,
+#                "file":"disks/test.qcow2",
+#                "backing_file_depth":1,
+#                "bps":1000000,
+#                "bps_rd":0,
+#                "bps_wr":0,
+#                "iops":1000000,
+#                "iops_rd":0,
+#                "iops_wr":0,
+#                "bps_max": 8000000,
+#                "bps_rd_max": 0,
+#                "bps_wr_max": 0,
+#                "iops_max": 0,
+#                "iops_rd_max": 0,
+#                "iops_wr_max": 0,
+#                "iops_size": 0,
+#                "detect_zeroes": "on",
+#                "write_threshold": 0,
+#                "image":{
+#                   "filename":"disks/test.qcow2",
+#                   "format":"qcow2",
+#                   "virtual-size":2048000,
+#                   "backing_file":"base.qcow2",
+#                   "full-backing-filename":"disks/base.qcow2",
+#                   "backing-filename-format":"qcow2",
+#                   "snapshots":[
+#                      {
+#                         "id": "1",
+#                         "name": "snapshot1",
+#                         "vm-state-size": 0,
+#                         "date-sec": 10000200,
+#                         "date-nsec": 12,
+#                         "vm-clock-sec": 206,
+#                         "vm-clock-nsec": 30
+#                      }
+#                   ],
+#                   "backing-image":{
+#                       "filename":"disks/base.qcow2",
+#                       "format":"qcow2",
+#                       "virtual-size":2048000
+#                   }
+#                }
+#             },
+#             "type":"unknown"
+#          },
+#          {
+#             "io-status": "ok",
+#             "device":"ide1-cd0",
+#             "locked":false,
+#             "removable":true,
+#             "type":"unknown"
+#          },
+#          {
+#             "device":"floppy0",
+#             "locked":false,
+#             "removable":true,
+#             "type":"unknown"
+#          },
+#          {
+#             "device":"sd0",
+#             "locked":false,
+#             "removable":true,
+#             "type":"unknown"
+#          }
+#       ]
+#    }
+#
 ##
 { 'command': 'query-block', 'returns': ['BlockInfo'] }
 
@@ -616,6 +697,9 @@
 # @stats:  A @BlockDeviceStats for the device.
 #
 # @parent: #optional This describes the file block device if it has one.
+#          Contains recursively the statistics of the underlying
+#          protocol (e.g. the host file for a qcow2 image). If there is
+#          no underlying protocol, this field is omitted
 #
 # @backing: #optional This describes the backing block device if it has one.
 #           (Since 2.0)
@@ -643,6 +727,106 @@
 # Returns: A list of @BlockStats for each virtual block devices.
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-blockstats" }
+# <- {
+#       "return":[
+#          {
+#             "device":"ide0-hd0",
+#             "parent":{
+#                "stats":{
+#                   "wr_highest_offset":3686448128,
+#                   "wr_bytes":9786368,
+#                   "wr_operations":751,
+#                   "rd_bytes":122567168,
+#                   "rd_operations":36772
+#                   "wr_total_times_ns":313253456
+#                   "rd_total_times_ns":3465673657
+#                   "flush_total_times_ns":49653
+#                   "flush_operations":61,
+#                   "rd_merged":0,
+#                   "wr_merged":0,
+#                   "idle_time_ns":2953431879,
+#                   "account_invalid":true,
+#                   "account_failed":false
+#                }
+#             },
+#             "stats":{
+#                "wr_highest_offset":2821110784,
+#                "wr_bytes":9786368,
+#                "wr_operations":692,
+#                "rd_bytes":122739200,
+#                "rd_operations":36604
+#                "flush_operations":51,
+#                "wr_total_times_ns":313253456
+#                "rd_total_times_ns":3465673657
+#                "flush_total_times_ns":49653,
+#                "rd_merged":0,
+#                "wr_merged":0,
+#                "idle_time_ns":2953431879,
+#                "account_invalid":true,
+#                "account_failed":false
+#             }
+#          },
+#          {
+#             "device":"ide1-cd0",
+#             "stats":{
+#                "wr_highest_offset":0,
+#                "wr_bytes":0,
+#                "wr_operations":0,
+#                "rd_bytes":0,
+#                "rd_operations":0
+#                "flush_operations":0,
+#                "wr_total_times_ns":0
+#                "rd_total_times_ns":0
+#                "flush_total_times_ns":0,
+#                "rd_merged":0,
+#                "wr_merged":0,
+#                "account_invalid":false,
+#                "account_failed":false
+#             }
+#          },
+#          {
+#             "device":"floppy0",
+#             "stats":{
+#                "wr_highest_offset":0,
+#                "wr_bytes":0,
+#                "wr_operations":0,
+#                "rd_bytes":0,
+#                "rd_operations":0
+#                "flush_operations":0,
+#                "wr_total_times_ns":0
+#                "rd_total_times_ns":0
+#                "flush_total_times_ns":0,
+#                "rd_merged":0,
+#                "wr_merged":0,
+#                "account_invalid":false,
+#                "account_failed":false
+#             }
+#          },
+#          {
+#             "device":"sd0",
+#             "stats":{
+#                "wr_highest_offset":0,
+#                "wr_bytes":0,
+#                "wr_operations":0,
+#                "rd_bytes":0,
+#                "rd_operations":0
+#                "flush_operations":0,
+#                "wr_total_times_ns":0
+#                "rd_total_times_ns":0
+#                "flush_total_times_ns":0,
+#                "rd_merged":0,
+#                "wr_merged":0,
+#                "account_invalid":false,
+#                "account_failed":false
+#             }
+#          }
+#       ]
+#    }
+#
 ##
 { 'command': 'query-blockstats',
   'data': { '*query-nodes': 'bool' },
@@ -787,6 +971,13 @@
 #         occur if an invalid password is specified.
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "block_passwd", "arguments": { "device": "ide0-hd0",
+#                                                "password": "12345" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'block_passwd', 'data': {'*device': 'str',
                                       '*node-name': 'str', 'password': 'str'} }
@@ -808,6 +999,13 @@
 #          If @device is not a valid block device, DeviceNotFound
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "block_resize",
+#      "arguments": { "device": "scratch", "size": 1073741824 } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'block_resize', 'data': { '*device': 'str',
                                        '*node-name': 'str',
@@ -839,7 +1037,9 @@
 #
 # @node-name: #optional graph node name to generate the snapshot from (Since 2.0)
 #
-# @snapshot-file: the target of the new image. A new file will be created.
+# @snapshot-file: the target of the new image. If the file exists, or
+# if it is a device, the snapshot will be created in the existing
+# file/device. Otherwise, a new file will be created.
 #
 # @snapshot-node-name: #optional the graph node name of the new image (Since 2.0)
 #
@@ -973,6 +1173,16 @@
 #          If @device is not a valid block device, DeviceNotFound
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "blockdev-snapshot-sync",
+#      "arguments": { "device": "ide-hd0",
+#                     "snapshot-file":
+#                     "/some/place/my-image",
+#                     "format": "qcow2" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'blockdev-snapshot-sync',
   'data': 'BlockdevSnapshotSync' }
@@ -983,9 +1193,31 @@
 #
 # Generates a snapshot of a block device.
 #
+# Create a snapshot, by installing 'node' as the backing image of
+# 'overlay'. Additionally, if 'node' is associated with a block
+# device, the block device changes to using 'overlay' as its new active
+# image.
+#
 # For the arguments, see the documentation of BlockdevSnapshot.
 #
 # Since: 2.5
+#
+# Example:
+#
+# -> { "execute": "blockdev-add",
+#      "arguments": { "options": { "driver": "qcow2",
+#                                  "node-name": "node1534",
+#                                  "file": { "driver": "file",
+#                                            "filename": "hd1.qcow2" },
+#                                  "backing": "" } } }
+#
+# <- { "return": {} }
+#
+# -> { "execute": "blockdev-snapshot",
+#      "arguments": { "node": "ide-hd0",
+#                     "overlay": "node1534" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'blockdev-snapshot',
   'data': 'BlockdevSnapshot' }
@@ -1001,7 +1233,9 @@
 # updated.
 #
 # @image-node-name: The name of the block driver state node of the
-#                   image to modify.
+#                   image to modify. The "device" argument is used
+#                   to verify "image-node-name" is in the chain
+#                   described by "device".
 #
 # @device:          The device name or node-name of the root node that owns
 #                   image-node-name.
@@ -1011,6 +1245,10 @@
 #                   when specifying the string or the image chain may
 #                   not be able to be reopened again.
 #
+# Returns: Nothing on success
+#
+#          If "device" does not exist or cannot be determined, DeviceNotFound
+#
 # Since: 2.1
 ##
 { 'command': 'change-backing-file',
@@ -1029,7 +1267,7 @@
 # @device:  the device name or node-name of a root node
 #
 # @base:   #optional The file name of the backing image to write data into.
-#                    If not specified, this is the deepest backing image
+#                    If not specified, this is the deepest backing image.
 #
 # @top:    #optional The file name of the backing image within the image chain,
 #                    which contains the topmost data to be committed down. If
@@ -1075,6 +1313,13 @@
 #
 # Since: 1.3
 #
+# Example:
+#
+# -> { "execute": "block-commit",
+#      "arguments": { "device": "virtio0",
+#                     "top": "/tmp/snap1.qcow2" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'block-commit',
   'data': { '*job-id': 'str', 'device': 'str', '*base': 'str', '*top': 'str',
@@ -1095,6 +1340,15 @@
 #          If @device is not a valid block device, GenericError
 #
 # Since: 1.6
+#
+# Example:
+#
+# -> { "execute": "drive-backup",
+#      "arguments": { "device": "drive0",
+#                     "sync": "full",
+#                     "target": "backup.img" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'drive-backup', 'boxed': true,
   'data': 'DriveBackup' }
@@ -1114,6 +1368,14 @@
 #          If @device is not a valid block device, DeviceNotFound
 #
 # Since: 2.3
+#
+# Example:
+# -> { "execute": "blockdev-backup",
+#      "arguments": { "device": "src-id",
+#                     "sync": "full",
+#                     "target": "tgt-id" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'blockdev-backup', 'boxed': true,
   'data': 'BlockdevBackup' }
@@ -1127,13 +1389,67 @@
 # Returns: the list of BlockDeviceInfo
 #
 # Since: 2.0
+#
+# Example:
+#
+# -> { "execute": "query-named-block-nodes" }
+# <- { "return": [ { "ro":false,
+#                    "drv":"qcow2",
+#                    "encrypted":false,
+#                    "file":"disks/test.qcow2",
+#                    "node-name": "my-node",
+#                    "backing_file_depth":1,
+#                    "bps":1000000,
+#                    "bps_rd":0,
+#                    "bps_wr":0,
+#                    "iops":1000000,
+#                    "iops_rd":0,
+#                    "iops_wr":0,
+#                    "bps_max": 8000000,
+#                    "bps_rd_max": 0,
+#                    "bps_wr_max": 0,
+#                    "iops_max": 0,
+#                    "iops_rd_max": 0,
+#                    "iops_wr_max": 0,
+#                    "iops_size": 0,
+#                    "write_threshold": 0,
+#                    "image":{
+#                       "filename":"disks/test.qcow2",
+#                       "format":"qcow2",
+#                       "virtual-size":2048000,
+#                       "backing_file":"base.qcow2",
+#                       "full-backing-filename":"disks/base.qcow2",
+#                       "backing-filename-format":"qcow2",
+#                       "snapshots":[
+#                          {
+#                             "id": "1",
+#                             "name": "snapshot1",
+#                             "vm-state-size": 0,
+#                             "date-sec": 10000200,
+#                             "date-nsec": 12,
+#                             "vm-clock-sec": 206,
+#                             "vm-clock-nsec": 30
+#                          }
+#                       ],
+#                       "backing-image":{
+#                           "filename":"disks/base.qcow2",
+#                           "format":"qcow2",
+#                           "virtual-size":2048000
+#                       }
+#                    } } ] }
+#
 ##
 { 'command': 'query-named-block-nodes', 'returns': [ 'BlockDeviceInfo' ] }
 
 ##
 # @drive-mirror:
 #
-# Start mirroring a block device's writes to a new destination.
+# Start mirroring a block device's writes to a new destination. target
+# specifies the target of the new image. If the file exists, or if it
+# is a device, it will be used as the new destination for writes. If
+# it does not exist, a new file will be created. format specifies the
+# format of the mirror image, default is to probe if mode='existing',
+# else the format of the source.
 #
 # See DriveMirror for parameter descriptions
 #
@@ -1141,6 +1457,16 @@
 #          If @device is not a valid block device, GenericError
 #
 # Since: 1.3
+#
+# Example:
+#
+# -> { "execute": "drive-mirror",
+#      "arguments": { "device": "ide-hd0",
+#                     "target": "/some/place/my-image",
+#                     "sync": "full",
+#                     "format": "qcow2" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'drive-mirror', 'boxed': true,
   'data': 'DriveMirror' }
@@ -1241,13 +1567,20 @@
 ##
 # @block-dirty-bitmap-add:
 #
-# Create a dirty bitmap with a name on the node
+# Create a dirty bitmap with a name on the node, and start tracking the writes.
 #
 # Returns: nothing on success
 #          If @node is not a valid block device or node, DeviceNotFound
 #          If @name is already taken, GenericError with an explanation
 #
 # Since: 2.4
+#
+# Example:
+#
+# -> { "execute": "block-dirty-bitmap-add",
+#      "arguments": { "node": "drive0", "name": "bitmap0" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'block-dirty-bitmap-add',
   'data': 'BlockDirtyBitmapAdd' }
@@ -1255,7 +1588,8 @@
 ##
 # @block-dirty-bitmap-remove:
 #
-# Remove a dirty bitmap on the node
+# Stop write tracking and remove the dirty bitmap that was created
+# with block-dirty-bitmap-add.
 #
 # Returns: nothing on success
 #          If @node is not a valid block device or node, DeviceNotFound
@@ -1263,6 +1597,13 @@
 #          if @name is frozen by an operation, GenericError
 #
 # Since: 2.4
+#
+# Example:
+#
+# -> { "execute": "block-dirty-bitmap-remove",
+#      "arguments": { "node": "drive0", "name": "bitmap0" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'block-dirty-bitmap-remove',
   'data': 'BlockDirtyBitmap' }
@@ -1270,13 +1611,22 @@
 ##
 # @block-dirty-bitmap-clear:
 #
-# Clear (reset) a dirty bitmap on the device
+# Clear (reset) a dirty bitmap on the device, so that an incremental
+# backup from this point in time forward will only backup clusters
+# modified after this clear operation.
 #
 # Returns: nothing on success
 #          If @node is not a valid block device, DeviceNotFound
 #          If @name is not found, GenericError with an explanation
 #
 # Since: 2.4
+#
+# Example:
+#
+# -> { "execute": "block-dirty-bitmap-clear",
+#      "arguments": { "node": "drive0", "name": "bitmap0" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'block-dirty-bitmap-clear',
   'data': 'BlockDirtyBitmap' }
@@ -1324,6 +1674,15 @@
 # Returns: nothing on success.
 #
 # Since: 2.6
+#
+# Example:
+#
+# -> { "execute": "blockdev-mirror",
+#      "arguments": { "device": "ide-hd0",
+#                     "target": "target0",
+#                     "sync": "full" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'blockdev-mirror',
   'data': { '*job-id': 'str', 'device': 'str', 'target': 'str',
@@ -1365,6 +1724,26 @@
 #          If @device is not a valid block device, DeviceNotFound
 #
 # Since: 1.1
+#
+# Example:
+#
+# -> { "execute": "block_set_io_throttle",
+#      "arguments": { "id": "ide0-1-0",
+#                     "bps": 1000000,
+#                     "bps_rd": 0,
+#                     "bps_wr": 0,
+#                     "iops": 0,
+#                     "iops_rd": 0,
+#                     "iops_wr": 0,
+#                     "bps_max": 8000000,
+#                     "bps_rd_max": 0,
+#                     "bps_wr_max": 0,
+#                     "iops_max": 0,
+#                     "iops_rd_max": 0,
+#                     "iops_wr_max": 0,
+#                     "bps_max_length": 60,
+#                     "iops_size": 0 } }
+# <- { "return": {} }
 ##
 { 'command': 'block_set_io_throttle', 'boxed': true,
   'data': 'BlockIOThrottle' }
@@ -1513,7 +1892,17 @@
 #            'stop' and 'enospc' can only be used if the block device
 #            supports io-status (see BlockInfo).  Since 1.3.
 #
+# Returns: Nothing on success. If @device does not exist, DeviceNotFound.
+#
 # Since: 1.1
+#
+# Example:
+#
+# -> { "execute": "block-stream",
+#      "arguments": { "device": "virtio0",
+#                     "base": "/tmp/master.qcow2" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'block-stream',
   'data': { '*job-id': 'str', 'device': 'str', '*base': 'str',
@@ -2443,13 +2832,52 @@
 # BlockBackend will be created; otherwise, @node-name is mandatory at the top
 # level and no BlockBackend will be created.
 #
-# This command is still a work in progress.  It doesn't support all
+# Note: This command is still a work in progress.  It doesn't support all
 # block drivers among other things.  Stay away from it unless you want
 # to help with its development.
 #
 # For the arguments, see the documentation of BlockdevOptions.
 #
 # Since: 1.7
+#
+# Example:
+#
+# 1.
+# -> { "execute": "blockdev-add",
+#      "arguments": {
+#          "options" : { "driver": "qcow2",
+#                        "file": { "driver": "file",
+#                                  "filename": "test.qcow2" } } } }
+# <- { "return": {} }
+#
+# 2.
+# -> { "execute": "blockdev-add",
+#      "arguments": {
+#          "options": {
+#            "driver": "qcow2",
+#            "node-name": "node0",
+#            "discard": "unmap",
+#            "cache": {
+#                "direct": true,
+#                "writeback": true
+#            },
+#            "file": {
+#                "driver": "file",
+#                "filename": "/tmp/test.qcow2"
+#            },
+#            "backing": {
+#                "driver": "raw",
+#                "file": {
+#                    "driver": "file",
+#                    "filename": "/dev/fdset/4"
+#                }
+#            }
+#          }
+#        }
+#      }
+#
+# <- { "return": {} }
+#
 ##
 { 'command': 'blockdev-add', 'data': 'BlockdevOptions', 'boxed': true }
 
@@ -2460,13 +2888,35 @@
 # The command will fail if the node is attached to a device or is
 # otherwise being used.
 #
-# This command is still a work in progress and is considered
+# Note: This command is still a work in progress and is considered
 # experimental. Stay away from it unless you want to help with its
 # development.
 #
 # @node-name: Name of the graph node to delete.
 #
 # Since: 2.5
+#
+# Example:
+#
+# -> { "execute": "blockdev-add",
+#      "arguments": {
+#          "options": {
+#              "driver": "qcow2",
+#              "node-name": "node0",
+#              "file": {
+#                  "driver": "file",
+#                  "filename": "test.qcow2"
+#              }
+#          }
+#      }
+#    }
+# <- { "return": {} }
+#
+# -> { "execute": "x-blockdev-del",
+#      "arguments": { "node-name": "node0" }
+#    }
+# <- { "return": {} }
+#
 ##
 { 'command': 'x-blockdev-del', 'data': { 'node-name': 'str' } }
 
@@ -2498,6 +2948,21 @@
 #          it is locked
 #
 # Since: 2.5
+#
+# Example:
+#
+# -> { "execute": "blockdev-open-tray",
+#      "arguments": { "id": "ide0-1-0" } }
+#
+# <- { "timestamp": { "seconds": 1418751016,
+#                     "microseconds": 716996 },
+#      "event": "DEVICE_TRAY_MOVED",
+#      "data": { "device": "ide1-cd0",
+#                "id": "ide0-1-0",
+#                "tray-open": true } }
+#
+# <- { "return": {} }
+#
 ##
 { 'command': 'blockdev-open-tray',
   'data': { '*device': 'str',
@@ -2518,6 +2983,21 @@
 # @id:      #optional The name or QOM path of the guest device (since: 2.8)
 #
 # Since: 2.5
+#
+# Example:
+#
+# -> { "execute": "blockdev-close-tray",
+#      "arguments": { "id": "ide0-1-0" } }
+#
+# <- { "timestamp": { "seconds": 1418751345,
+#                     "microseconds": 272147 },
+#      "event": "DEVICE_TRAY_MOVED",
+#      "data": { "device": "ide1-cd0",
+#                "id": "ide0-1-0",
+#                "tray-open": false } }
+#
+# <- { "return": {} }
+#
 ##
 { 'command': 'blockdev-close-tray',
   'data': { '*device': 'str',
@@ -2540,6 +3020,32 @@
 # @id:     #optional The name or QOM path of the guest device (since: 2.8)
 #
 # Since: 2.5
+#
+# Example:
+#
+# -> { "execute": "x-blockdev-remove-medium",
+#      "arguments": { "id": "ide0-1-0" } }
+#
+# <- { "error": { "class": "GenericError",
+#                 "desc": "Tray of device 'ide0-1-0' is not open" } }
+#
+# -> { "execute": "blockdev-open-tray",
+#      "arguments": { "id": "ide0-1-0" } }
+#
+# <- { "timestamp": { "seconds": 1418751627,
+#                     "microseconds": 549958 },
+#      "event": "DEVICE_TRAY_MOVED",
+#      "data": { "device": "ide1-cd0",
+#                "id": "ide0-1-0",
+#                "tray-open": true } }
+#
+# <- { "return": {} }
+#
+# -> { "execute": "x-blockdev-remove-medium",
+#      "arguments": { "device": "ide0-1-0" } }
+#
+# <- { "return": {} }
+#
 ##
 { 'command': 'x-blockdev-remove-medium',
   'data': { '*device': 'str',
@@ -2552,8 +3058,9 @@
 # device's tray must currently be open (unless there is no attached guest
 # device) and there must be no medium inserted already.
 #
-# This command is still a work in progress and is considered experimental.
-# Stay away from it unless you want to help with its development.
+# Note: This command is still a work in progress and is considered
+# experimental.  Stay away from it unless you want to help with its
+# development.
 #
 # @device:    #optional Block device name (deprecated, use @id instead)
 #
@@ -2562,6 +3069,23 @@
 # @node-name: name of a node in the block driver state graph
 #
 # Since: 2.5
+#
+# Example:
+#
+# -> { "execute": "blockdev-add",
+#      "arguments": {
+#          "options": { "node-name": "node0",
+#                       "driver": "raw",
+#                       "file": { "driver": "file",
+#                                 "filename": "fedora.iso" } } } }
+# <- { "return": {} }
+#
+# -> { "execute": "x-blockdev-insert-medium",
+#      "arguments": { "id": "ide0-1-0",
+#                     "node-name": "node0" } }
+#
+# <- { "return": {} }
+#
 ##
 { 'command': 'x-blockdev-insert-medium',
   'data': { '*device': 'str',
@@ -2582,6 +3106,7 @@
 # @read-write:  Makes the device writable
 #
 # Since: 2.3
+#
 ##
 { 'enum': 'BlockdevChangeReadOnlyMode',
   'data': ['retain', 'read-only', 'read-write'] }
@@ -2609,6 +3134,37 @@
 #                   to 'retain'
 #
 # Since: 2.5
+#
+# Examples:
+#
+# 1. Change a removable medium
+#
+# -> { "execute": "blockdev-change-medium",
+#      "arguments": { "id": "ide0-1-0",
+#                     "filename": "/srv/images/Fedora-12-x86_64-DVD.iso",
+#                     "format": "raw" } }
+# <- { "return": {} }
+#
+# 2. Load a read-only medium into a writable drive
+#
+# -> { "execute": "blockdev-change-medium",
+#      "arguments": { "id": "floppyA",
+#                     "filename": "/srv/images/ro.img",
+#                     "format": "raw",
+#                     "read-only-mode": "retain" } }
+#
+# <- { "error":
+#      { "class": "GenericError",
+#        "desc": "Could not open '/srv/images/ro.img': Permission denied" } }
+#
+# -> { "execute": "blockdev-change-medium",
+#      "arguments": { "id": "floppyA",
+#                     "filename": "/srv/images/ro.img",
+#                     "format": "raw",
+#                     "read-only-mode": "read-only" } }
+#
+# <- { "return": {} }
+#
 ##
 { 'command': 'blockdev-change-medium',
   'data': { '*device': 'str',
@@ -2638,7 +3194,10 @@
 ##
 # @BLOCK_IMAGE_CORRUPTED:
 #
-# Emitted when a corruption has been detected in a disk image
+# Emitted when a disk image is being marked corrupt. The image can be
+# identified by its device or node name. The 'device' field is always
+# present for compatibility reasons, but it can be empty ("") if the
+# image does not have a device name associated.
 #
 # @device: device name. This is always present for compatibility
 #          reasons, but it can be empty ("") if the image does not
@@ -2656,10 +3215,21 @@
 # @size: #optional, if the corruption resulted from an image access, this is
 #        the access size
 #
-# fatal: if set, the image is marked corrupt and therefore unusable after this
+# @fatal: if set, the image is marked corrupt and therefore unusable after this
 #        event and must be repaired (Since 2.2; before, every
 #        BLOCK_IMAGE_CORRUPTED event was fatal)
 #
+# Note: If action is "stop", a STOP event will eventually follow the
+#       BLOCK_IO_ERROR event.
+#
+# Example:
+#
+# <- { "event": "BLOCK_IMAGE_CORRUPTED",
+#      "data": { "device": "ide0-hd0", "node-name": "node0",
+#                "msg": "Prevented active L1 table overwrite", "offset": 196608,
+#                "size": 65536 },
+#      "timestamp": { "seconds": 1378126126, "microseconds": 966463 } }
+#
 # Since: 1.7
 ##
 { 'event': 'BLOCK_IMAGE_CORRUPTED',
@@ -2700,6 +3270,16 @@
 # BLOCK_IO_ERROR event
 #
 # Since: 0.13.0
+#
+# Example:
+#
+# <- { "event": "BLOCK_IO_ERROR",
+#      "data": { "device": "ide0-hd1",
+#                "node-name": "#block212",
+#                "operation": "write",
+#                "action": "stop" },
+#      "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
+#
 ##
 { 'event': 'BLOCK_IO_ERROR',
   'data': { 'device': 'str', 'node-name': 'str', 'operation': 'IoOperationType',
@@ -2729,6 +3309,15 @@
 #         interpret the error string
 #
 # Since: 1.1
+#
+# Example:
+#
+# <- { "event": "BLOCK_JOB_COMPLETED",
+#      "data": { "type": "stream", "device": "virtio-disk0",
+#                "len": 10737418240, "offset": 10737418240,
+#                "speed": 0 },
+#      "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
+#
 ##
 { 'event': 'BLOCK_JOB_COMPLETED',
   'data': { 'type'  : 'BlockJobType',
@@ -2756,6 +3345,15 @@
 # @speed: rate limit, bytes per second
 #
 # Since: 1.1
+#
+# Example:
+#
+# <- { "event": "BLOCK_JOB_CANCELLED",
+#      "data": { "type": "stream", "device": "virtio-disk0",
+#                "len": 10737418240, "offset": 134217728,
+#                "speed": 0 },
+#      "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
+#
 ##
 { 'event': 'BLOCK_JOB_CANCELLED',
   'data': { 'type'  : 'BlockJobType',
@@ -2777,6 +3375,15 @@
 # @action: action that has been taken
 #
 # Since: 1.3
+#
+# Example:
+#
+# <- { "event": "BLOCK_JOB_ERROR",
+#      "data": { "device": "ide0-hd1",
+#                "operation": "write",
+#                "action": "stop" },
+#      "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
+#
 ##
 { 'event': 'BLOCK_JOB_ERROR',
   'data': { 'device'   : 'str',
@@ -2804,6 +3411,14 @@
 # event
 #
 # Since: 1.3
+#
+# Example:
+#
+# <- { "event": "BLOCK_JOB_READY",
+#      "data": { "device": "drive0", "type": "mirror", "speed": 0,
+#                "len": 2097152, "offset": 2097152 }
+#      "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
+#
 ##
 { 'event': 'BLOCK_JOB_READY',
   'data': { 'type'  : 'BlockJobType',
@@ -2856,8 +3471,12 @@
 ##
 # @block-set-write-threshold:
 #
-# Change the write threshold for a block drive. An event will be delivered
-# if a write to this block drive crosses the configured threshold.
+# Change the write threshold for a block drive. An event will be
+# delivered if a write to this block drive crosses the configured
+# threshold.  The threshold is an offset, thus must be
+# non-negative. Default is no write threshold. Setting the threshold
+# to zero disables it.
+#
 # This is useful to transparently resize thin-provisioned drives without
 # the guest OS noticing.
 #
@@ -2867,6 +3486,14 @@
 #                   Use 0 to disable the threshold.
 #
 # Since: 2.3
+#
+# Example:
+#
+# -> { "execute": "block-set-write-threshold",
+#      "arguments": { "node-name": "mydev",
+#                     "write-threshold": 17179869184 } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'block-set-write-threshold',
   'data': { 'node-name': 'str', 'write-threshold': 'uint64' } }
@@ -2897,6 +3524,28 @@
 # the rest of the array.
 #
 # Since: 2.7
+#
+# Example:
+#
+# 1. Add a new node to a quorum
+# -> { "execute": "blockdev-add",
+#      "arguments": {
+#          "options": { "driver": "raw",
+#                       "node-name": "new_node",
+#                        "file": { "driver": "file",
+#                                  "filename": "test.raw" } } } }
+# <- { "return": {} }
+# -> { "execute": "x-blockdev-change",
+#      "arguments": { "parent": "disk1",
+#                     "node": "new_node" } }
+# <- { "return": {} }
+#
+# 2. Delete a quorum's node
+# -> { "execute": "x-blockdev-change",
+#      "arguments": { "parent": "disk1",
+#                     "child": "children.1" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'x-blockdev-change',
   'data' : { 'parent': 'str',
diff --git a/qapi/block.json b/qapi/block.json
index e4ad74b..2a2d95a 100644
--- a/qapi/block.json
+++ b/qapi/block.json
@@ -81,19 +81,33 @@
 ##
 # @blockdev-snapshot-internal-sync:
 #
-# Synchronously take an internal snapshot of a block device, when the format
-# of the image used supports it.
+# Synchronously take an internal snapshot of a block device, when the
+# format of the image used supports it. If the name is an empty
+# string, or a snapshot with name already exists, the operation will
+# fail.
 #
 # For the arguments, see the documentation of BlockdevSnapshotInternal.
 #
 # Returns: nothing on success
+#
 #          If @device is not a valid block device, GenericError
+#
 #          If any snapshot matching @name exists, or @name is empty,
 #          GenericError
+#
 #          If the format of the image used does not support it,
 #          BlockFormatFeatureNotSupported
 #
 # Since: 1.7
+#
+# Example:
+#
+# -> { "execute": "blockdev-snapshot-internal-sync",
+#      "arguments": { "device": "ide-hd0",
+#                     "name": "snapshot0" }
+#    }
+# <- { "return": {} }
+#
 ##
 { 'command': 'blockdev-snapshot-internal-sync',
   'data': 'BlockdevSnapshotInternal' }
@@ -121,6 +135,24 @@
 #          If @id and @name are both not specified, GenericError
 #
 # Since: 1.7
+#
+# Example:
+#
+# -> { "execute": "blockdev-snapshot-delete-internal-sync",
+#      "arguments": { "device": "ide-hd0",
+#                     "name": "snapshot0" }
+#    }
+# <- { "return": {
+#                    "id": "1",
+#                    "name": "snapshot0",
+#                    "vm-state-size": 0,
+#                    "date-sec": 1000012,
+#                    "date-nsec": 10,
+#                    "vm-clock-sec": 100,
+#                    "vm-clock-nsec": 20
+#      }
+#    }
+#
 ##
 { 'command': 'blockdev-snapshot-delete-internal-sync',
   'data': { 'device': 'str', '*id': 'str', '*name': 'str'},
@@ -135,15 +167,21 @@
 #
 # @id:      #optional The name or QOM path of the guest device (since: 2.8)
 #
-# @force:   @optional If true, eject regardless of whether the drive is locked.
+# @force:   #optional If true, eject regardless of whether the drive is locked.
 #           If not specified, the default value is false.
 #
 # Returns:  Nothing on success
+#
 #           If @device is not a valid block device, DeviceNotFound
 #
-# Notes:    Ejecting a device will no media results in success
+# Notes:    Ejecting a device with no media results in success
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "eject", "arguments": { "device": "ide1-0-1" } }
+# <- { "return": {} }
 ##
 { 'command': 'eject',
   'data': { '*device': 'str',
@@ -210,6 +248,16 @@
 # @tray-open: true if the tray has been opened or false if it has been closed
 #
 # Since: 1.1
+#
+# Example:
+#
+# <- { "event": "DEVICE_TRAY_MOVED",
+#      "data": { "device": "ide1-cd0",
+#                "id": "/machine/unattached/device[22]",
+#                "tray-open": true
+#      },
+#      "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
+#
 ##
 { 'event': 'DEVICE_TRAY_MOVED',
   'data': { 'device': 'str', 'id': 'str', 'tray-open': 'bool' } }
diff --git a/qapi/common.json b/qapi/common.json
index d93f159..b626647 100644
--- a/qapi/common.json
+++ b/qapi/common.json
@@ -77,6 +77,21 @@
 # Returns:  A @VersionInfo object describing the current version of QEMU.
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-version" }
+# <- {
+#       "return":{
+#          "qemu":{
+#             "major":0,
+#             "minor":11,
+#             "micro":5
+#          },
+#          "package":""
+#       }
+#    }
+#
 ##
 { 'command': 'query-version', 'returns': 'VersionInfo' }
 
@@ -99,6 +114,23 @@
 # Returns: A list of @CommandInfo for all supported commands
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# -> { "execute": "query-commands" }
+# <- {
+#      "return":[
+#         {
+#            "name":"query-balloon"
+#         },
+#         {
+#            "name":"system_powerdown"
+#         }
+#      ]
+#    }
+#
+# Note: This example has been shortened as the real response is too long.
+#
 ##
 { 'command': 'query-commands', 'returns': ['CommandInfo'] }
 
diff --git a/qapi/event.json b/qapi/event.json
index 59942b0..512b4be 100644
--- a/qapi/event.json
+++ b/qapi/event.json
@@ -14,6 +14,12 @@
 # not exit, and a STOP event will eventually follow the SHUTDOWN event
 #
 # Since: 0.12.0
+#
+# Example:
+#
+# <- { "event": "SHUTDOWN",
+#      "timestamp": { "seconds": 1267040730, "microseconds": 682951 } }
+#
 ##
 { 'event': 'SHUTDOWN' }
 
@@ -24,6 +30,12 @@
 # system, such as via ACPI.
 #
 # Since: 0.12.0
+#
+# Example:
+#
+# <- { "event": "POWERDOWN",
+#      "timestamp": { "seconds": 1267040730, "microseconds": 682951 } }
+#
 ##
 { 'event': 'POWERDOWN' }
 
@@ -33,6 +45,12 @@
 # Emitted when the virtual machine is reset
 #
 # Since: 0.12.0
+#
+# Example:
+#
+# <- { "event": "RESET",
+#      "timestamp": { "seconds": 1267041653, "microseconds": 9518 } }
+#
 ##
 { 'event': 'RESET' }
 
@@ -42,6 +60,12 @@
 # Emitted when the virtual machine is stopped
 #
 # Since: 0.12.0
+#
+# Example:
+#
+# <- { "event": "STOP",
+#      "timestamp": { "seconds": 1267041730, "microseconds": 281295 } }
+#
 ##
 { 'event': 'STOP' }
 
@@ -51,6 +75,12 @@
 # Emitted when the virtual machine resumes execution
 #
 # Since: 0.12.0
+#
+# Example:
+#
+# <- { "event": "RESUME",
+#      "timestamp": { "seconds": 1271770767, "microseconds": 582542 } }
+#
 ##
 { 'event': 'RESUME' }
 
@@ -61,6 +91,12 @@
 # which is sometimes called standby state
 #
 # Since: 1.1
+#
+# Example:
+#
+# <- { "event": "SUSPEND",
+#      "timestamp": { "seconds": 1344456160, "microseconds": 309119 } }
+#
 ##
 { 'event': 'SUSPEND' }
 
@@ -73,6 +109,12 @@
 # Note: QEMU shuts down (similar to event @SHUTDOWN) when entering this state
 #
 # Since: 1.2
+#
+# Example:
+#
+# <-   { "event": "SUSPEND_DISK",
+#        "timestamp": { "seconds": 1344456160, "microseconds": 309119 } }
+#
 ##
 { 'event': 'SUSPEND_DISK' }
 
@@ -82,6 +124,12 @@
 # Emitted when the guest has woken up from suspend state and is running
 #
 # Since: 1.1
+#
+# Example:
+#
+# <- { "event": "WAKEUP",
+#      "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
+#
 ##
 { 'event': 'WAKEUP' }
 
@@ -93,7 +141,16 @@
 # @offset: offset between base RTC clock (as specified by -rtc base), and
 #          new RTC clock value
 #
+# Note: This event is rate-limited.
+#
 # Since: 0.13.0
+#
+# Example:
+#
+# <-   { "event": "RTC_CHANGE",
+#        "data": { "offset": 78 },
+#        "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
+#
 ##
 { 'event': 'RTC_CHANGE',
   'data': { 'offset': 'int' } }
@@ -108,7 +165,16 @@
 # Note: If action is "reset", "shutdown", or "pause" the WATCHDOG event is
 # followed respectively by the RESET, SHUTDOWN, or STOP events
 #
+# Note: This event is rate-limited.
+#
 # Since: 0.13.0
+#
+# Example:
+#
+# <- { "event": "WATCHDOG",
+#      "data": { "action": "reset" },
+#      "timestamp": { "seconds": 1267061043, "microseconds": 959568 } }
+#
 ##
 { 'event': 'WATCHDOG',
   'data': { 'action': 'WatchdogExpirationAction' } }
@@ -125,6 +191,14 @@
 # @path: device path
 #
 # Since: 1.5
+#
+# Example:
+#
+# <- { "event": "DEVICE_DELETED",
+#      "data": { "device": "virtio-net-pci-0",
+#                "path": "/machine/peripheral/virtio-net-pci-0" },
+#      "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
+#
 ##
 { 'event': 'DEVICE_DELETED',
   'data': { '*device': 'str', 'path': 'str' } }
@@ -140,6 +214,15 @@
 # @path: device path
 #
 # Since: 1.6
+#
+# Example:
+#
+# <- { "event": "NIC_RX_FILTER_CHANGED",
+#      "data": { "name": "vnet0",
+#                "path": "/machine/peripheral/vnet0/virtio-backend" },
+#      "timestamp": { "seconds": 1368697518, "microseconds": 326866 } }
+#    }
+#
 ##
 { 'event': 'NIC_RX_FILTER_CHANGED',
   'data': { '*name': 'str', 'path': 'str' } }
@@ -157,6 +240,17 @@
 # the authentication ID is not provided
 #
 # Since: 0.13.0
+#
+# Example:
+#
+# <- { "event": "VNC_CONNECTED",
+#      "data": {
+#            "server": { "auth": "sasl", "family": "ipv4",
+#                        "service": "5901", "host": "0.0.0.0" },
+#            "client": { "family": "ipv4", "service": "58425",
+#                        "host": "127.0.0.1" } },
+#      "timestamp": { "seconds": 1262976601, "microseconds": 975795 } }
+#
 ##
 { 'event': 'VNC_CONNECTED',
   'data': { 'server': 'VncServerInfo',
@@ -173,6 +267,17 @@
 # @client: client information
 #
 # Since: 0.13.0
+#
+# Example:
+#
+# <-  { "event": "VNC_INITIALIZED",
+#       "data": {
+#            "server": { "auth": "sasl", "family": "ipv4",
+#                        "service": "5901", "host": "0.0.0.0"},
+#            "client": { "family": "ipv4", "service": "46089",
+#                        "host": "127.0.0.1", "sasl_username": "luiz" } },
+#       "timestamp": { "seconds": 1263475302, "microseconds": 150772 } }
+#
 ##
 { 'event': 'VNC_INITIALIZED',
   'data': { 'server': 'VncServerInfo',
@@ -188,6 +293,17 @@
 # @client: client information
 #
 # Since: 0.13.0
+#
+# Example:
+#
+# <- { "event": "VNC_DISCONNECTED",
+#      "data": {
+#            "server": { "auth": "sasl", "family": "ipv4",
+#                        "service": "5901", "host": "0.0.0.0" },
+#            "client": { "family": "ipv4", "service": "58425",
+#                        "host": "127.0.0.1", "sasl_username": "luiz" } },
+#      "timestamp": { "seconds": 1262976601, "microseconds": 975795 } }
+#
 ##
 { 'event': 'VNC_DISCONNECTED',
   'data': { 'server': 'VncServerInfo',
@@ -203,6 +319,16 @@
 # @client: client information
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# <- { "timestamp": {"seconds": 1290688046, "microseconds": 388707},
+#      "event": "SPICE_CONNECTED",
+#      "data": {
+#        "server": { "port": "5920", "family": "ipv4", "host": "127.0.0.1"},
+#        "client": {"port": "52873", "family": "ipv4", "host": "127.0.0.1"}
+#    }}
+#
 ##
 { 'event': 'SPICE_CONNECTED',
   'data': { 'server': 'SpiceBasicInfo',
@@ -219,6 +345,18 @@
 # @client: client information
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# <- { "timestamp": {"seconds": 1290688046, "microseconds": 417172},
+#      "event": "SPICE_INITIALIZED",
+#      "data": {"server": {"auth": "spice", "port": "5921",
+#                          "family": "ipv4", "host": "127.0.0.1"},
+#               "client": {"port": "49004", "family": "ipv4", "channel-type": 3,
+#                          "connection-id": 1804289383, "host": "127.0.0.1",
+#                          "channel-id": 0, "tls": true}
+#    }}
+#
 ##
 { 'event': 'SPICE_INITIALIZED',
   'data': { 'server': 'SpiceServerInfo',
@@ -234,6 +372,16 @@
 # @client: client information
 #
 # Since: 0.14.0
+#
+# Example:
+#
+# <- { "timestamp": {"seconds": 1290688046, "microseconds": 388707},
+#      "event": "SPICE_DISCONNECTED",
+#      "data": {
+#        "server": { "port": "5920", "family": "ipv4", "host": "127.0.0.1"},
+#        "client": {"port": "52873", "family": "ipv4", "host": "127.0.0.1"}
+#    }}
+#
 ##
 { 'event': 'SPICE_DISCONNECTED',
   'data': { 'server': 'SpiceBasicInfo',
@@ -245,6 +393,12 @@
 # Emitted when SPICE migration has completed
 #
 # Since: 1.3
+#
+# Example:
+#
+# <- { "timestamp": {"seconds": 1290688046, "microseconds": 417172},
+#      "event": "SPICE_MIGRATE_COMPLETED" }
+#
 ##
 { 'event': 'SPICE_MIGRATE_COMPLETED' }
 
@@ -256,6 +410,13 @@
 # @status: @MigrationStatus describing the current migration status.
 #
 # Since: 2.4
+#
+# Example:
+#
+# <- {"timestamp": {"seconds": 1432121972, "microseconds": 744001},
+#     "event": "MIGRATION",
+#     "data": {"status": "completed"} }
+#
 ##
 { 'event': 'MIGRATION',
   'data': {'status': 'MigrationStatus'}}
@@ -269,6 +430,12 @@
 # @pass: An incrementing count (starting at 1 on the first pass)
 #
 # Since: 2.6
+#
+# Example:
+#
+# { "timestamp": {"seconds": 1449669631, "microseconds": 239225},
+#   "event": "MIGRATION_PASS", "data": {"pass": 2} }
+#
 ##
 { 'event': 'MIGRATION_PASS',
   'data': { 'pass': 'int' } }
@@ -281,6 +448,13 @@
 # Since: 2.1
 #
 # @info: ACPIOSTInfo type as described in qapi-schema.json
+#
+# Example:
+#
+# <- { "event": "ACPI_DEVICE_OST",
+#      "data": { "device": "d1", "slot": "0",
+#                "slot-type": "DIMM", "source": 1, "status": 0 } }
+#
 ##
 { 'event': 'ACPI_DEVICE_OST',
      'data': { 'info': 'ACPIOSTInfo' } }
@@ -293,7 +467,16 @@
 #
 # @actual: actual level of the guest memory balloon in bytes
 #
+# Note: this event is rate-limited.
+#
 # Since: 1.2
+#
+# Example:
+#
+# <- { "event": "BALLOON_CHANGE",
+#      "data": { "actual": 944766976 },
+#      "timestamp": { "seconds": 1267020223, "microseconds": 435656 } }
+#
 ##
 { 'event': 'BALLOON_CHANGE',
   'data': { 'actual': 'int' } }
@@ -306,6 +489,12 @@
 # @action: action that has been taken, currently always "pause"
 #
 # Since: 1.5
+#
+# Example:
+#
+# <- { "event": "GUEST_PANICKED",
+#      "data": { "action": "pause" } }
+#
 ##
 { 'event': 'GUEST_PANICKED',
   'data': { 'action': 'GuestPanicAction' } }
@@ -321,7 +510,16 @@
 #
 # @sectors-count: failed read operation sector count
 #
+# Note: This event is rate-limited.
+#
 # Since: 2.0
+#
+# Example:
+#
+# <- { "event": "QUORUM_FAILURE",
+#      "data": { "reference": "usr1", "sector-num": 345435, "sectors-count": 5 },
+#      "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
+#
 ##
 { 'event': 'QUORUM_FAILURE',
   'data': { 'reference': 'str', 'sector-num': 'int', 'sectors-count': 'int' } }
@@ -344,7 +542,26 @@
 #
 # @sectors-count: failed read operation sector count
 #
+# Note: This event is rate-limited.
+#
 # Since: 2.0
+#
+# Example:
+#
+# 1. Read operation
+#
+# { "event": "QUORUM_REPORT_BAD",
+#      "data": { "node-name": "node0", "sector-num": 345435, "sectors-count": 5,
+#                "type": "read" },
+#      "timestamp": { "seconds": 1344522075, "microseconds": 745528 } }
+#
+# 2. Flush operation
+#
+# { "event": "QUORUM_REPORT_BAD",
+#      "data": { "node-name": "node0", "sector-num": 0, "sectors-count": 2097120,
+#                "type": "flush", "error": "Broken pipe" },
+#      "timestamp": { "seconds": 1456406829, "microseconds": 291763 } }
+#
 ##
 { 'event': 'QUORUM_REPORT_BAD',
   'data': { 'type': 'QuorumOpType', '*error': 'str', 'node-name': 'str',
@@ -360,6 +577,13 @@
 # @open: true if the guest has opened the virtio-serial port
 #
 # Since: 2.1
+#
+# Example:
+#
+# <- { "event": "VSERPORT_CHANGE",
+#      "data": { "id": "channel0", "open": true },
+#      "timestamp": { "seconds": 1401385907, "microseconds": 422329 } }
+#
 ##
 { 'event': 'VSERPORT_CHANGE',
   'data': { 'id': 'str', 'open': 'bool' } }
@@ -374,6 +598,15 @@
 # @msg: Informative message
 #
 # Since: 2.4
+#
+# Example:
+#
+# <- { "event": "MEM_UNPLUG_ERROR"
+#      "data": { "device": "dimm1",
+#                "msg": "acpi: device unplug for unsupported device"
+#      },
+#      "timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
+#
 ##
 { 'event': 'MEM_UNPLUG_ERROR',
   'data': { 'device': 'str', 'msg': 'str' } }
@@ -390,6 +623,13 @@
 #         user should not try to interpret the error string.
 #
 # Since: 2.6
+#
+# Example:
+#
+# { "event": "DUMP_COMPLETED",
+#   "data": {"result": {"total": 1090650112, "status": "completed",
+#                       "completed": 1090650112} } }
+#
 ##
 { 'event': 'DUMP_COMPLETED' ,
   'data': { 'result': 'DumpQueryResult', '*error': 'str' } }
diff --git a/qapi/rocker.json b/qapi/rocker.json
index dd72e02..28a4eab 100644
--- a/qapi/rocker.json
+++ b/qapi/rocker.json
@@ -26,6 +26,12 @@
 # Returns: @Rocker information
 #
 # Since: 2.4
+#
+# Example:
+#
+# -> { "execute": "query-rocker", "arguments": { "name": "sw1" } }
+# <- { "return": {"name": "sw1", "ports": 2, "id": 1327446905938}}
+#
 ##
 { 'command': 'query-rocker',
   'data': { 'name': 'str' },
@@ -84,11 +90,21 @@
 ##
 # @query-rocker-ports:
 #
-# Return rocker switch information.
+# Return rocker switch port information.
 #
-# Returns: @Rocker information
+# Returns: a list of @RockerPort information
 #
 # Since: 2.4
+#
+# Example:
+#
+# -> { "execute": "query-rocker-ports", "arguments": { "name": "sw1" } }
+# <- { "return": [ {"duplex": "full", "enabled": true, "name": "sw1.1",
+#                   "autoneg": "off", "link-up": true, "speed": 10000},
+#                  {"duplex": "full", "enabled": true, "name": "sw1.2",
+#                   "autoneg": "off", "link-up": true, "speed": 10000}
+#    ]}
+#
 ##
 { 'command': 'query-rocker-ports',
   'data': { 'name': 'str' },
@@ -219,9 +235,23 @@
 # @tbl-id: #optional flow table ID.  If tbl-id is not specified, returns
 # flow information for all tables.
 #
-# Returns: @Rocker OF-DPA flow information
+# Returns: rocker OF-DPA flow information
 #
 # Since: 2.4
+#
+# Example:
+#
+# -> { "execute": "query-rocker-of-dpa-flows",
+#      "arguments": { "name": "sw1" } }
+# <- { "return": [ {"key": {"in-pport": 0, "priority": 1, "tbl-id": 0},
+#                   "hits": 138,
+#                   "cookie": 0,
+#                   "action": {"goto-tbl": 10},
+#                   "mask": {"in-pport": 4294901760}
+#                  },
+#                  {...more...},
+#    ]}
+#
 ##
 { 'command': 'query-rocker-of-dpa-flows',
   'data': { 'name': 'str', '*tbl-id': 'uint32' },
@@ -281,9 +311,28 @@
 # @type: #optional group type.  If type is not specified, returns
 # group information for all group types.
 #
-# Returns: @Rocker OF-DPA group information
+# Returns: rocker OF-DPA group information
 #
 # Since: 2.4
+#
+# Example:
+#
+# -> { "execute": "query-rocker-of-dpa-groups",
+#      "arguments": { "name": "sw1" } }
+# <- { "return": [ {"type": 0, "out-pport": 2,
+#                   "pport": 2, "vlan-id": 3841,
+#                   "pop-vlan": 1, "id": 251723778},
+#                  {"type": 0, "out-pport": 0,
+#                   "pport": 0, "vlan-id": 3841,
+#                   "pop-vlan": 1, "id": 251723776},
+#                  {"type": 0, "out-pport": 1,
+#                   "pport": 1, "vlan-id": 3840,
+#                   "pop-vlan": 1, "id": 251658241},
+#                  {"type": 0, "out-pport": 0,
+#                   "pport": 0, "vlan-id": 3840,
+#                   "pop-vlan": 1, "id": 251658240}
+#    ]}
+#
 ##
 { 'command': 'query-rocker-of-dpa-groups',
   'data': { 'name': 'str', '*type': 'uint8' },
diff --git a/qapi/trace.json b/qapi/trace.json
index 3ad7df7..2bfda7a 100644
--- a/qapi/trace.json
+++ b/qapi/trace.json
@@ -62,6 +62,13 @@
 # an error is returned.
 #
 # Since: 2.2
+#
+# Example:
+#
+# -> { "execute": "trace-event-get-state",
+#      "arguments": { "name": "qemu_memalign" } }
+# <- { "return": [ { "name": "qemu_memalign", "state": "disabled" } ] }
+#
 ##
 { 'command': 'trace-event-get-state',
   'data': {'name': 'str', '*vcpu': 'int'},
@@ -87,6 +94,13 @@
 # error is returned.
 #
 # Since: 2.2
+#
+# Example:
+#
+# -> { "execute": "trace-event-set-state",
+#      "arguments": { "name": "qemu_memalign", "enable": "true" } }
+# <- { "return": {} }
+#
 ##
 { 'command': 'trace-event-set-state',
   'data': {'name': 'str', 'enable': 'bool', '*ignore-unavailable': 'bool',
-- 
2.10.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [Qemu-devel] [PATCH v3 14/14] build-sys: add qapi doc generation targets
  2016-11-07  7:30 [Qemu-devel] [PATCH v3 00/14] qapi doc generation (whole version, squashed) Marc-André Lureau
                   ` (12 preceding siblings ...)
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 13/14] qmp-commands: (SQUASHED) move doc to schema Marc-André Lureau
@ 2016-11-07  7:30 ` Marc-André Lureau
  13 siblings, 0 replies; 28+ messages in thread
From: Marc-André Lureau @ 2016-11-07  7:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: eblake, armbru, Marc-André Lureau

Generate and install the man and html version of QAPI documentation.

Add it also to optional pdf/dvi/info targets.

Also support plain-text targets docs/qemu-ga-ref.txt & docs/qemu-qmp-ref.txt.

Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
---
 Makefile   | 56 +++++++++++++++++++++++++++++++++++++++++++++++++-------
 .gitignore | 11 ++++++++++-
 2 files changed, 59 insertions(+), 8 deletions(-)

diff --git a/Makefile b/Makefile
index 3617736..cc1c46e 100644
--- a/Makefile
+++ b/Makefile
@@ -91,6 +91,8 @@ HELPERS-$(CONFIG_LINUX) = qemu-bridge-helper$(EXESUF)
 
 ifdef BUILD_DOCS
 DOCS=qemu-doc.html qemu.1 qemu-img.1 qemu-nbd.8 qemu-ga.8
+DOCS+=docs/qemu-qmp-ref.html docs/qemu-qmp-ref.7
+DOCS+=docs/qemu-ga-ref.html docs/qemu-ga-ref.7
 ifdef CONFIG_VIRTFS
 DOCS+=fsdev/virtfs-proxy-helper.1
 endif
@@ -266,6 +268,7 @@ qemu-ga$(EXESUF): QEMU_CFLAGS += -I qga/qapi-generated
 gen-out-type = $(subst .,-,$(suffix $@))
 
 qapi-py = $(SRC_PATH)/scripts/qapi.py $(SRC_PATH)/scripts/ordereddict.py
+qapi-py += $(SRC_PATH)/scripts/qapi2texi.py
 
 qga/qapi-generated/qga-qapi-types.c qga/qapi-generated/qga-qapi-types.h :\
 $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
@@ -395,6 +398,11 @@ distclean: clean
 	rm -f qemu-doc.vr
 	rm -f config.log
 	rm -f linux-headers/asm
+	rm -f qemu-ga-qapi.texi qemu-qapi.texi
+	rm -f docs/qemu-qmp-ref.7 docs/qemu-ga-ref.7
+	rm -f docs/qemu-qmp-ref.txt docs/qemu-ga-ref.txt
+	rm -f docs/qemu-qmp-ref.pdf docs/qemu-ga-ref.pdf
+	rm -f docs/qemu-qmp-ref.html docs/qemu-ga-ref.html
 	for d in $(TARGET_DIRS); do \
 	rm -rf $$d || exit 1 ; \
         done
@@ -431,9 +439,12 @@ endif
 install-doc: $(DOCS)
 	$(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
 	$(INSTALL_DATA) qemu-doc.html "$(DESTDIR)$(qemu_docdir)"
+	$(INSTALL_DATA) docs/qemu-qmp-ref.html "$(DESTDIR)$(qemu_docdir)"
 ifdef CONFIG_POSIX
 	$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
 	$(INSTALL_DATA) qemu.1 "$(DESTDIR)$(mandir)/man1"
+	$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man7"
+	$(INSTALL_DATA) docs/qemu-qmp-ref.7 "$(DESTDIR)$(mandir)/man7"
 ifneq ($(TOOLS),)
 	$(INSTALL_DATA) qemu-img.1 "$(DESTDIR)$(mandir)/man1"
 	$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man8"
@@ -441,6 +452,8 @@ ifneq ($(TOOLS),)
 endif
 ifneq (,$(findstring qemu-ga,$(TOOLS)))
 	$(INSTALL_DATA) qemu-ga.8 "$(DESTDIR)$(mandir)/man8"
+	$(INSTALL_DATA) docs/qemu-ga-ref.html "$(DESTDIR)$(qemu_docdir)"
+	$(INSTALL_DATA) docs/qemu-ga-ref.7 "$(DESTDIR)$(mandir)/man7"
 endif
 endif
 ifdef CONFIG_VIRTFS
@@ -528,9 +541,9 @@ ui/console-gl.o: $(SRC_PATH)/ui/console-gl.c \
 	ui/shader/texture-blit-vert.h ui/shader/texture-blit-frag.h
 
 # documentation
-MAKEINFO=makeinfo
+MAKEINFO=makeinfo -D 'VERSION $(VERSION)'
 MAKEINFOFLAGS=--no-headers --no-split --number-sections
-TEXIFLAG=$(if $(V),,--quiet)
+TEXIFLAG=$(if $(V),,--quiet) --command='@set VERSION $(VERSION)'
 %.dvi: %.texi
 	$(call quiet-command,texi2dvi $(TEXIFLAG) -I . $<,"GEN","$@")
 
@@ -542,7 +555,11 @@ TEXIFLAG=$(if $(V),,--quiet)
 	$(call quiet-command,$(MAKEINFO) $< -o $@,"GEN","$@")
 
 %.pdf: %.texi
-	$(call quiet-command,texi2pdf $(TEXIFLAG) -I . $<,"GEN","$@")
+	$(call quiet-command,texi2pdf $(TEXIFLAG) -I . $< -o $@,"GEN","$@")
+
+%.txt: %.texi
+	$(call quiet-command,LC_ALL=C $(MAKEINFO) $(MAKEINFOFLAGS) --plaintext $< -o $@,\
+	"  GEN   $@")
 
 qemu-options.texi: $(SRC_PATH)/qemu-options.hx $(SRC_PATH)/scripts/hxtool
 	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@")
@@ -556,6 +573,12 @@ qemu-monitor-info.texi: $(SRC_PATH)/hmp-commands-info.hx $(SRC_PATH)/scripts/hxt
 qemu-img-cmds.texi: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
 	$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -t < $< > $@,"GEN","$@")
 
+qemu-qapi.texi: $(qapi-modules) $(qapi-py)
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi2texi.py $< > $@,"GEN" "$@")
+
+qemu-ga-qapi.texi: $(SRC_PATH)/qga/qapi-schema.json $(qapi-py)
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi2texi.py $< > $@,"GEN","$@")
+
 qemu.1: qemu-doc.texi qemu-options.texi qemu-monitor.texi qemu-monitor-info.texi
 	$(call quiet-command, \
 	  perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu.pod && \
@@ -587,16 +610,35 @@ qemu-ga.8: qemu-ga.texi
 	  $(POD2MAN) --section=8 --center=" " --release=" " qemu-ga.pod > $@, \
 	  "GEN","$@")
 
-dvi: qemu-doc.dvi
-html: qemu-doc.html
-info: qemu-doc.info
-pdf: qemu-doc.pdf
+docs/qemu-qmp-ref.7:
+	$(call quiet-command, \
+	 perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-qmp-ref.pod && \
+	 $(POD2MAN) --section=7 --center=" " --release=" " qemu-qmp-ref.pod > $@, \
+	 "GEN","$@")
+
+docs/qemu-ga-ref.7:
+	$(call quiet-command, \
+	 perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< qemu-ga-ref.pod && \
+	 $(POD2MAN) --section=7 --center=" " --release=" " qemu-ga-ref.pod > $@, \
+	 "GEN","$@")
+
+dvi: qemu-doc.dvi docs/qemu-qmp-ref.dvi docs/qemu-ga-ref.dvi
+html: qemu-doc.html docs/qemu-qmp-ref.html docs/qemu-ga-ref.html
+info: qemu-doc.info docs/qemu-qmp-ref.info docs/qemu-ga-ref.info
+pdf: qemu-doc.pdf docs/qemu-qmp-ref.pdf docs/qemu-ga-ref.pdf
 
 qemu-doc.dvi qemu-doc.html qemu-doc.info qemu-doc.pdf: \
 	qemu-img.texi qemu-nbd.texi qemu-options.texi qemu-option-trace.texi \
 	qemu-monitor.texi qemu-img-cmds.texi qemu-ga.texi \
 	qemu-monitor-info.texi
 
+docs/qemu-ga-ref.dvi docs/qemu-ga-ref.html docs/qemu-ga-ref.info docs/qemu-ga-ref.pdf docs/qemu-ga-ref.txt docs/qemu-ga-ref.7: \
+docs/qemu-ga-ref.texi qemu-ga-qapi.texi
+
+docs/qemu-qmp-ref.dvi docs/qemu-qmp-ref.html docs/qemu-qmp-ref.info docs/qemu-qmp-ref.pdf docs/qemu-qmp-ref.txt docs/qemu-qmp-ref.7: \
+docs/qemu-qmp-ref.texi qemu-qapi.texi
+
+
 ifdef CONFIG_WIN32
 
 INSTALLER = qemu-setup-$(VERSION)$(EXESUF)
diff --git a/.gitignore b/.gitignore
index 3d7848c..d0905c3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -39,7 +39,7 @@
 /qmp-introspect.[ch]
 /qmp-marshal.c
 /qemu-doc.html
-/qemu-doc.info
+/qemu-doc.info*
 /qemu-img
 /qemu-nbd
 /qemu-options.def
@@ -109,6 +109,15 @@
 /pc-bios/optionrom/kvmvapic.img
 /pc-bios/s390-ccw/s390-ccw.elf
 /pc-bios/s390-ccw/s390-ccw.img
+/docs/qemu-ga-ref.html
+/docs/qemu-ga-ref.txt
+/docs/qemu-qmp-ref.html
+/docs/qemu-qmp-ref.txt
+docs/qemu-ga-ref.info*
+docs/qemu-qmp-ref.info*
+/qemu-ga-qapi.texi
+/qemu-qapi.texi
+*.tps
 .stgit-*
 cscope.*
 tags
-- 
2.10.0

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [Qemu-devel] [PATCH v3 01/14] qapi: add missing 'bus' argument in device_add
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 01/14] qapi: add missing 'bus' argument in device_add Marc-André Lureau
@ 2016-11-07 15:10   ` Markus Armbruster
  2016-11-07 22:55   ` Eric Blake
  1 sibling, 0 replies; 28+ messages in thread
From: Markus Armbruster @ 2016-11-07 15:10 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> 'device_add' is incomplete for now, but 'bus' is a common argument for
> regarless of the device, and is present in documentation. Add it to the
> device_add schema definition.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qapi-schema.json | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/qapi-schema.json b/qapi-schema.json
> index b0b4bf6..4ba5772 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -2317,7 +2317,7 @@
>  # Since: 0.13
>  ##
>  { 'command': 'device_add',
> -  'data': {'driver': 'str', 'id': 'str'},
> +  'data': {'driver': 'str', '*bus': 'str', 'id': 'str'},
>    'gen': false } # so we can get the additional arguments
>  
>  ##

Makes sense.

@id is actually optional, care to fix that, too?

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [Qemu-devel] [PATCH v3 03/14] qga/schema: improve guest-set-vcpus Returns: section
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 03/14] qga/schema: improve guest-set-vcpus Returns: section Marc-André Lureau
@ 2016-11-07 15:25   ` Markus Armbruster
  0 siblings, 0 replies; 28+ messages in thread
From: Markus Armbruster @ 2016-11-07 15:25 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> The documentation parser finishes a section after an empty line. Fix the

Suggest "The documentation parser we're going to add".

> Returns: section of guest-set-vcpus, and itemize the possible return
> values.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qga/qapi-schema.json | 12 ++++--------
>  1 file changed, 4 insertions(+), 8 deletions(-)
>
> diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
> index 758803a..cb68c17 100644
> --- a/qga/qapi-schema.json
> +++ b/qga/qapi-schema.json
> @@ -696,22 +696,18 @@
>  #
>  # Returns: The length of the initial sublist that has been successfully
>  #          processed. The guest agent maximizes this value. Possible cases:
> -#
> -#          0:                if the @vcpus list was empty on input. Guest state
> +#          - 0:              if the @vcpus list was empty on input. Guest state
>  #                            has not been changed. Otherwise,
> -#
> -#          Error:            processing the first node of @vcpus failed for the
> +#          - Error:          processing the first node of @vcpus failed for the
>  #                            reason returned. Guest state has not been changed.
>  #                            Otherwise,
> -#
> -#          < length(@vcpus): more than zero initial nodes have been processed,
> +#          - < length(@vcpus): more than zero initial nodes have been processed,
>  #                            but not the entire @vcpus list. Guest state has
>  #                            changed accordingly. To retrieve the error
>  #                            (assuming it persists), repeat the call with the
>  #                            successfully processed initial sublist removed.
>  #                            Otherwise,
> -#
> -#          length(@vcpus):   call successful.
> +#          - length(@vcpus): call successful.
>  #
>  # Since: 1.5
>  ##

Matches how we format similar lists elswhere.

If the "empty line ends section" syntax turns out to be inconvenient, we
can try to consider indentation.  But not now.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [Qemu-devel] [PATCH v3 06/14] qapi: fix various symbols mismatch in documentation
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 06/14] qapi: fix various symbols mismatch in documentation Marc-André Lureau
@ 2016-11-07 15:40   ` Markus Armbruster
  0 siblings, 0 replies; 28+ messages in thread
From: Markus Armbruster @ 2016-11-07 15:40 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> There are various mismatch:
> - invalid symbols
> - section and member symbols mismatch
> - enum or union values vs 'type'
>
> The documentation parser catches all these cases.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qapi-schema.json     | 20 +++++++++-----------
>  qapi/block-core.json |  4 ----
>  qapi/common.json     |  6 +++---
>  qapi/rocker.json     |  2 +-
>  qga/qapi-schema.json |  6 +++---
>  5 files changed, 16 insertions(+), 22 deletions(-)
>
> diff --git a/qapi-schema.json b/qapi-schema.json
> index 5f377fa..0c9a293 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -693,8 +693,6 @@
>  #
>  # Set various migration parameters.  See MigrationParameters for details.
>  #
> -# @x-checkpoint-delay: the delay time between two checkpoints. (Since 2.8)
> -#
>  # Since: 2.4
>  ##
>  { 'command': 'migrate-set-parameters', 'boxed': true,
> @@ -1171,7 +1169,7 @@
>             '*service': 'str', '*auth': 'str', '*clients': ['VncClientInfo']} }
>  
>  ##
> -# @VncPriAuth:
> +# @VncPrimaryAuth:
>  #
>  # vnc primary authentication method.
>  #
> @@ -3174,7 +3172,7 @@
>  #
>  # @alias: #optional an alias for the machine name
>  #
> -# @default: #optional whether the machine is default
> +# @is-default: #optional whether the machine is default
>  #
>  # @cpu-max: maximum number of CPUs supported by the machine type
>  #           (since 1.5.0)
> @@ -3727,7 +3725,6 @@
>  #
>  # @device: The name of the special file for the device,
>  #          i.e. /dev/ttyS0 on Unix or COM1: on Windows
> -# @type: What kind of device this is.
>  #
>  # Since: 1.4
>  ##
> @@ -3992,7 +3989,7 @@
>  #
>  # A union referencing different TPM backend types' configuration options
>  #
> -# @passthrough: The configuration options for the TPM passthrough type
> +# @type: 'passthrough' The configuration options for the TPM passthrough type
>  #
>  # Since: 1.5
>  ##
> @@ -4000,7 +3997,7 @@
>     'data': { 'passthrough' : 'TPMPassthroughOptions' } }
>  
>  ##
> -# @TpmInfo:
> +# @TPMInfo:
>  #
>  # Information about the TPM
>  #
> @@ -4344,10 +4341,11 @@
>  #
>  # Input event union.
>  #
> -# @key: Input event of Keyboard
> -# @btn: Input event of pointer buttons
> -# @rel: Input event of relative pointer motion
> -# @abs: Input event of absolute pointer motion
> +# @type: the input type, one of:
> +#  - 'key': Input event of Keyboard
> +#  - 'btn': Input event of pointer buttons
> +#  - 'rel': Input event of relative pointer motion
> +#  - 'abs': Input event of absolute pointer motion
>  #
>  # Since: 2.0
>  ##

This will do for now, but we need to figure out how to document unions
properly.

> diff --git a/qapi/block-core.json b/qapi/block-core.json
> index 372889c..c64a48c 100644
> --- a/qapi/block-core.json
> +++ b/qapi/block-core.json
> @@ -2160,10 +2160,6 @@
>  #
>  # @type:       Transport type used for gluster connection
>  #
> -# @unix:       socket file
> -#
> -# @tcp:        host address and port number
> -#
>  # This is similar to SocketAddress, only distinction:
>  #
>  # 1. GlusterServer is a flat union, SocketAddress is a simple union.

Unions again.  We lose a bit of information here, but it's almost
worthless information.

> diff --git a/qapi/common.json b/qapi/common.json
> index 9353a7b..6987100 100644
> --- a/qapi/common.json
> +++ b/qapi/common.json
> @@ -34,11 +34,11 @@
>  #
>  # A three-part version number.
>  #
> -# @qemu.major:  The major version number.
> +# @major:  The major version number.
>  #
> -# @qemu.minor:  The minor version number.
> +# @minor:  The minor version number.
>  #
> -# @qemu.micro:  The micro version number.
> +# @micro:  The micro version number.
>  #
>  # Since: 2.4
>  ##
> diff --git a/qapi/rocker.json b/qapi/rocker.json
> index 2fe7fdf..ace2776 100644
> --- a/qapi/rocker.json
> +++ b/qapi/rocker.json
> @@ -1,5 +1,5 @@
>  ##
> -# @Rocker:
> +# @RockerSwitch:
>  #
>  # Rocker switch information.
>  #
> diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
> index 5173c4a..2e6cc91 100644
> --- a/qga/qapi-schema.json
> +++ b/qga/qapi-schema.json
> @@ -203,7 +203,7 @@
>  #
>  # Open a file in the guest and retrieve a file handle for it
>  #
> -# @filepath: Full path to the file in the guest to open.
> +# @path: Full path to the file in the guest to open.
>  #
>  # @mode: #optional open mode, as per fopen(), "r" is the default.
>  #
> @@ -378,7 +378,7 @@
>    'data': { 'handle': 'int' } }
>  
>  ##
> -# @GuestFsFreezeStatus
> +# @GuestFsfreezeStatus
>  #
>  # An enumeration of filesystem freeze states
>  #
> @@ -766,7 +766,7 @@
>  # @GuestDiskAddress:
>  #
>  # @pci-controller: controller's PCI address
> -# @type: bus type
> +# @bus-type: bus type
>  # @bus: bus id
>  # @target: target id
>  # @unit: unit id

Lovely doc fixes :)

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [Qemu-devel] [PATCH v3 07/14] qapi: use one symbol per line
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 07/14] qapi: use one symbol per line Marc-André Lureau
@ 2016-11-07 15:57   ` Markus Armbruster
  0 siblings, 0 replies; 28+ messages in thread
From: Markus Armbruster @ 2016-11-07 15:57 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> The documentation parser only handles a single symbol per line.

Suggest "The documentation parser we're going to add".

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qapi/block-core.json | 8 ++++++--
>  1 file changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/qapi/block-core.json b/qapi/block-core.json
> index c64a48c..e1cc94a 100644
> --- a/qapi/block-core.json
> +++ b/qapi/block-core.json
> @@ -1712,9 +1712,13 @@
>  #
>  # Drivers that are supported in block device operations.
>  #
> -# @host_device, @host_cdrom: Since 2.1
> +# @host_device: Since 2.1
> +# @host_cdrom: Since 2.1
>  # @gluster: Since 2.7
> -# @nbd, @nfs, @replication, @ssh: Since 2.8
> +# @nbd: Since 2.8
> +# @nfs: Since 2.8
> +# @replication: Since 2.8
> +# @ssh: Since 2.8
>  #
>  # Since: 2.0
>  ##

If we had more, I'd consider making the doc parser smarter, but it's not
worth the bother just for this one.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [Qemu-devel] [PATCH v3 08/14] qapi: add missing colon-ending for section name
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 08/14] qapi: add missing colon-ending for section name Marc-André Lureau
@ 2016-11-07 15:58   ` Markus Armbruster
  0 siblings, 0 replies; 28+ messages in thread
From: Markus Armbruster @ 2016-11-07 15:58 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> The documentation parser expects a section name to end with ':',

Suggest "The documentation parser we're going to add".

> otherwise the comment is treated as free-form text body.
>
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qapi-schema.json     | 300 +++++++++++++++++++++++++--------------------------
>  qapi/block-core.json | 196 ++++++++++++++++-----------------
>  qapi/block.json      |  16 +--
>  qapi/common.json     |   8 +-
>  qapi/event.json      |  58 +++++-----
>  qapi/introspect.json |  28 ++---
>  qapi/trace.json      |   8 +-
>  qga/qapi-schema.json |  44 ++++----
>  8 files changed, 329 insertions(+), 329 deletions(-)

That's a lot of colons :)

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [Qemu-devel] [PATCH v3 09/14] qapi: add some sections in docs
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 09/14] qapi: add some sections in docs Marc-André Lureau
@ 2016-11-07 15:59   ` Markus Armbruster
  0 siblings, 0 replies; 28+ messages in thread
From: Markus Armbruster @ 2016-11-07 15:59 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> Add some more section title, and misc fixes.

Are there any "misc fixes" left?  I can see only section titles.

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qapi-schema.json     |  4 ++++
>  qapi/block-core.json |  6 ++++--
>  qapi/block.json      | 10 ++++++++--
>  qapi/common.json     |  6 ++++--
>  qapi/crypto.json     |  5 ++++-
>  qapi/event.json      |  6 ++++++
>  qapi/rocker.json     |  4 ++++
>  qapi/trace.json      |  3 +++
>  8 files changed, 37 insertions(+), 7 deletions(-)
>
> diff --git a/qapi-schema.json b/qapi-schema.json
> index e9605b0..b7dff19 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -20,6 +20,10 @@
>  # QAPI introspection
>  { 'include': 'qapi/introspect.json' }
>  
> +##
> +# = QMP commands
> +##
> +
>  ##
>  # @qmp_capabilities:
>  #
> diff --git a/qapi/block-core.json b/qapi/block-core.json
> index bc78042..91febed 100644
> --- a/qapi/block-core.json
> +++ b/qapi/block-core.json
> @@ -1,6 +1,8 @@
>  # -*- Mode: Python -*-
> -#
> -# QAPI block core definitions (vm unrelated)
> +
> +##
> +# == QAPI block core definitions (vm unrelated)
> +##
>  
>  # QAPI common definitions
>  { 'include': 'common.json' }
> diff --git a/qapi/block.json b/qapi/block.json
> index 937df05..e4ad74b 100644
> --- a/qapi/block.json
> +++ b/qapi/block.json
> @@ -1,10 +1,16 @@
>  # -*- Mode: Python -*-
> -#
> -# QAPI block definitions (vm related)
> +
> +##
> +# = QAPI block definitions
> +##
>  
>  # QAPI block core definitions
>  { 'include': 'block-core.json' }
>  
> +##
> +# == QAPI block definitions (vm unrelated)
> +##
> +
>  ##
>  # @BiosAtaTranslation:
>  #
> diff --git a/qapi/common.json b/qapi/common.json
> index 624a861..d93f159 100644
> --- a/qapi/common.json
> +++ b/qapi/common.json
> @@ -1,6 +1,8 @@
>  # -*- Mode: Python -*-
> -#
> -# QAPI common definitions
> +
> +##
> +# = QAPI common definitions
> +##
>  
>  ##
>  # @QapiErrorClass:
> diff --git a/qapi/crypto.json b/qapi/crypto.json
> index 15d296e..1e517b0 100644
> --- a/qapi/crypto.json
> +++ b/qapi/crypto.json
> @@ -1,6 +1,9 @@
>  # -*- Mode: Python -*-
>  #
> -# QAPI crypto definitions
> +
> +##
> +# = QAPI crypto definitions
> +##
>  
>  ##
>  # @QCryptoTLSCredsEndpoint:
> diff --git a/qapi/event.json b/qapi/event.json
> index 37bf34e..59942b0 100644
> --- a/qapi/event.json
> +++ b/qapi/event.json
> @@ -1,3 +1,9 @@
> +# -*- Mode: Python -*-
> +
> +##
> +# = Events
> +##
> +
>  ##
>  # @SHUTDOWN:
>  #
> diff --git a/qapi/rocker.json b/qapi/rocker.json
> index ace2776..dd72e02 100644
> --- a/qapi/rocker.json
> +++ b/qapi/rocker.json
> @@ -1,4 +1,8 @@
>  ##
> +# = Rocker API
> +##
> +
> +##
>  # @RockerSwitch:
>  #
>  # Rocker switch information.
> diff --git a/qapi/trace.json b/qapi/trace.json
> index 4fd39b7..3ad7df7 100644
> --- a/qapi/trace.json
> +++ b/qapi/trace.json
> @@ -5,6 +5,9 @@
>  # This work is licensed under the terms of the GNU GPL, version 2 or later.
>  # See the COPYING file in the top-level directory.
>  
> +##
> +# = Tracing commands
> +##
>  
>  ##
>  # @TraceEventState:

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [Qemu-devel] [PATCH v3 01/14] qapi: add missing 'bus' argument in device_add
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 01/14] qapi: add missing 'bus' argument in device_add Marc-André Lureau
  2016-11-07 15:10   ` Markus Armbruster
@ 2016-11-07 22:55   ` Eric Blake
  1 sibling, 0 replies; 28+ messages in thread
From: Eric Blake @ 2016-11-07 22:55 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel; +Cc: armbru

[-- Attachment #1: Type: text/plain, Size: 936 bytes --]

On 11/07/2016 01:30 AM, Marc-André Lureau wrote:
> 'device_add' is incomplete for now, but 'bus' is a common argument for
> regarless of the device, and is present in documentation. Add it to the

s/regarless/regardless/

> device_add schema definition.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qapi-schema.json | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/qapi-schema.json b/qapi-schema.json
> index b0b4bf6..4ba5772 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -2317,7 +2317,7 @@
>  # Since: 0.13
>  ##
>  { 'command': 'device_add',
> -  'data': {'driver': 'str', 'id': 'str'},
> +  'data': {'driver': 'str', '*bus': 'str', 'id': 'str'},
>    'gen': false } # so we can get the additional arguments
>  
>  ##
> 

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [Qemu-devel] [PATCH v3 02/14] qga/schema: fix double-return in doc
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 02/14] qga/schema: fix double-return in doc Marc-André Lureau
@ 2016-11-07 22:59   ` Eric Blake
  0 siblings, 0 replies; 28+ messages in thread
From: Eric Blake @ 2016-11-07 22:59 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel; +Cc: armbru

[-- Attachment #1: Type: text/plain, Size: 788 bytes --]

On 11/07/2016 01:30 AM, Marc-André Lureau wrote:
> guest-get-memory-block-info documentation should have only one
> "Returns:".
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qga/qapi-schema.json | 1 -
>  1 file changed, 1 deletion(-)

Reviewed-by: Eric Blake <eblake@redhat.com>

> 
> diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
> index c21f308..758803a 100644
> --- a/qga/qapi-schema.json
> +++ b/qga/qapi-schema.json
> @@ -952,7 +952,6 @@
>  #
>  # Get information relating to guest memory blocks.
>  #
> -# Returns: memory block size in bytes.
>  # Returns: @GuestMemoryBlockInfo
>  #
>  # Since 2.3
> 

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [Qemu-devel] [PATCH v3 04/14] qapi: fix schema symbol sections
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 04/14] qapi: fix schema symbol sections Marc-André Lureau
@ 2016-11-07 23:07   ` Eric Blake
  0 siblings, 0 replies; 28+ messages in thread
From: Eric Blake @ 2016-11-07 23:07 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel; +Cc: armbru

[-- Attachment #1: Type: text/plain, Size: 613 bytes --]

On 11/07/2016 01:30 AM, Marc-André Lureau wrote:
> According to docs/qapi-code-gen.txt, there needs to be '##' to start a
> and end a symbol section, that's also what the documentation parser
> expects.
> 
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qapi-schema.json     | 18 +++++++++++++-----
>  qapi/block-core.json |  1 +
>  qga/qapi-schema.json |  3 +++
>  3 files changed, 17 insertions(+), 5 deletions(-)

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [Qemu-devel] [PATCH v3 05/14] qapi: fix missing symbol @prefix
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 05/14] qapi: fix missing symbol @prefix Marc-André Lureau
@ 2016-11-07 23:08   ` Eric Blake
  0 siblings, 0 replies; 28+ messages in thread
From: Eric Blake @ 2016-11-07 23:08 UTC (permalink / raw)
  To: Marc-André Lureau, qemu-devel; +Cc: armbru

[-- Attachment #1: Type: text/plain, Size: 475 bytes --]

On 11/07/2016 01:30 AM, Marc-André Lureau wrote:
> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  qapi-schema.json     |  4 ++--
>  qapi/block-core.json |  4 ++--
>  qapi/crypto.json     | 36 ++++++++++++++++++------------------
>  3 files changed, 22 insertions(+), 22 deletions(-)

Reviewed-by: Eric Blake <eblake@redhat.com>

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 604 bytes --]

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [Qemu-devel] [PATCH v3 10/14] docs: add master qapi texi files
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 10/14] docs: add master qapi texi files Marc-André Lureau
@ 2016-11-08 14:19   ` Markus Armbruster
  0 siblings, 0 replies; 28+ messages in thread
From: Markus Armbruster @ 2016-11-08 14:19 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel

I see you managed to turn the templates into master files.  A welcome
simplification of the build process.

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> The qapi2texi scripts generates a file to be included in a texi

script (singular)

> file. Add "QEMU QMP Reference Manual" and "QEMU Guest Agent Protocol
> Reference" master texi files. Move qmp-intro.txt into qemu-qmp-ref.texi,
> to widen its content on various installed target
> formats (man/txt/html/pdf/info..)

I feel replacing qmp-intro.txt in this patch as well is one step too
many.  Let's do exactly the same both for QGA and QMP in this patch.
Actually, in this series, because I want to commit it sooner rather than
later, and the way to do that is to factor out and postpone inessential
parts that are eating precious review bandwidth.

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  docs/qemu-ga-ref.texi         |  65 ++++++++++++++++++
>  docs/qemu-qmp-ref.texi        | 156 ++++++++++++++++++++++++++++++++++++++++++
>  docs/qmp-intro.txt            |  87 -----------------------
>  docs/writing-qmp-commands.txt |   2 +-
>  4 files changed, 222 insertions(+), 88 deletions(-)
>  create mode 100644 docs/qemu-ga-ref.texi
>  create mode 100644 docs/qemu-qmp-ref.texi
>  delete mode 100644 docs/qmp-intro.txt
>
> diff --git a/docs/qemu-ga-ref.texi b/docs/qemu-ga-ref.texi
> new file mode 100644
> index 0000000..ad90712
> --- /dev/null
> +++ b/docs/qemu-ga-ref.texi
> @@ -0,0 +1,65 @@
> +\input texinfo
> +@setfilename qemu-ga-ref.info
> +
> +@exampleindent 0
> +@paragraphindent 0
> +
> +@settitle QEMU Guest Agent Protocol Reference
> +
> +@copying
> +This is the QEMU Guest Agent Protocol reference manual.
> +
> +Copyright @copyright{} 2016 The QEMU Project developers

Need something on permissions, because without, we don't grant any.
Since much of the contents comes from existing files without an explicit
license notice, I guess we need to stick to GPLv2+.  Here's my try,
patterned after the notice carried by "The Debian Administrator's
Handbook"[*]:

   @quotation

   This manual is free documentation: you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation, either version 2 of the
   License, or (at your option) any later version.

   This manual is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this manual.  If not, see http://www.gnu.org/licenses/.
   @end quotation

> +@end copying
> +
> +@ifinfo
> +@dircategory QEMU
> +@direntry
> +* QEMU-GA-Ref: (qemu-ga-ref).   QEMU Guest Agent Protocol Reference
> +@end direntry
> +@end ifinfo

I don't think the redundant @ifinfo buys us anything.

> +
> +@titlepage
> +@title Guest Agent Protocol Reference Manual
> +@subtitle QEMU version @value{VERSION}
> +@page
> +@vskip 0pt plus 1filll
> +@insertcopying
> +@end titlepage
> +
> +@contents
> +
> +@ifnottex
> +@node Top
> +@top QEMU Guest Agent protocol reference
> +@end ifnottex
> +
> +@menu
> +* API Reference::
> +* Commands and Events Index::
> +* Data Types Index::
> +@end menu
> +
> +@node API Reference
> +@chapter API Reference
> +
> +@c for texi2pod:
> +@c man begin DESCRIPTION
> +
> +@include qemu-ga-qapi.texi
> +
> +@c man end
> +
> +@c man begin SEEALSO
> +The HTML documentation of QEMU for more information.
> +@c man end
> +
> +@node Commands and Events Index
> +@unnumbered Commands and Events Index
> +@printindex fn
> +
> +@node Data Types Index
> +@unnumbered Data Types Index
> +@printindex tp
> +
> +@bye
> diff --git a/docs/qemu-qmp-ref.texi b/docs/qemu-qmp-ref.texi
> new file mode 100644
> index 0000000..c1740ae
> --- /dev/null
> +++ b/docs/qemu-qmp-ref.texi
> @@ -0,0 +1,156 @@

Comments on the previous file apply.

> +\input texinfo
> +@setfilename qemu-qmp-ref.info
> +
> +@exampleindent 0
> +@paragraphindent 0
> +
> +@settitle QEMU QMP Reference Manual
> +
> +@copying
> +This is the QEMU QMP reference manual.
> +
> +Copyright @copyright{} 2016 The QEMU Project developers
> +@end copying
> +
> +@ifinfo
> +@dircategory QEMU
> +@direntry
> +* QEMU-QMP-Ref: (qemu-qmp-ref). QEMU QMP Reference Manual
> +@end direntry
> +@end ifinfo
> +
> +@titlepage
> +@title QMP Reference Manual
> +@subtitle QEMU version @value{VERSION}
> +@page
> +@vskip 0pt plus 1filll
> +@insertcopying
> +@end titlepage
> +
> +@contents
> +
> +@ifnottex
> +@node Top
> +@top QEMU QMP reference
> +@end ifnottex
> +
> +@menu
> +* Introduction::
> +* API Reference::
> +* Commands and Events Index::
> +* Data Types Index::
> +@end menu
[Skipping chapter Introduction...]
> +@node API Reference
> +@chapter API Reference
> +
> +@c for texi2pod:
> +@c man begin DESCRIPTION
> +
> +@include qemu-qapi.texi
> +
> +@c man end
> +
> +@c man begin SEEALSO
> +The HTML documentation of QEMU for more precise information.
> +@c man end
> +
> +@node Commands and Events Index
> +@unnumbered Commands and Events Index
> +@printindex fn
> +
> +@node Data Types Index
> +@unnumbered Data Types Index
> +@printindex tp
> +
> +@bye
> diff --git a/docs/qmp-intro.txt b/docs/qmp-intro.txt
> deleted file mode 100644
> index f6a3a03..0000000
> --- a/docs/qmp-intro.txt
> +++ /dev/null
[Skipping...]
> diff --git a/docs/writing-qmp-commands.txt b/docs/writing-qmp-commands.txt
> index 44c14db..de54977 100644
> --- a/docs/writing-qmp-commands.txt
> +++ b/docs/writing-qmp-commands.txt
[Skipping...]


[*] https://www.debian.org/doc/manuals/debian-handbook/

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [Qemu-devel] [PATCH v3 11/14] qapi: add qapi2texi script
  2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 11/14] qapi: add qapi2texi script Marc-André Lureau
@ 2016-11-10 16:37   ` Markus Armbruster
  2016-11-15 17:17     ` Marc-André Lureau
  0 siblings, 1 reply; 28+ messages in thread
From: Markus Armbruster @ 2016-11-10 16:37 UTC (permalink / raw)
  To: Marc-André Lureau; +Cc: qemu-devel

Marc-André Lureau <marcandre.lureau@redhat.com> writes:

> As the name suggests, the qapi2texi script converts JSON QAPI
> description into a texi file suitable for different target
> formats (info/man/txt/pdf/html...).
>
> It parses the following kind of blocks:
>
> Free-form:
>
>   ##
>   # = Section
>   # == Subsection
>   #
>   # Some text foo with *emphasis*
>   # 1. with a list
>   # 2. like that
>   #
>   # And some code:
>   # | $ echo foo
>   # | -> do this
>   # | <- get that
>   #
>   ##
>
> Symbol:
>
>   ##
>   # @symbol:
>   #
>   # Symbol body ditto ergo sum. Foo bar
>   # baz ding.
>   #
>   # @arg: foo
>   # @arg: #optional foo
>   #
>   # Returns: returns bla bla
>   #          Or bla blah
>   #
>   # Since: version
>   # Notes: notes, comments can have
>   #        - itemized list
>   #        - like this
>   #
>   # Example:
>   #
>   # -> { "execute": "quit" }
>   # <- { "return": {} }
>   #
>   ##

The following discussion belongs to review of qapi-code-gen.txt, but the
example here is more abstract and nicely visible, so let me use it.

The "Symbol" kind of block as shown above is for QMP commands with
arguments defined inline.

It also serves for QMP events: just omit the return value.

For struct types, the terminology is a bit off ("argument" instead of
"member"), but the basic structure less the return value still works.
No surprise, because a command is essentially a triple (name, arguments
type, return value type), where the arguments type is a struct type (but
see below for non-struct arguments).

>From there, it's a small step to using it for enum types.

But how to do union types is non-obvious.  In their general form, they
have common members, one of them the tag, and variant members depending
on the tag value.  How do we want such types be documented?

Alternate types can be documented like structs, I think.

What about QMP commands with arguments of the form 'data': 'TypeName'?
We typically replace the whole @arg: part by something like

    # For the arguments, see the documentation of BlockdevSnapshotSync.

Note that with 'boxed': true, TypeName could even be union or alternate.

My point is: the documentation needs work.  Whether we should do the
within this series or on top is debatable.

> That's roughly following the following BNF grammar:

EBNF, actually.

>
> api_comment = "##\n" comment "##\n"
> comment = freeform_comment | symbol_comment
> freeform_comment = { "#" text "\n" }

As we'll see below, your code actually requires at least one space after
"#" unless text is empty.

> symbol_comment = "#" "@" name ":\n" { freeform | member | meta }

Your code actually requires exactly one space between "#" and "@".  It
happily accepts additional text between : and newline.

freeform is undefined.  I guess you mean freeform_comment.

With that corrected, the grammar is ambiguous.  Your intent is obvious
enough, though.  Just not to a computer.

> member = "#" '@' name ':' [ text ] freeform_comment

Again, your code requires exactly one space after "#".

> meta = "#" ( "Returns:", "Since:", "Note:", "Notes:", "Example:", "Examples:" ) [ text ] freeform_comment

Likewise.

> text = free-text markdown-like, "#optional" for members

Here, the grammar switches from EBNF to prose.

As is, the grammar can serve as semi-formal user documentation.  It
can't quite serve as specification for the parser.  As we'll see below,
the code processing doc strings is not a parser constructed from this
grammar.

Why am I so hung up on constructing parsers systematically from
grammars?  When you do that, you can derive the accepted language from
the *grammar*.  Generally *much* easier than from ad hoc parser code.
Moreover, a (sufficiently simple) grammar leads to a natural internal
representation, namely an abstract syntax tree.

But let's continue.

> Thanks to the following json expressions, the documentation is enhanced
> with extra information about the type of arguments and return value
> expected.

What exactly do you want to convey with this sentence?

> Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> ---
>  scripts/qapi.py        | 175 ++++++++++++++++++++++++++-
>  scripts/qapi2texi.py   | 316 +++++++++++++++++++++++++++++++++++++++++++++++++
>  docs/qapi-code-gen.txt |  44 +++++--
>  3 files changed, 524 insertions(+), 11 deletions(-)
>  create mode 100755 scripts/qapi2texi.py
>
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index 21bc32f..ed52ee4 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py

Warning: loads of comments ahead.  Doesn't mean there are loads of
problems!  I need to write to think clearly, and I'm sharing my thinking
to hopefully help us converge.

> @@ -122,6 +122,103 @@ class QAPIExprError(Exception):
>              "%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
>  
>  
> +class QAPIDoc(object):
> +    def __init__(self, parser):
> +        self.parser = parser
> +        self.symbol = None
> +        self.body = []
> +        # args is {'arg': 'doc', ...}

Rather terse, but I think I get what you mean.

> +        self.args = OrderedDict()
> +        # meta is [(Since/Notes/Examples/Returns:, 'doc'), ...]

More so.

> +        self.meta = []
> +        # the current section to populate, array of [dict, key, comment...]

Now you've reached my limit :)

"array of [...]" sounds like a list of lists.  But you probably mean
just a list.

We'll see below that dict is either self.args or self.meta, and key is a
key in dict.

> +        self.section = None
> +        self.expr_elem = None
> +
> +    def get_body(self):
> +        return "\n".join(self.body)

Not worth a doc string?  The existing code doesn't have any, but since
you provide them for other public methods of this class...

> +
> +    def has_meta(self, name):
> +        """Returns True if the doc has a meta section 'name'"""
> +        return next((True for i in self.meta if i[0] == name), False)

Less clever, but probably more obvious to readers lacking a degree in
Python generators:

           for i in self.meta:
               if i[0] == name:
                   return True
           return False

I'm not against using more advanced language features, but when the
"advanced" code needs more tokens than the "retarded" one...

> +
> +    def append(self, line):
> +        """Adds a # comment line, to be parsed and added in a section"""
> +        line = line[1:]

As we'll see below, @line is the full comment token text including the
initial '#', but not including the final '\n'.  First thing we do with
it is strip the initial '#'.  Makes me wonder why we pass it in.  It's
not wrong, of course.

Note that comments don't need to be full lines, they just happen to be
used that way most of the time.  Admittedly contrived counter-example:

    { 'enum': 'Empty', 'data': [] } ##
                                    # @XY:
                                    ##
    { 'enum': 'XY', 'data': ['x', 'y'] }

This makes the parser call doc.append("# @XY:").  The argument "# @XY:"
isn't a full line in the source.  It becomes a line in the documentation
text QAPIDoc wraps.

> +        if len(line) == 0:
> +            self._append_section(line)
> +            return

Special case for comment '#'.  Note that '# ' is processed as a normal
case.

> +
> +        if line[0] != ' ':
> +            raise QAPISchemaError(self.parser, "missing space after #")
> +
> +        line = line[1:]
> +        # take the first word out
> +        name = line.split(' ', 1)[0]

For a comment '# ', @name becomes '', because ''.split(' ', 1) returns
[''].  Works.

For a comment '#  Since:' (note two spaces), name becomes '', because
.split() returns ['', 'Since:'].  Thus, the keywords are only recognized
exactly after '# '.  Is this a good idea?

> +        if name.startswith("@") and name.endswith(":"):
> +            line = line[len(name):]
> +            name = name[1:-1]
> +            if self.symbol is None:
> +                # the first is the symbol this APIDoc object documents

Suggest

                   # The first @NAME: is the symbol being documented

> +                if len(self.body):
> +                    raise QAPISchemaError(self.parser, "symbol must come first")

You and I know what 'symbol' means here, but the user should not need to
know.  Suggest something like "'@%s:' must come first".  I'm not
entirely happy with that either, but I don't have better ideas right
now.

If the parser was constructed from your grammar, we'd deal with the
first @NAME: not coming first differently.  According to the grammar, a
doc comment block either starts with '##\n# @' (a symbol block), or it
doesn't (a free-form block).  If the first line isn't a @NAME: line, but
later lines are, the parser decides it's a free-from block right there.
Any @NAME: lines it finds later would be parsed as free-form line.  If
we want to reject such lines in free-form blocks, the easiest way would
be a semantic check.

> +                self.symbol = name

Here's how we can tell what kind of block we're working on:

if .symbol is not None:
    this is a symbol block
elif .body is not None:
    this is a free-form block
else
    we don't know, yet

> +            else:
> +                # else an arg

Suggest
                   # Subsequent @NAME: are arguments and such

> +                self._start_args_section(name)

The remainder of the line after @NAME: is left in @line, and will be
stuffed into the current section or else the body after the conditional.
That's what the grammar specifies for argument NAME, in rule member.
It's not what it specifies for symbol NAME, in rule symbol_comment.

In particular, when nothing follows symbol NAME, we still stuff '' into
the body.  For instance,

    ##
    # @symbol:
    # 
    # lorem ipsum
    ##

produces self.body = ['', '', 'lorem ipsum'], which .get_body()
transforms into '\n\nlorem ipsum'.  Extra newline.  I guess it's all the
same to Texinfo in the end.

> +        elif self.symbol and name in (
> +                "Returns:", "Since:",
> +                # those are often singular or plural
> +                "Note:", "Notes:",
> +                "Example:", "Examples:"):
> +            # new "meta" section
> +            line = line[len(name):]
> +            self._start_meta_section(name[:-1])
> +
> +        self._append_section(line)
> +
> +    def _start_args_section(self, name):
> +        self.end_section()
> +        if self.args.has_key(name):
> +            raise QAPISchemaError(self.parser, "'%s' arg duplicated" % name)

Where's self.args[name] added?  Oh, I see, it's hidden in end_section().
Could it be added here instead?

> +        self.section = [self.args, name]
> +
> +    def _start_meta_section(self, name):
> +        self.end_section()
> +        if name in ("Returns", "Since") and self.has_meta(name):
> +            raise QAPISchemaError(self.parser, "'%s' section duplicated" % name)

For the implementation, it's a section, but for the user, it's a line.
Suggest "Duplicate '%s'".

Comment on _start_args_section() applies.

> +        self.section = [self.meta, name]
> +
> +    def _append_section(self, line):
> +        """Add a comment to the current section, or the comment body"""

_append_to_section() or _section_append() would be clearer.  We're not
appending a section, we're appending *to* a section.  Or to the body,
which isn't a section.  Hmm.

> +        if self.section:
> +            name = self.section[1]
> +            if not name.startswith("Example"):
> +                # an empty line ends the section, except with Example
> +                if len(self.section) > 2 and len(line) == 0:
> +                    self.end_section()
> +                    return
> +                # Example is verbatim
> +                line = line.strip()

The comment is confusing, because it explains what we're not doing
elsewhere.  Comments should explain what we're doing here.

> +            if len(line) > 0:
> +                self.section.append(line)
> +        else:
> +            self.body.append(line.strip())
> +
> +    def end_section(self):
> +        if self.section is not None:

I prefer the more laconic "if self.section:", especially when
self.section can't have a false value other than None anyway.  Even more
I prefer making the fact that this does nothing when we don't have a
section immediately obvious:

           if not self.section:
               return
           do the work...

> +            target = self.section[0]
> +            name = self.section[1]
> +            if len(self.section) < 3:
> +                raise QAPISchemaError(self.parser, "Empty doc section")
> +            doc = "\n".join(self.section[2:])
> +            if isinstance(target, dict):
> +                target[name] = doc
> +            else:
> +                target.append((name, doc))
> +            self.section = None

Until the next _start_FOO_section(), self.section remains None.
Therefore, any text between here and the next section will be appended
to self.body.  This is going to mangle input that doesn't quite match
expectations.  Example:

    ##
    # @frobnicate:
    #
    # Frobnicate some frobs.
    #
    # @frobs: bla, bla, explain @frobs,
    #         bla.
    #
    #         Beware of the tiger!
    #
    #         Explain @frobs some more, bla, bla.
    #
    # @harder: frobnicate harder.
    ##
    { 'command': 'frobnicate',
      'data': { 'frobs': 'any', '*harder': 'bool' } }

Results in a QAPIDoc with

    .symbol = 'frobnicate'
    .args = { 'frobs': 'frobs bla, bla, explain,\nbla',
              'harder': 'frobnicate harder.' }
    .body = ['', '', 'Frobnicate some frobs.', '',
             'Beware of the tiger!', '',
             'Explain some more, bla, bla.', '']

and the following .texi:

    @deftypefn Command {} frobnicate @
    {('frobs': @var{any}, ['harder': @var{bool}])}

    @table @var
    @item frobs
    bla, bla, explain @var{frobs},
    bla.
    @item harder
    frobnicate harder.
    @end table


    Frobnicate some frobs.

    Beware of the tiger!

    Explain @var{frobs} some more, bla, bla.

The only way to detect the mistake is to read the generated
documentation attentively.  We can't rely on everybody doing that during
development.  Even when you do, the mangled output gives you no clue on
the mistake you made, unless you know how the doc generator works.

The generator could detect the mistake at the syntactical or at the
semantic level.

More general question: can you think of a legitimate reason for the
generator emitting documentation in a different order than it was
written?

If no, we should pick an internal representation that can represent the
input we have / envisage to have faithfully, then reject input it can't
represent faithfully.

> +
> +
>  class QAPISchemaParser(object):
>  
>      def __init__(self, fp, previously_included=[], incl_info=None):
> @@ -137,9 +234,15 @@ class QAPISchemaParser(object):

Let's see how parsing works.

>          self.line = 1
>          self.line_pos = 0
>          self.exprs = []
> +        self.docs = []
>          self.accept()
>  
>          while self.tok is not None:
> +            if self.tok == '#' and self.val.startswith('##'):
> +                doc = self.get_doc()
> +                self.docs.append(doc)
> +                continue
> +

Top-level doc comments get accumulated in list self.docs.

>              expr_info = {'file': fname, 'line': self.line,
>                           'parent': self.incl_info}
>              expr = self.get_expr(False)
> @@ -160,6 +263,7 @@ class QAPISchemaParser(object):
>                          raise QAPIExprError(expr_info, "Inclusion loop for %s"
>                                              % include)
>                      inf = inf['parent']
> +
>                  # skip multiple include of the same file
>                  if incl_abs_fname in previously_included:
>                      continue
> @@ -171,12 +275,40 @@ class QAPISchemaParser(object):
>                  exprs_include = QAPISchemaParser(fobj, previously_included,
>                                                   expr_info)
>                  self.exprs.extend(exprs_include.exprs)
> +                self.docs.extend(exprs_include.docs)

The include's list of docs are spliced in.

>              else:
>                  expr_elem = {'expr': expr,
>                               'info': expr_info}
> +                if len(self.docs) > 0:
> +                    self.docs[-1].expr_elem = expr_elem
>                  self.exprs.append(expr_elem)

A non-include expression gets tied to the last doc comment.  This isn't
quite right.  Example:

    ##
    # @Empty:
    ##
    { 'enum': 'Empty', 'data': [] }

    { 'enum': 'XY', 'data': ['x', 'y'] }

The doc comment's expr_elem gets first set to the first enum expression,
then overwritten with the second one.

Less serious, but still somewhat weird:

    ##
    # Lorem ipsum
    ##

    # @Empty:
    { 'enum': 'Empty', 'data': [] }

The first comment block is a doc comment.  The second one isn't, and
gets ignored.  The first one's expr_elem gets set to the enum
expression.

The quick fix is to set .expr_elem only when it's still None.

The thorough fix is to integrate doc comments deeper into the syntax.

>  
> -    def accept(self):
> +    def get_doc(self):

Here, we know self.tok == '#', and self.val is thus the comment line
less the newline (see accept()).

> +        if self.val != '##':
> +            raise QAPISchemaError(self, "Doc comment not starting with '##'")

It starts with '##' alright, it just happens not to end there.  What
about "Junk after '##'"?  Or, if that's too laconic, perhaps "Junk after
'##' at start of documentation comment".

> +
> +        doc = QAPIDoc(self)
> +        self.accept(False)
> +        while self.tok == '#':
> +            if self.val.startswith('##'):
> +                # ## ends doc

"# ##" looks awkward.  Suggest

                   # End of doc comment

> +                if self.val != '##':
> +                    raise QAPISchemaError(self, "non-empty '##' line %s"
> +                                          % self.val)

Let's make the message similar to whatever message we emit for junk
after the initial ##.

> +                self.accept()
> +                doc.end_section()
> +                return doc
> +            else:
> +                doc.append(self.val)
> +            self.accept(False)
> +

Here, self.tok is whatever follows the doc comment.

> +        if self.val != '##':
> +            raise QAPISchemaError(self, "Doc comment not finishing with '##'")

This check is incorrect.  For instance, input

    ##
    '## gotcha'

yields

    /dev/stdin:2:1: Doc comment not finishing with '##'

because self.tok == "'" and self.val == "## gotcha".

Either fail unconditionally here (then the final ## is required), or do
nothing (then it's optional).  Your commit message suggests the former.

> +
> +        doc.end_section()
> +        return doc
> +
> +    def accept(self, skip_comment=True):
>          while True:
>              self.tok = self.src[self.cursor]
>              self.pos = self.cursor
> @@ -184,7 +316,13 @@ class QAPISchemaParser(object):
>              self.val = None
>  
>              if self.tok == '#':
> +                if self.src[self.cursor] == '#':
> +                    # ## starts a doc comment

Suggest

                       # Start of doc comment

> +                    skip_comment = False
>                  self.cursor = self.src.find('\n', self.cursor)
> +                self.val = self.src[self.pos:self.cursor]

Puts the complete line less the newline into self.val.  I wonder whether
we should strip the initial '#' as well.

> +                if not skip_comment:
> +                    return

Make that

                   if not skip_comment:
                       self.val = self.src[self.pos:self.cursor]
                       return

>              elif self.tok in "{}:,[]":
>                  return
>              elif self.tok == "'":

Comment tokens are thrown away as before, except when the parser asks
for them by passing skip_comment=False, or when the comment token starts
with ##.  The parser asks while parsing a doc comment, in get_doc().

This is a backchannel from the parser to the lexer.  I'd rather avoid
such lexer hacks, but I guess we can address that on top.

A comment starting with ## inside an expression is now a syntax error.
For instance, input

    {
    ##

yields

    /dev/stdin:2:1: Expected string or "}"

Rather unfriendly error message, but we can fix that on top.

> @@ -779,6 +917,41 @@ def check_exprs(exprs):
>  
>      return exprs
>  
> +def check_docs(docs):
> +    for doc in docs:
> +        expr_elem = doc.expr_elem
> +        if not expr_elem:
> +            continue

A symbol block without an expr_elem should be an error, shouldn't it?

> +
> +        expr = expr_elem['expr']
> +        for i in ('enum', 'union', 'alternate', 'struct', 'command', 'event'):
> +            if i in expr:
> +                meta = i
> +                break

We're working with expression trees here, not the QAPISchemaEntity
objects.  Okay as long as the work is sufficiently trivial.

> +
> +        info = expr_elem['info']
> +        name = expr[meta]
> +        if doc.symbol != name:
> +            raise QAPIExprError(info,
> +                                "Documentation symbol mismatch '%s' != '%s'"
> +                                % (doc.symbol, name))

Cryptic.  Suggest "Definition of '%s' follows documentation for '%s'" %
(name, doc.symbol).

> +        if not 'command' in expr and doc.has_meta('Returns'):
> +            raise QAPIExprError(info, "Invalid return documentation")
> +
> +        doc_args = set(doc.args.keys())

doc_args is the set of documented argument names.  Actually member names
when expr defines a type, but let's ignore that for now.

> +        if meta == 'union':
> +            data = expr.get('base', [])
> +        else:
> +            data = expr.get('data', [])
> +        if isinstance(data, dict):
> +            data = data.keys()
> +        args = set([k.strip('*') for k in data])

Suggest to rename k to name.

To see what args is, we first need to figure out what data is.

If expr defines an enum, expr['data'] is the list of of member names.
args is the set of member names.

If expr defines a struct type, expr['data'] is the OrderedDict mapping
local member names with optional '*' prefix to types.  args is the set
of local member names.  "Local", because additional members may be
inherited from a base type.

If expr defines an alternate type, likewise, except there should be no
'*' prefixes and no base type.

If expr defines a simple union type, expr['data'] is the OrderedDict
mapping tag value names to types.  The tag member is implicit.
expr['base'] should not exist.  args is therefore the empty set.

If expr defines a flat union type, data is the OrderedDict mapping tag
value names to types.  expr['base'] must exist, and is either a
dictionary or the name of a struct type.  If it's a dictionary, args is
the set of common members defined inline.  If it's a struct type name,
args is the set of characters in the type name.  Oops.  Test case: union
UserDefFlatUnion in qapi-schema-test.json.

Aside: covering all cases correctly is not trivial enough for expression
trees, I'm afraid.  Class QAPISchema has to do it.  Can we avoid
duplicating its logic here?  I'm not sure; the QAPISchemaEntity might
turn out to be just differently inconvenient.

If expr defines a command, data is either the OrderedDict mapping
argument names to types, or the name of the arguments type.  If it's a
dictionary, args is the set of argument names.  If it's a type name,
args is the set of characters in the type name.  Oops again.  Test case:
command user_def_cmd0 in qapi-schema-test.json.

If expr defines an event, likewise.  No test case in
qapi-schema-test.json.  Hole in the test coverage.

Conclusion: args is meant to be the set of arguments / members actually
defined.  For unions, that does *not* include variant members.

> +        if meta == 'alternate' or \
> +           (meta == 'union' and not expr.get('discriminator')):
> +            args.add('type')

For alternate and simple union types, add 'type' to the set of arguments
actually defined.

Recall that the set contains the member names for alternates, and
nothing for simple unions.

> +        if not doc_args.issubset(args):

Could use the <= operator: if not doc_args <= args.  Matter of taste.

> +            raise QAPIExprError(info, "Members documentation is not a subset of"
> +                                " API %r > %r" % (list(doc_args), list(args)))

Errors out if the doc string documents arguments that aren't actually
defined as far as we know.

"As far as we know", because we second-guess what's actually defined
based on the expression tree, and don't get all the cases right.  The
actual actual definitions are determined by class QAPISchema, and can be
found in its internal representation.  Hmm.

Failing to document an argument is not an error.  It probably should be,
at least in the longer run.

>  
>  #
>  # Schema compiler frontend
> diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
> new file mode 100755
> index 0000000..7e2440c
> --- /dev/null
> +++ b/scripts/qapi2texi.py

Considering the length of this review so far, I'm only skimming
generator part for now.

> @@ -0,0 +1,316 @@
> +#!/usr/bin/env python
> +# QAPI texi generator
> +#
> +# This work is licensed under the terms of the GNU LGPL, version 2+.
> +# See the COPYING file in the top-level directory.
> +"""This script produces the documentation of a qapi schema in texinfo format"""
> +import re
> +import sys
> +
> +from qapi import *
> +
> +COMMAND_FMT = """
> +@deftypefn {type} {{{ret}}} {name} @
> +{{{args}}}
> +
> +{body}
> +
> +@end deftypefn
> +
> +""".format
> +
> +ENUM_FMT = """
> +@deftp Enum {name}
> +
> +{body}
> +
> +@end deftp
> +
> +""".format
> +
> +STRUCT_FMT = """
> +@deftp {type} {name} @
> +{{{attrs}}}
> +
> +{body}
> +
> +@end deftp
> +
> +""".format
> +
> +EXAMPLE_FMT = """@example
> +{code}
> +@end example
> +""".format
> +
> +
> +def subst_strong(doc):
> +    """Replaces *foo* by @strong{foo}"""
> +    return re.sub(r'\*([^_\n]+)\*', r'@emph{\1}', doc)
> +
> +
> +def subst_emph(doc):
> +    """Replaces _foo_ by @emph{foo}"""
> +    return re.sub(r'\s_([^_\n]+)_\s', r' @emph{\1} ', doc)
> +
> +
> +def subst_vars(doc):
> +    """Replaces @var by @var{var}"""
> +    return re.sub(r'@([\w-]+)', r'@var{\1}', doc)
> +
> +
> +def subst_braces(doc):
> +    """Replaces {} with @{ @}"""
> +    return doc.replace("{", "@{").replace("}", "@}")
> +
> +
> +def texi_example(doc):
> +    """Format @example"""
> +    doc = subst_braces(doc).strip('\n')
> +    return EXAMPLE_FMT(code=doc)
> +
> +
> +def texi_comment(doc):
> +    """
> +    Format a comment
> +
> +    Lines starting with:
> +    - |: generates an @example
> +    - =: generates @section
> +    - ==: generates @subsection
> +    - 1. or 1): generates an @enumerate @item
> +    - o/*/-: generates an @itemize list
> +    """
> +    lines = []
> +    doc = subst_braces(doc)
> +    doc = subst_vars(doc)
> +    doc = subst_emph(doc)
> +    doc = subst_strong(doc)
> +    inlist = ""
> +    lastempty = False
> +    for line in doc.split('\n'):
> +        empty = line == ""
> +
> +        if line.startswith("| "):
> +            line = EXAMPLE_FMT(code=line[1:])
> +        elif line.startswith("= "):
> +            line = "@section " + line[1:]
> +        elif line.startswith("== "):
> +            line = "@subsection " + line[2:]
> +        elif re.match("^([0-9]*[.)]) ", line):
> +            if not inlist:
> +                lines.append("@enumerate")
> +                inlist = "enumerate"
> +            line = line[line.find(" ")+1:]
> +            lines.append("@item")
> +        elif re.match("^[o*-] ", line):
> +            if not inlist:
> +                lines.append("@itemize %s" % {'o': "@bullet",
> +                                              '*': "@minus",
> +                                              '-': ""}[line[0]])
> +                inlist = "itemize"
> +            lines.append("@item")
> +            line = line[2:]
> +        elif lastempty and inlist:
> +            lines.append("@end %s\n" % inlist)
> +            inlist = ""
> +
> +        lastempty = empty
> +        lines.append(line)
> +
> +    if inlist:
> +        lines.append("@end %s\n" % inlist)
> +    return "\n".join(lines)
> +
> +
> +def texi_args(expr):
> +    """
> +    Format the functions/structure/events.. arguments/members
> +    """
> +    data = expr["data"] if "data" in expr else {}
> +    if isinstance(data, str):
> +        args = data
> +    else:
> +        arg_list = []
> +        for name, typ in data.iteritems():
> +            # optional arg
> +            if name.startswith("*"):
> +                name = name[1:]
> +                arg_list.append("['%s': @var{%s}]" % (name, typ))
> +            # regular arg
> +            else:
> +                arg_list.append("'%s': @var{%s}" % (name, typ))
> +        args = ", ".join(arg_list)
> +    return args
> +
> +def section_order(section):
> +    return {"Returns": 0,
> +            "Note": 1,
> +            "Notes": 1,
> +            "Since": 2,
> +            "Example": 3,
> +            "Examples": 3}[section]
> +
> +def texi_body(doc, arg="@var"):
> +    """
> +    Format the body of a symbol documentation:
> +    - a table of arguments
> +    - followed by "Returns/Notes/Since/Example" sections
> +    """
> +    body = "@table %s\n" % arg
> +    for arg, desc in doc.args.iteritems():
> +        if desc.startswith("#optional"):
> +            desc = desc[10:]
> +            arg += "*"
> +        elif desc.endswith("#optional"):
> +            desc = desc[:-10]
> +            arg += "*"
> +        body += "@item %s\n%s\n" % (arg, texi_comment(desc))
> +    body += "@end table\n"
> +    body += texi_comment(doc.get_body())
> +
> +    meta = sorted(doc.meta, key=lambda i: section_order(i[0]))
> +    for m in meta:
> +        key, doc = m
> +        func = texi_comment
> +        if key.startswith("Example"):
> +            func = texi_example
> +
> +        body += "\n@quotation %s\n%s\n@end quotation" % \
> +                (key, func(doc))
> +    return body
> +
> +
> +def texi_alternate(expr, doc):
> +    """
> +    Format an alternate to texi
> +    """
> +    args = texi_args(expr)
> +    body = texi_body(doc)
> +    return STRUCT_FMT(type="Alternate",
> +                      name=doc.symbol,
> +                      attrs="[ " + args + " ]",
> +                      body=body)
> +
> +
> +def texi_union(expr, doc):
> +    """
> +    Format an union to texi
> +    """
> +    args = texi_args(expr)
> +    body = texi_body(doc)
> +    return STRUCT_FMT(type="Union",
> +                      name=doc.symbol,
> +                      attrs="[ " + args + " ]",
> +                      body=body)
> +
> +
> +def texi_enum(_, doc):
> +    """
> +    Format an enum to texi
> +    """
> +    body = texi_body(doc, "@samp")
> +    return ENUM_FMT(name=doc.symbol,
> +                    body=body)
> +
> +
> +def texi_struct(expr, doc):
> +    """
> +    Format a struct to texi
> +    """
> +    args = texi_args(expr)
> +    body = texi_body(doc)
> +    return STRUCT_FMT(type="Struct",
> +                      name=doc.symbol,
> +                      attrs="@{ " + args + " @}",
> +                      body=body)
> +
> +
> +def texi_command(expr, doc):
> +    """
> +    Format a command to texi
> +    """
> +    args = texi_args(expr)
> +    ret = expr["returns"] if "returns" in expr else ""
> +    body = texi_body(doc)
> +    return COMMAND_FMT(type="Command",
> +                       name=doc.symbol,
> +                       ret=ret,
> +                       args="(" + args + ")",
> +                       body=body)
> +
> +
> +def texi_event(expr, doc):
> +    """
> +    Format an event to texi
> +    """
> +    args = texi_args(expr)
> +    body = texi_body(doc)
> +    return COMMAND_FMT(type="Event",
> +                       name=doc.symbol,
> +                       ret="",
> +                       args="(" + args + ")",
> +                       body=body)
> +
> +
> +def texi(docs):
> +    """
> +    Convert QAPI schema expressions to texi documentation
> +    """
> +    res = []
> +    for doc in docs:
> +        try:
> +            expr_elem = doc.expr_elem
> +            if expr_elem is None:
> +                res.append(texi_body(doc))
> +                continue
> +
> +            expr = expr_elem['expr']
> +            (kind, _) = expr.items()[0]
> +
> +            fmt = {"command": texi_command,
> +                   "struct": texi_struct,
> +                   "enum": texi_enum,
> +                   "union": texi_union,
> +                   "alternate": texi_alternate,
> +                   "event": texi_event}
> +            try:
> +                fmt = fmt[kind]
> +            except KeyError:
> +                raise ValueError("Unknown expression kind '%s'" % kind)
> +            res.append(fmt(expr, doc))
> +        except:
> +            print >>sys.stderr, "error at @%s" % qapi
> +            raise

What errors do you expect here?  I'm asking because catching exceptions
indiscrimatingly feels problematic.

> +
> +    return '\n'.join(res)
> +
> +
> +def parse_schema(fname):
> +    """
> +    Parse the given schema file and return the exprs
> +    """
> +    try:
> +        schema = QAPISchemaParser(open(fname, "r"))
> +        check_exprs(schema.exprs)
> +        check_docs(schema.docs)
> +        return schema.docs

You don't actually "return the exprs", you return a list of QAPIDoc.

Either return schema and let the caller retrieve its .docs, or rename
the function to parse_docs().  In either case, fix up the doc string.

> +    except (QAPISchemaError, QAPIExprError), err:
> +        print >>sys.stderr, err
> +        exit(1)

The function duplicates parts of QAPISchema.__init__().  The parts it
doesn't duplicate would be useful here, because without them, you might
be working on a broken schema.

Recommend to drop the function, and ...

> +
> +
> +def main(argv):
> +    """
> +    Takes schema argument, prints result to stdout
> +    """
> +    if len(argv) != 2:
> +        print >>sys.stderr, "%s: need exactly 1 argument: SCHEMA" % argv[0]
> +        sys.exit(1)
> +
> +    docs = parse_schema(argv[1])

... instead do

       schema = QAPISchema(argv[1])
       docs = schema.docs

with the obvious patch to make docs an attribute of schema:

diff --git a/scripts/qapi.py b/scripts/qapi.py
index ed52ee4..b17e7de 100644
--- a/scripts/qapi.py
+++ b/scripts/qapi.py
@@ -1424,7 +1424,9 @@ class QAPISchemaEvent(QAPISchemaEntity):
 class QAPISchema(object):
     def __init__(self, fname):
         try:
-            self.exprs = check_exprs(QAPISchemaParser(open(fname, "r")).exprs)
+            parser = QAPISchemaParser(open(fname, "r"))
+            self.exprs = check_exprs(parser.exprs)
+            self.docs = parser.docs
             self._entity_dict = {}
             self._predefining = True
             self._def_predefineds()

You don't use the common parse_command_line().  Probably the right
choice right now, as reusing it would require modifications (we have no
use for -c and -h at least), and wouldn't buy us much.

> +    print texi(docs)
> +
> +
> +if __name__ == "__main__":
> +    main(sys.argv)

Ignorant question: why is this __name__ == "__main__" raindance better
than the stupid way the qapi-{commands,event,introspect,types,visit}.py
work?

> diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
> index 2841c51..d82e251 100644
> --- a/docs/qapi-code-gen.txt
> +++ b/docs/qapi-code-gen.txt
> @@ -45,16 +45,13 @@ QAPI parser does not).  At present, there is no place where a QAPI
>  schema requires the use of JSON numbers or null.
>  
>  Comments are allowed; anything between an unquoted # and the following
> -newline is ignored.  Although there is not yet a documentation
> -generator, a form of stylized comments has developed for consistently
> -documenting details about an expression and when it was added to the
> -schema.  The documentation is delimited between two lines of ##, then
> -the first line names the expression, an optional overview is provided,
> -then individual documentation about each member of 'data' is provided,
> -and finally, a 'Since: x.y.z' tag lists the release that introduced
> -the expression.  Optional members are tagged with the phrase
> -'#optional', often with their default value; and extensions added
> -after the expression was first released are also given a '(since
> +newline is ignored.  The documentation is delimited between two lines
> +of ##, then the first line names the expression, an optional overview
> +is provided, then individual documentation about each member of 'data'
> +is provided, and finally, a 'Since: x.y.z' tag lists the release that
> +introduced the expression.  Optional members are tagged with the
> +phrase '#optional', often with their default value; and extensions
> +added after the expression was first released are also given a '(since
>  x.y.z)' comment.  For example:
>  
>      ##
> @@ -73,12 +70,39 @@ x.y.z)' comment.  For example:
>      #           (Since 2.0)
>      #
>      # Since: 0.14.0
> +    #
> +    # Notes: You can also make a list:
> +    #        - with items
> +    #        - like this
> +    #
> +    # Example:
> +    #
> +    # -> { "execute": ... }
> +    # <- { "return": ... }

Err, 'BlockStats' is a *type*, not a command.

> +    #
>      ##
>      { 'struct': 'BlockStats',
>        'data': {'*device': 'str', 'stats': 'BlockDeviceStats',
>                 '*parent': 'BlockStats',
>                 '*backing': 'BlockStats'} }
>  
> +It's also possible to create documentation sections, such as:
> +
> +    ##
> +    # = Section
> +    # == Subsection
> +    #
> +    # Some text foo with *emphasis*
> +    # 1. with a list
> +    # 2. like that
> +    #
> +    # And some code:
> +    # | $ echo foo
> +    # | -> do this
> +    # | <- get that
> +    #
> +    ##
> +

This suggests various kinds of markup, including section headers,
emphasis, numbered lists.  But what exactly is recognized?

>  The schema sets up a series of types, as well as commands and events
>  that will use those types.  Forward references are allowed: the parser
>  scans in two passes, where the first pass learns all type names, and

As discussed in my review of the cover letter, we have some additional
documentation work to do.

Also missing: tests.  A first cut should have a negative test for each
error qapi2texi.py can report, plus a modest suite of positive tests.  A
negative test consists of tests/qapi-schema/NAME.{json,out,err,exit}.
Positive tests can be added to tests/qapi-schema/qapi-schema-test.json,
or to a separate test schema, in case that's more convenient.

To get the most mileage out of positive tests, test-qapi.py should be
extended to show the resulting QAPIDoc.  Sketch appended.

diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
index ef74e2c..93cc709 100644
--- a/tests/qapi-schema/test-qapi.py
+++ b/tests/qapi-schema/test-qapi.py
@@ -55,3 +55,13 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
 
 schema = QAPISchema(sys.argv[1])
 schema.visit(QAPISchemaTestVisitor())
+
+for doc in schema.docs:
+    expr_elem = doc.expr_elem
+    expr_info = expr_elem and expr_elem['info']
+    print 'doc %s %s' % (doc.symbol, expr_info)
+    for arg, text in doc.args.iteritems():
+        print '    arg=%s %s' % (arg, text)
+    for key, text in doc.meta:
+        print '    meta %s %s' % (key, text)
+    print '    body=%s' % doc.body

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [Qemu-devel] [PATCH v3 11/14] qapi: add qapi2texi script
  2016-11-10 16:37   ` Markus Armbruster
@ 2016-11-15 17:17     ` Marc-André Lureau
  0 siblings, 0 replies; 28+ messages in thread
From: Marc-André Lureau @ 2016-11-15 17:17 UTC (permalink / raw)
  To: Markus Armbruster; +Cc: qemu-devel

Hi

On Thu, Nov 10, 2016 at 9:32 PM Markus Armbruster <armbru@redhat.com> wrote:

> Marc-André Lureau <marcandre.lureau@redhat.com> writes:
>
> > As the name suggests, the qapi2texi script converts JSON QAPI
> > description into a texi file suitable for different target
> > formats (info/man/txt/pdf/html...).
> >
> > It parses the following kind of blocks:
> >
> > Free-form:
> >
> >   ##
> >   # = Section
> >   # == Subsection
> >   #
> >   # Some text foo with *emphasis*
> >   # 1. with a list
> >   # 2. like that
> >   #
> >   # And some code:
> >   # | $ echo foo
> >   # | -> do this
> >   # | <- get that
> >   #
> >   ##
> >
> > Symbol:
> >
> >   ##
> >   # @symbol:
> >   #
> >   # Symbol body ditto ergo sum. Foo bar
> >   # baz ding.
> >   #
> >   # @arg: foo
> >   # @arg: #optional foo
> >   #
> >   # Returns: returns bla bla
> >   #          Or bla blah
> >   #
> >   # Since: version
> >   # Notes: notes, comments can have
> >   #        - itemized list
> >   #        - like this
> >   #
> >   # Example:
> >   #
> >   # -> { "execute": "quit" }
> >   # <- { "return": {} }
> >   #
> >   ##
>
> The following discussion belongs to review of qapi-code-gen.txt, but the
> example here is more abstract and nicely visible, so let me use it.
>
> The "Symbol" kind of block as shown above is for QMP commands with
> arguments defined inline.
>
> It also serves for QMP events: just omit the return value.
>
> For struct types, the terminology is a bit off ("argument" instead of
> "member"), but the basic structure less the return value still works.
> No surprise, because a command is essentially a triple (name, arguments
> type, return value type), where the arguments type is a struct type (but
> see below for non-struct arguments).
>

Yeah, I stick with args for now, but we may want to rename it to
member/fields. Other suggestions?

>
> From there, it's a small step to using it for enum types.
>

Right, I realize it may be nice to enumerate the values, even if they are
not documented. I have made some changes in this direction in the generator.


> But how to do union types is non-obvious.  In their general form, they
> have common members, one of them the tag, and variant members depending
> on the tag value.  How do we want such types be documented?
>

Fair enough, union types are quite badly documented by current version of
generator. I have made some changes, so 'base' arguments and 'data'
alternative are shown that way:

BlockdevOptions (Union)

{ 'driver': BlockdevDriver, ['node-name': str], ['discard':
BlockdevDiscardOptions], ['cache': BlockdevCacheOptions], ['read-only':
bool], ['detect-zeroes': BlockdevDetectZeroesOptions] } + 'driver' = [
'archipelago': BlockdevOptionsArchipelago, 'blkdebug':
BlockdevOptionsBlkdebug,....



> Alternate types can be documented like structs, I think.
>

mostly, I have used the [] syntax to represent union & alternatives
(instead of {}). I hope that helps.


>
> What about QMP commands with arguments of the form 'data': 'TypeName'?
> We typically replace the whole @arg: part by something like
>
>     # For the arguments, see the documentation of BlockdevSnapshotSync.
>
> Note that with 'boxed': true, TypeName could even be union or alternate.
>
> My point is: the documentation needs work.  Whether we should do the
> within this series or on top is debatable.
>

I'd rather fix it on top, that series is already pretty large and dense,
and hopefully is a good starting point.

>
> > That's roughly following the following BNF grammar:
>
> EBNF, actually.
>
>
ok

>
> > api_comment = "##\n" comment "##\n"
> > comment = freeform_comment | symbol_comment
> > freeform_comment = { "#" text "\n" }
>
> As we'll see below, your code actually requires at least one space after
> "#" unless text is empty.
>

ok


> > symbol_comment = "#" "@" name ":\n" { freeform | member | meta }
>
> Your code actually requires exactly one space between "#" and "@".  It
> happily accepts additional text between : and newline.
>
> freeform is undefined.  I guess you mean freeform_comment.
>

ok


> With that corrected, the grammar is ambiguous.  Your intent is obvious
> enough, though.  Just not to a computer.
>
> > member = "#" '@' name ':' [ text ] freeform_comment
>
> Again, your code requires exactly one space after "#".
>
> > meta = "#" ( "Returns:", "Since:", "Note:", "Notes:", "Example:",
> "Examples:" ) [ text ] freeform_comment
>
> Likewise.
>

ok


> > text = free-text markdown-like, "#optional" for members
>
> Here, the grammar switches from EBNF to prose.
>
> As is, the grammar can serve as semi-formal user documentation.  It
> can't quite serve as specification for the parser.  As we'll see below,
> the code processing doc strings is not a parser constructed from this
> grammar.
>
> Why am I so hung up on constructing parsers systematically from
> grammars?  When you do that, you can derive the accepted language from
> the *grammar*.  Generally *much* easier than from ad hoc parser code.
> Moreover, a (sufficiently simple) grammar leads to a natural internal
> representation, namely an abstract syntax tree.
>
> But let's continue.
>
> > Thanks to the following json expressions, the documentation is enhanced
> > with extra information about the type of arguments and return value
> > expected.
>
> What exactly do you want to convey with this sentence?
>

Not much, that we use the json expressions to enhance the written doc.


>
> > Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
> > ---
> >  scripts/qapi.py        | 175 ++++++++++++++++++++++++++-
> >  scripts/qapi2texi.py   | 316
> +++++++++++++++++++++++++++++++++++++++++++++++++
> >  docs/qapi-code-gen.txt |  44 +++++--
> >  3 files changed, 524 insertions(+), 11 deletions(-)
> >  create mode 100755 scripts/qapi2texi.py
> >
> > diff --git a/scripts/qapi.py b/scripts/qapi.py
> > index 21bc32f..ed52ee4 100644
> > --- a/scripts/qapi.py
> > +++ b/scripts/qapi.py
>
> Warning: loads of comments ahead.  Doesn't mean there are loads of
> problems!  I need to write to think clearly, and I'm sharing my thinking
> to hopefully help us converge.
>
>
ok :)


> > @@ -122,6 +122,103 @@ class QAPIExprError(Exception):
> >              "%s:%d: %s" % (self.info['file'], self.info['line'],
> self.msg)
> >
> >
> > +class QAPIDoc(object):
> > +    def __init__(self, parser):
> > +        self.parser = parser
> > +        self.symbol = None
> > +        self.body = []
> > +        # args is {'arg': 'doc', ...}
>
> Rather terse, but I think I get what you mean.
>
> > +        self.args = OrderedDict()
> > +        # meta is [(Since/Notes/Examples/Returns:, 'doc'), ...]
>
> More so.
>
> > +        self.meta = []
> > +        # the current section to populate, array of [dict, key,
> comment...]
>
> Now you've reached my limit :)
>
> "array of [...]" sounds like a list of lists.  But you probably mean
> just a list.
>
> We'll see below that dict is either self.args or self.meta, and key is a
> key in dict.
>

I have introduced a nested Section class, hopefull that helps a bit


> > +        self.section = None
> > +        self.expr_elem = None
> > +
> > +    def get_body(self):
> > +        return "\n".join(self.body)
>
> Not worth a doc string?  The existing code doesn't have any, but since
> you provide them for other public methods of this class...
>
>
Not all of them, get_body() and end_section() seem rather obvious to me,
doc string could be redundant.

> +
> > +    def has_meta(self, name):
> > +        """Returns True if the doc has a meta section 'name'"""
> > +        return next((True for i in self.meta if i[0] == name), False)
>
> Less clever, but probably more obvious to readers lacking a degree in
> Python generators:
>
>            for i in self.meta:
>                if i[0] == name:
>                    return True
>            return False
>
> I'm not against using more advanced language features, but when the
> "advanced" code needs more tokens than the "retarded" one...
>

agree (I think I had something else in mind when I started writing that
line)


>
> > +
> > +    def append(self, line):
> > +        """Adds a # comment line, to be parsed and added in a section"""
> > +        line = line[1:]
>
> As we'll see below, @line is the full comment token text including the
> initial '#', but not including the final '\n'.  First thing we do with
> it is strip the initial '#'.  Makes me wonder why we pass it in.  It's
> not wrong, of course.
>
>
I don't see much point in changing this either


> Note that comments don't need to be full lines, they just happen to be
> used that way most of the time.  Admittedly contrived counter-example:
>
>     { 'enum': 'Empty', 'data': [] } ##
>                                     # @XY:
>                                     ##
>     { 'enum': 'XY', 'data': ['x', 'y'] }
>
> This makes the parser call doc.append("# @XY:").  The argument "# @XY:"
> isn't a full line in the source.  It becomes a line in the documentation
> text QAPIDoc wraps.
>
> > +        if len(line) == 0:
> > +            self._append_section(line)
> > +            return
>
> Special case for comment '#'.  Note that '# ' is processed as a normal
> case.
>
> > +
> > +        if line[0] != ' ':
> > +            raise QAPISchemaError(self.parser, "missing space after #")
> > +
> > +        line = line[1:]
> > +        # take the first word out
> > +        name = line.split(' ', 1)[0]
>
> For a comment '# ', @name becomes '', because ''.split(' ', 1) returns
> [''].  Works.
>
> For a comment '#  Since:' (note two spaces), name becomes '', because
> .split() returns ['', 'Since:'].  Thus, the keywords are only recognized
> exactly after '# '.  Is this a good idea?
>

Good for consistency, and there might be cases where arg version/note
documentation could legitimately (for now) look like:

##
# @foo:
# @arg: bla blah
#           Since: 2.8
##

> +        if name.startswith("@") and name.endswith(":"):
> > +            line = line[len(name):]
> > +            name = name[1:-1]
> > +            if self.symbol is None:
> > +                # the first is the symbol this APIDoc object documents
>
> Suggest
>
>                    # The first @NAME: is the symbol being documented
>

ok


>
> > +                if len(self.body):
> > +                    raise QAPISchemaError(self.parser, "symbol must
> come first")
>
> You and I know what 'symbol' means here, but the user should not need to
> know.  Suggest something like "'@%s:' must come first".  I'm not
> entirely happy with that either, but I don't have better ideas right
> now.
>

ok


>
> If the parser was constructed from your grammar, we'd deal with the
> first @NAME: not coming first differently.  According to the grammar, a
> doc comment block either starts with '##\n# @' (a symbol block), or it
> doesn't (a free-form block).  If the first line isn't a @NAME: line, but
> later lines are, the parser decides it's a free-from block right there.
> Any @NAME: lines it finds later would be parsed as free-form line.  If
> we want to reject such lines in free-form blocks, the easiest way would
> be a semantic check.
>

Ok, I'll move it do check_docs()

> +                self.symbol = name
>
> Here's how we can tell what kind of block we're working on:
>
> if .symbol is not None:
>     this is a symbol block
> elif .body is not None:
>     this is a free-form block
> else
>     we don't know, yet
>


ok, I have adapted it slightly to avoid some redundancy in the "we don't
know" and "free-form" cases


> > +            else:
> > +                # else an arg
>
> Suggest
>                    # Subsequent @NAME: are arguments and such
>

This goes away with above refactoring, since we know we are parsing args


>
> > +                self._start_args_section(name)
>
> The remainder of the line after @NAME: is left in @line, and will be
> stuffed into the current section or else the body after the conditional.
> That's what the grammar specifies for argument NAME, in rule member.
> It's not what it specifies for symbol NAME, in rule symbol_comment.
>
> In particular, when nothing follows symbol NAME, we still stuff '' into
> the body.  For instance,
>
>     ##
>     # @symbol:
>     #
>     # lorem ipsum
>     ##
>
> produces self.body = ['', '', 'lorem ipsum'], which .get_body()
> transforms into '\n\nlorem ipsum'.  Extra newline.  I guess it's all the
> same to Texinfo in the end.
>

Ok, let's make sure the first @symbol: doesn't contain extra characters.


>
> > +        elif self.symbol and name in (
> > +                "Returns:", "Since:",
> > +                # those are often singular or plural
> > +                "Note:", "Notes:",
> > +                "Example:", "Examples:"):
> > +            # new "meta" section
> > +            line = line[len(name):]
> > +            self._start_meta_section(name[:-1])
> > +
> > +        self._append_section(line)
> > +
> > +    def _start_args_section(self, name):
> > +        self.end_section()
> > +        if self.args.has_key(name):
> > +            raise QAPISchemaError(self.parser, "'%s' arg duplicated" %
> name)
>
> Where's self.args[name] added?  Oh, I see, it's hidden in end_section().
> Could it be added here instead?
>

How? self.args[name] = "" which will be overwritten in end_section? ok


>
> > +        self.section = [self.args, name]
> > +
> > +    def _start_meta_section(self, name):
> > +        self.end_section()
> > +        if name in ("Returns", "Since") and self.has_meta(name):
> > +            raise QAPISchemaError(self.parser, "'%s' section
> duplicated" % name)
>
> For the implementation, it's a section, but for the user, it's a line.
> Suggest "Duplicate '%s'".
>
> Comment on _start_args_section() applies.
>

ok


> > +        self.section = [self.meta, name]
> > +
> > +    def _append_section(self, line):
> > +        """Add a comment to the current section, or the comment body"""
>
> _append_to_section() or _section_append() would be clearer.  We're not
> appending a section, we're appending *to* a section.  Or to the body,
> which isn't a section.  Hmm.
>

ok, what about _append_freeform() ?

>
> > +        if self.section:
> > +            name = self.section[1]
> > +            if not name.startswith("Example"):
> > +                # an empty line ends the section, except with Example
> > +                if len(self.section) > 2 and len(line) == 0:
> > +                    self.end_section()
> > +                    return
> > +                # Example is verbatim
> > +                line = line.strip()
>
> The comment is confusing, because it explains what we're not doing
> elsewhere.  Comments should explain what we're doing here.
>
>
ok, I'll remove it


> > +            if len(line) > 0:
> > +                self.section.append(line)
> > +        else:
> > +            self.body.append(line.strip())
> > +
> > +    def end_section(self):
> > +        if self.section is not None:
>
> I prefer the more laconic "if self.section:", especially when
> self.section can't have a false value other than None anyway.  Even more
> I prefer making the fact that this does nothing when we don't have a
> section immediately obvious:
>
>            if not self.section:
>                return
>            do the work...
>
>
ok


> > +            target = self.section[0]
> > +            name = self.section[1]
> > +            if len(self.section) < 3:
> > +                raise QAPISchemaError(self.parser, "Empty doc section")
> > +            doc = "\n".join(self.section[2:])
> > +            if isinstance(target, dict):
> > +                target[name] = doc
> > +            else:
> > +                target.append((name, doc))
> > +            self.section = None
>
> Until the next _start_FOO_section(), self.section remains None.
> Therefore, any text between here and the next section will be appended
> to self.body.  This is going to mangle input that doesn't quite match
> expectations.  Example:
>
>     ##
>     # @frobnicate:
>     #
>     # Frobnicate some frobs.
>     #
>     # @frobs: bla, bla, explain @frobs,
>     #         bla.
>     #
>     #         Beware of the tiger!
>     #
>     #         Explain @frobs some more, bla, bla.
>     #
>     # @harder: frobnicate harder.
>     ##
>     { 'command': 'frobnicate',
>       'data': { 'frobs': 'any', '*harder': 'bool' } }
>
> Results in a QAPIDoc with
>
>     .symbol = 'frobnicate'
>     .args = { 'frobs': 'frobs bla, bla, explain,\nbla',
>               'harder': 'frobnicate harder.' }
>     .body = ['', '', 'Frobnicate some frobs.', '',
>              'Beware of the tiger!', '',
>              'Explain some more, bla, bla.', '']
>
> and the following .texi:
>
>     @deftypefn Command {} frobnicate @
>     {('frobs': @var{any}, ['harder': @var{bool}])}
>
>     @table @var
>     @item frobs
>     bla, bla, explain @var{frobs},
>     bla.
>     @item harder
>     frobnicate harder.
>     @end table
>
>
>     Frobnicate some frobs.
>
>     Beware of the tiger!
>
>     Explain @var{frobs} some more, bla, bla.
>
> The only way to detect the mistake is to read the generated
> documentation attentively.  We can't rely on everybody doing that during
> development.  Even when you do, the mangled output gives you no clue on
> the mistake you made, unless you know how the doc generator works.
>
> The generator could detect the mistake at the syntactical or at the
> semantic level.
>

I have changed the logic there, since in general paragraphs are indented
with @arg sections like your example above. So an empty line will no longer
break the current section, only an empty line followed by a non-indented
paragraph after an argument documentation will. That is

@foo: arg doc

Blah

Will break the argument section on "Blah", and append it to the
documentation body.

This fixes real doc issues from previous iterations, see @block-commit for
example.

More general question: can you think of a legitimate reason for the
> generator emitting documentation in a different order than it was
> written?
>

It would be nicer if the generator can freely reorder/display the
documentation, for consistency and style (different blocks could use
different style etc).


>
> If no, we should pick an internal representation that can represent the
> input we have / envisage to have faithfully, then reject input it can't
> represent faithfully.
>
> > +
> > +
> >  class QAPISchemaParser(object):
> >
> >      def __init__(self, fp, previously_included=[], incl_info=None):
> > @@ -137,9 +234,15 @@ class QAPISchemaParser(object):
>
> Let's see how parsing works.
>
> >          self.line = 1
> >          self.line_pos = 0
> >          self.exprs = []
> > +        self.docs = []
> >          self.accept()
> >
> >          while self.tok is not None:
> > +            if self.tok == '#' and self.val.startswith('##'):
> > +                doc = self.get_doc()
> > +                self.docs.append(doc)
> > +                continue
> > +
>
> Top-level doc comments get accumulated in list self.docs.
>
> >              expr_info = {'file': fname, 'line': self.line,
> >                           'parent': self.incl_info}
> >              expr = self.get_expr(False)
> > @@ -160,6 +263,7 @@ class QAPISchemaParser(object):
> >                          raise QAPIExprError(expr_info, "Inclusion loop
> for %s"
> >                                              % include)
> >                      inf = inf['parent']
> > +
> >                  # skip multiple include of the same file
> >                  if incl_abs_fname in previously_included:
> >                      continue
> > @@ -171,12 +275,40 @@ class QAPISchemaParser(object):
> >                  exprs_include = QAPISchemaParser(fobj,
> previously_included,
> >                                                   expr_info)
> >                  self.exprs.extend(exprs_include.exprs)
> > +                self.docs.extend(exprs_include.docs)
>
> The include's list of docs are spliced in.
>
> >              else:
> >                  expr_elem = {'expr': expr,
> >                               'info': expr_info}
> > +                if len(self.docs) > 0:
> > +                    self.docs[-1].expr_elem = expr_elem
> >                  self.exprs.append(expr_elem)
>
> A non-include expression gets tied to the last doc comment.  This isn't
> quite right.  Example:
>
>     ##
>     # @Empty:
>     ##
>     { 'enum': 'Empty', 'data': [] }
>
>     { 'enum': 'XY', 'data': ['x', 'y'] }
>
> The doc comment's expr_elem gets first set to the first enum expression,
> then overwritten with the second one.
>

good catch, regression from last iteration


> Less serious, but still somewhat weird:
>
>     ##
>     # Lorem ipsum
>     ##
>
>     # @Empty:
>     { 'enum': 'Empty', 'data': [] }
>
> The first comment block is a doc comment.  The second one isn't, and
> gets ignored.  The first one's expr_elem gets set to the enum
> expression.
>
> The quick fix is to set .expr_elem only when it's still None.
>
> I'll take the quick fix


> The thorough fix is to integrate doc comments deeper into the syntax.
>
>
as you know, my initial goal was not to bring a strict doc parser (many doc
parser are not that strict and work well enough), rather to just generate
something good enough out of the json to get rid of txt duplication.
Further improvements can be made after this series hopefully.


> >
> > -    def accept(self):
> > +    def get_doc(self):
>
> Here, we know self.tok == '#', and self.val is thus the comment line
> less the newline (see accept()).
>
> > +        if self.val != '##':
> > +            raise QAPISchemaError(self, "Doc comment not starting with
> '##'")
>
> It starts with '##' alright, it just happens not to end there.  What
> about "Junk after '##'"?  Or, if that's too laconic, perhaps "Junk after
> '##' at start of documentation comment".
>

ok


> > +
> > +        doc = QAPIDoc(self)
> > +        self.accept(False)
> > +        while self.tok == '#':
> > +            if self.val.startswith('##'):
> > +                # ## ends doc
>
> "# ##" looks awkward.  Suggest
>
>                    # End of doc comment
>
>
ok


> > +                if self.val != '##':
> > +                    raise QAPISchemaError(self, "non-empty '##' line %s"
> > +                                          % self.val)
>
> Let's make the message similar to whatever message we emit for junk
> after the initial ##.
>

ok


>
> > +                self.accept()
> > +                doc.end_section()
> > +                return doc
> > +            else:
> > +                doc.append(self.val)
> > +            self.accept(False)
> > +
>
> Here, self.tok is whatever follows the doc comment.
>
> > +        if self.val != '##':
> > +            raise QAPISchemaError(self, "Doc comment not finishing with
> '##'")
>
> This check is incorrect.  For instance, input
>
>     ##
>     '## gotcha'
>
> yields
>
>     /dev/stdin:2:1: Doc comment not finishing with '##'
>
> because self.tok == "'" and self.val == "## gotcha".
>
> Either fail unconditionally here (then the final ## is required), or do
> nothing (then it's optional).  Your commit message suggests the former.
>
> ok


> > +
> > +        doc.end_section()
> > +        return doc
> > +
> > +    def accept(self, skip_comment=True):
> >          while True:
> >              self.tok = self.src[self.cursor]
> >              self.pos = self.cursor
> > @@ -184,7 +316,13 @@ class QAPISchemaParser(object):
> >              self.val = None
> >
> >              if self.tok == '#':
> > +                if self.src[self.cursor] == '#':
> > +                    # ## starts a doc comment
>
> Suggest
>
>                        # Start of doc comment
>
>
ok


> > +                    skip_comment = False
> >                  self.cursor = self.src.find('\n', self.cursor)
> > +                self.val = self.src[self.pos:self.cursor]
>
> Puts the complete line less the newline into self.val.  I wonder whether
> we should strip the initial '#' as well.
>
> > +                if not skip_comment:
> > +                    return
>
> Make that
>
>                    if not skip_comment:
>                        self.val = self.src[self.pos:self.cursor]
>                        return
>
> ok


> >              elif self.tok in "{}:,[]":
> >                  return
> >              elif self.tok == "'":
>
> Comment tokens are thrown away as before, except when the parser asks
> for them by passing skip_comment=False, or when the comment token starts
> with ##.  The parser asks while parsing a doc comment, in get_doc().
>
> This is a backchannel from the parser to the lexer.  I'd rather avoid
> such lexer hacks, but I guess we can address that on top.
>
>
Alternative I imagine is to return comments from the lexer, I don't mind if
you prefer it that way, let me know

A comment starting with ## inside an expression is now a syntax error.
> For instance, input
>
>     {
>     ##
>
> yields
>
>     /dev/stdin:2:1: Expected string or "}"
>
> Rather unfriendly error message, but we can fix that on top.
>
> > @@ -779,6 +917,41 @@ def check_exprs(exprs):
> >
> >      return exprs
> >
> > +def check_docs(docs):
> > +    for doc in docs:
> > +        expr_elem = doc.expr_elem
> > +        if not expr_elem:
> > +            continue
>
> A symbol block without an expr_elem should be an error, shouldn't it?
>
>
I don't think we want to make comments mandatory, for tests at least. I
have move the check to check_exprs() and added a 'strict_doc' argument only
set when generating doc.

> +
> > +        expr = expr_elem['expr']
> > +        for i in ('enum', 'union', 'alternate', 'struct', 'command',
> 'event'):
> > +            if i in expr:
> > +                meta = i
> > +                break
>
> We're working with expression trees here, not the QAPISchemaEntity
> objects.  Okay as long as the work is sufficiently trivial.
>
> > +
> > +        info = expr_elem['info']
> > +        name = expr[meta]
> > +        if doc.symbol != name:
> > +            raise QAPIExprError(info,
> > +                                "Documentation symbol mismatch '%s' !=
> '%s'"
> > +                                % (doc.symbol, name))
>
> Cryptic.  Suggest "Definition of '%s' follows documentation for '%s'" %
> (name, doc.symbol).
>

ok


>
> > +        if not 'command' in expr and doc.has_meta('Returns'):
> > +            raise QAPIExprError(info, "Invalid return documentation")
> > +
> > +        doc_args = set(doc.args.keys())
>
> doc_args is the set of documented argument names.  Actually member names
> when expr defines a type, but let's ignore that for now.
>
> > +        if meta == 'union':
> > +            data = expr.get('base', [])
> > +        else:
> > +            data = expr.get('data', [])
> > +        if isinstance(data, dict):
> > +            data = data.keys()
> > +        args = set([k.strip('*') for k in data])
>
> Suggest to rename k to name.
>
> ok


> To see what args is, we first need to figure out what data is.
>
> If expr defines an enum, expr['data'] is the list of of member names.
> args is the set of member names.
>
> If expr defines a struct type, expr['data'] is the OrderedDict mapping
> local member names with optional '*' prefix to types.  args is the set
> of local member names.  "Local", because additional members may be
> inherited from a base type.
>
> If expr defines an alternate type, likewise, except there should be no
> '*' prefixes and no base type.
>
> If expr defines a simple union type, expr['data'] is the OrderedDict
> mapping tag value names to types.  The tag member is implicit.
> expr['base'] should not exist.  args is therefore the empty set.
>
> If expr defines a flat union type, data is the OrderedDict mapping tag
> value names to types.  expr['base'] must exist, and is either a
> dictionary or the name of a struct type.  If it's a dictionary, args is
> the set of common members defined inline.  If it's a struct type name,
> args is the set of characters in the type name.  Oops.  Test case: union
> UserDefFlatUnion in qapi-schema-test.json.
>
> Aside: covering all cases correctly is not trivial enough for expression
> trees, I'm afraid.  Class QAPISchema has to do it.  Can we avoid
> duplicating its logic here?  I'm not sure; the QAPISchemaEntity might
> turn out to be just differently inconvenient.
>
> If expr defines a command, data is either the OrderedDict mapping
> argument names to types, or the name of the arguments type.  If it's a
> dictionary, args is the set of argument names.  If it's a type name,
> args is the set of characters in the type name.  Oops again.  Test case:
> command user_def_cmd0 in qapi-schema-test.json.
>

Do those have real use cases in the schema? If not, could we ignore or not
support them?


>
> If expr defines an event, likewise.  No test case in
> qapi-schema-test.json.  Hole in the test coverage.
>
> Conclusion: args is meant to be the set of arguments / members actually
> defined.  For unions, that does *not* include variant members.
>

I understand there is a lot of missing cases, but since they don't seem to
be reached, can we leave this for a future improvement? Someone more
familiar with QAPI details could help me here :)


> > +        if meta == 'alternate' or \
> > +           (meta == 'union' and not expr.get('discriminator')):
> > +            args.add('type')
>
> For alternate and simple union types, add 'type' to the set of arguments
> actually defined.
>
> Recall that the set contains the member names for alternates, and
> nothing for simple unions.
>
> > +        if not doc_args.issubset(args):
>
> Could use the <= operator: if not doc_args <= args.  Matter of taste.
>
> > +            raise QAPIExprError(info, "Members documentation is not a
> subset of"
> > +                                " API %r > %r" % (list(doc_args),
> list(args)))
>
> Errors out if the doc string documents arguments that aren't actually
> defined as far as we know.
>
> "As far as we know", because we second-guess what's actually defined
> based on the expression tree, and don't get all the cases right.  The
> actual actual definitions are determined by class QAPISchema, and can be
> found in its internal representation.  Hmm.
>


I guess this can be later improved by using lookup_entity()?


> Failing to document an argument is not an error.  It probably should be,
> at least in the longer run.
>

Eventually, since we have total control of the documentation. But in
practice, arguments can be quite obvious and people tend to not document
them, I wouldn't be so strict.

>
> >  #
> >  # Schema compiler frontend
> > diff --git a/scripts/qapi2texi.py b/scripts/qapi2texi.py
> > new file mode 100755
> > index 0000000..7e2440c
> > --- /dev/null
> > +++ b/scripts/qapi2texi.py
>
> Considering the length of this review so far, I'm only skimming
> generator part for now.
>
>
thanks ;)


> > @@ -0,0 +1,316 @@
> > +#!/usr/bin/env python
> > +# QAPI texi generator
> > +#
> > +# This work is licensed under the terms of the GNU LGPL, version 2+.
> > +# See the COPYING file in the top-level directory.
> > +"""This script produces the documentation of a qapi schema in texinfo
> format"""
> > +import re
> > +import sys
> > +
> > +from qapi import *
> > +
> > +COMMAND_FMT = """
> > +@deftypefn {type} {{{ret}}} {name} @
> > +{{{args}}}
> > +
> > +{body}
> > +
> > +@end deftypefn
> > +
> > +""".format
> > +
> > +ENUM_FMT = """
> > +@deftp Enum {name}
> > +
> > +{body}
> > +
> > +@end deftp
> > +
> > +""".format
> > +
> > +STRUCT_FMT = """
> > +@deftp {type} {name} @
> > +{{{attrs}}}
> > +
> > +{body}
> > +
> > +@end deftp
> > +
> > +""".format
> > +
> > +EXAMPLE_FMT = """@example
> > +{code}
> > +@end example
> > +""".format
> > +
> > +
> > +def subst_strong(doc):
> > +    """Replaces *foo* by @strong{foo}"""
> > +    return re.sub(r'\*([^_\n]+)\*', r'@emph{\1}', doc)
> > +
> > +
> > +def subst_emph(doc):
> > +    """Replaces _foo_ by @emph{foo}"""
> > +    return re.sub(r'\s_([^_\n]+)_\s', r' @emph{\1} ', doc)
> > +
> > +
> > +def subst_vars(doc):
> > +    """Replaces @var by @var{var}"""
> > +    return re.sub(r'@([\w-]+)', r'@var{\1}', doc)
> > +
> > +
> > +def subst_braces(doc):
> > +    """Replaces {} with @{ @}"""
> > +    return doc.replace("{", "@{").replace("}", "@}")
> > +
> > +
> > +def texi_example(doc):
> > +    """Format @example"""
> > +    doc = subst_braces(doc).strip('\n')
> > +    return EXAMPLE_FMT(code=doc)
> > +
> > +
> > +def texi_comment(doc):
> > +    """
> > +    Format a comment
> > +
> > +    Lines starting with:
> > +    - |: generates an @example
> > +    - =: generates @section
> > +    - ==: generates @subsection
> > +    - 1. or 1): generates an @enumerate @item
> > +    - o/*/-: generates an @itemize list
> > +    """
> > +    lines = []
> > +    doc = subst_braces(doc)
> > +    doc = subst_vars(doc)
> > +    doc = subst_emph(doc)
> > +    doc = subst_strong(doc)
> > +    inlist = ""
> > +    lastempty = False
> > +    for line in doc.split('\n'):
> > +        empty = line == ""
> > +
> > +        if line.startswith("| "):
> > +            line = EXAMPLE_FMT(code=line[1:])
> > +        elif line.startswith("= "):
> > +            line = "@section " + line[1:]
> > +        elif line.startswith("== "):
> > +            line = "@subsection " + line[2:]
> > +        elif re.match("^([0-9]*[.)]) ", line):
> > +            if not inlist:
> > +                lines.append("@enumerate")
> > +                inlist = "enumerate"
> > +            line = line[line.find(" ")+1:]
> > +            lines.append("@item")
> > +        elif re.match("^[o*-] ", line):
> > +            if not inlist:
> > +                lines.append("@itemize %s" % {'o': "@bullet",
> > +                                              '*': "@minus",
> > +                                              '-': ""}[line[0]])
> > +                inlist = "itemize"
> > +            lines.append("@item")
> > +            line = line[2:]
> > +        elif lastempty and inlist:
> > +            lines.append("@end %s\n" % inlist)
> > +            inlist = ""
> > +
> > +        lastempty = empty
> > +        lines.append(line)
> > +
> > +    if inlist:
> > +        lines.append("@end %s\n" % inlist)
> > +    return "\n".join(lines)
> > +
> > +
> > +def texi_args(expr):
> > +    """
> > +    Format the functions/structure/events.. arguments/members
> > +    """
> > +    data = expr["data"] if "data" in expr else {}
> > +    if isinstance(data, str):
> > +        args = data
> > +    else:
> > +        arg_list = []
> > +        for name, typ in data.iteritems():
> > +            # optional arg
> > +            if name.startswith("*"):
> > +                name = name[1:]
> > +                arg_list.append("['%s': @var{%s}]" % (name, typ))
> > +            # regular arg
> > +            else:
> > +                arg_list.append("'%s': @var{%s}" % (name, typ))
> > +        args = ", ".join(arg_list)
> > +    return args
> > +
> > +def section_order(section):
> > +    return {"Returns": 0,
> > +            "Note": 1,
> > +            "Notes": 1,
> > +            "Since": 2,
> > +            "Example": 3,
> > +            "Examples": 3}[section]
> > +
> > +def texi_body(doc, arg="@var"):
> > +    """
> > +    Format the body of a symbol documentation:
> > +    - a table of arguments
> > +    - followed by "Returns/Notes/Since/Example" sections
> > +    """
> > +    body = "@table %s\n" % arg
> > +    for arg, desc in doc.args.iteritems():
> > +        if desc.startswith("#optional"):
> > +            desc = desc[10:]
> > +            arg += "*"
> > +        elif desc.endswith("#optional"):
> > +            desc = desc[:-10]
> > +            arg += "*"
> > +        body += "@item %s\n%s\n" % (arg, texi_comment(desc))
> > +    body += "@end table\n"
> > +    body += texi_comment(doc.get_body())
> > +
> > +    meta = sorted(doc.meta, key=lambda i: section_order(i[0]))
> > +    for m in meta:
> > +        key, doc = m
> > +        func = texi_comment
> > +        if key.startswith("Example"):
> > +            func = texi_example
> > +
> > +        body += "\n@quotation %s\n%s\n@end quotation" % \
> > +                (key, func(doc))
> > +    return body
> > +
> > +
> > +def texi_alternate(expr, doc):
> > +    """
> > +    Format an alternate to texi
> > +    """
> > +    args = texi_args(expr)
> > +    body = texi_body(doc)
> > +    return STRUCT_FMT(type="Alternate",
> > +                      name=doc.symbol,
> > +                      attrs="[ " + args + " ]",
> > +                      body=body)
> > +
> > +
> > +def texi_union(expr, doc):
> > +    """
> > +    Format an union to texi
> > +    """
> > +    args = texi_args(expr)
> > +    body = texi_body(doc)
> > +    return STRUCT_FMT(type="Union",
> > +                      name=doc.symbol,
> > +                      attrs="[ " + args + " ]",
> > +                      body=body)
> > +
> > +
> > +def texi_enum(_, doc):
> > +    """
> > +    Format an enum to texi
> > +    """
> > +    body = texi_body(doc, "@samp")
> > +    return ENUM_FMT(name=doc.symbol,
> > +                    body=body)
> > +
> > +
> > +def texi_struct(expr, doc):
> > +    """
> > +    Format a struct to texi
> > +    """
> > +    args = texi_args(expr)
> > +    body = texi_body(doc)
> > +    return STRUCT_FMT(type="Struct",
> > +                      name=doc.symbol,
> > +                      attrs="@{ " + args + " @}",
> > +                      body=body)
> > +
> > +
> > +def texi_command(expr, doc):
> > +    """
> > +    Format a command to texi
> > +    """
> > +    args = texi_args(expr)
> > +    ret = expr["returns"] if "returns" in expr else ""
> > +    body = texi_body(doc)
> > +    return COMMAND_FMT(type="Command",
> > +                       name=doc.symbol,
> > +                       ret=ret,
> > +                       args="(" + args + ")",
> > +                       body=body)
> > +
> > +
> > +def texi_event(expr, doc):
> > +    """
> > +    Format an event to texi
> > +    """
> > +    args = texi_args(expr)
> > +    body = texi_body(doc)
> > +    return COMMAND_FMT(type="Event",
> > +                       name=doc.symbol,
> > +                       ret="",
> > +                       args="(" + args + ")",
> > +                       body=body)
> > +
> > +
> > +def texi(docs):
> > +    """
> > +    Convert QAPI schema expressions to texi documentation
> > +    """
> > +    res = []
> > +    for doc in docs:
> > +        try:
> > +            expr_elem = doc.expr_elem
> > +            if expr_elem is None:
> > +                res.append(texi_body(doc))
> > +                continue
> > +
> > +            expr = expr_elem['expr']
> > +            (kind, _) = expr.items()[0]
> > +
> > +            fmt = {"command": texi_command,
> > +                   "struct": texi_struct,
> > +                   "enum": texi_enum,
> > +                   "union": texi_union,
> > +                   "alternate": texi_alternate,
> > +                   "event": texi_event}
> > +            try:
> > +                fmt = fmt[kind]
> > +            except KeyError:
> > +                raise ValueError("Unknown expression kind '%s'" % kind)
> > +            res.append(fmt(expr, doc))
> > +        except:
> > +            print >>sys.stderr, "error at @%s" % qapi
> > +            raise
>
> What errors do you expect here?  I'm asking because catching exceptions
> indiscrimatingly feels problematic.
>

yeah, I think it's mostly KeyError or ValueError, I can restrict it, but at
the same time, since we re-raise, I don't think it's problematic, it's a
top-level function.


> > +
> > +    return '\n'.join(res)
> > +
> > +
> > +def parse_schema(fname):
> > +    """
> > +    Parse the given schema file and return the exprs
> > +    """
> > +    try:
> > +        schema = QAPISchemaParser(open(fname, "r"))
> > +        check_exprs(schema.exprs)
> > +        check_docs(schema.docs)
> > +        return schema.docs
>
> You don't actually "return the exprs", you return a list of QAPIDoc.
>
>
Yeah, last iteration change,


> Either return schema and let the caller retrieve its .docs, or rename
> the function to parse_docs().  In either case, fix up the doc string.
>
> > +    except (QAPISchemaError, QAPIExprError), err:
> > +        print >>sys.stderr, err
> > +        exit(1)
>
> The function duplicates parts of QAPISchema.__init__().  The parts it
> doesn't duplicate would be useful here, because without them, you might
> be working on a broken schema.
>
> Recommend to drop the function, and ...
>
> > +
> > +
> > +def main(argv):
> > +    """
> > +    Takes schema argument, prints result to stdout
> > +    """
> > +    if len(argv) != 2:
> > +        print >>sys.stderr, "%s: need exactly 1 argument: SCHEMA" %
> argv[0]
> > +        sys.exit(1)
> > +
> > +    docs = parse_schema(argv[1])
>
> ... instead do
>
>        schema = QAPISchema(argv[1])
>        docs = schema.docs
>

done


>
> with the obvious patch to make docs an attribute of schema:
>
> diff --git a/scripts/qapi.py b/scripts/qapi.py
> index ed52ee4..b17e7de 100644
> --- a/scripts/qapi.py
> +++ b/scripts/qapi.py
> @@ -1424,7 +1424,9 @@ class QAPISchemaEvent(QAPISchemaEntity):
>  class QAPISchema(object):
>      def __init__(self, fname):
>          try:
> -            self.exprs = check_exprs(QAPISchemaParser(open(fname,
> "r")).exprs)
> +            parser = QAPISchemaParser(open(fname, "r"))
> +            self.exprs = check_exprs(parser.exprs)
> +            self.docs = parser.docs
>              self._entity_dict = {}
>              self._predefining = True
>              self._def_predefineds()
>
>
ok


> You don't use the common parse_command_line().  Probably the right
> choice right now, as reusing it would require modifications (we have no
> use for -c and -h at least), and wouldn't buy us much.
>
> > +    print texi(docs)
> > +
> > +
> > +if __name__ == "__main__":
> > +    main(sys.argv)
>
> Ignorant question: why is this __name__ == "__main__" raindance better
> than the stupid way the qapi-{commands,event,introspect,types,visit}.py
> work?
>

I have always used __name__ == "__main__", see:

http://stackoverflow.com/questions/419163/what-does-if-name-main-do


>
> > diff --git a/docs/qapi-code-gen.txt b/docs/qapi-code-gen.txt
> > index 2841c51..d82e251 100644
> > --- a/docs/qapi-code-gen.txt
> > +++ b/docs/qapi-code-gen.txt
> > @@ -45,16 +45,13 @@ QAPI parser does not).  At present, there is no
> place where a QAPI
> >  schema requires the use of JSON numbers or null.
> >
> >  Comments are allowed; anything between an unquoted # and the following
> > -newline is ignored.  Although there is not yet a documentation
> > -generator, a form of stylized comments has developed for consistently
> > -documenting details about an expression and when it was added to the
> > -schema.  The documentation is delimited between two lines of ##, then
> > -the first line names the expression, an optional overview is provided,
> > -then individual documentation about each member of 'data' is provided,
> > -and finally, a 'Since: x.y.z' tag lists the release that introduced
> > -the expression.  Optional members are tagged with the phrase
> > -'#optional', often with their default value; and extensions added
> > -after the expression was first released are also given a '(since
> > +newline is ignored.  The documentation is delimited between two lines
> > +of ##, then the first line names the expression, an optional overview
> > +is provided, then individual documentation about each member of 'data'
> > +is provided, and finally, a 'Since: x.y.z' tag lists the release that
> > +introduced the expression.  Optional members are tagged with the
> > +phrase '#optional', often with their default value; and extensions
> > +added after the expression was first released are also given a '(since
> >  x.y.z)' comment.  For example:
> >
> >      ##
> > @@ -73,12 +70,39 @@ x.y.z)' comment.  For example:
> >      #           (Since 2.0)
> >      #
> >      # Since: 0.14.0
> > +    #
> > +    # Notes: You can also make a list:
> > +    #        - with items
> > +    #        - like this
> > +    #
> > +    # Example:
> > +    #
> > +    # -> { "execute": ... }
> > +    # <- { "return": ... }
>
> Err, 'BlockStats' is a *type*, not a command.
>
>
It could be returned/used in an example, it fits also this example.



> > +    #
> >      ##
> >      { 'struct': 'BlockStats',
> >        'data': {'*device': 'str', 'stats': 'BlockDeviceStats',
> >                 '*parent': 'BlockStats',
> >                 '*backing': 'BlockStats'} }
> >
> > +It's also possible to create documentation sections, such as:
> > +
> > +    ##
> > +    # = Section
> > +    # == Subsection
> > +    #
> > +    # Some text foo with *emphasis*
> > +    # 1. with a list
> > +    # 2. like that
> > +    #
> > +    # And some code:
> > +    # | $ echo foo
> > +    # | -> do this
> > +    # | <- get that
> > +    #
> > +    ##
> > +
>
> This suggests various kinds of markup, including section headers,
> emphasis, numbered lists.  But what exactly is recognized?
>
>
Ok updated


> >  The schema sets up a series of types, as well as commands and events
> >  that will use those types.  Forward references are allowed: the parser
> >  scans in two passes, where the first pass learns all type names, and
>
> As discussed in my review of the cover letter, we have some additional
> documentation work to do.
>
>
sure, but it's already 175 patches to review ;)


> Also missing: tests.  A first cut should have a negative test for each
> error qapi2texi.py can report, plus a modest suite of positive tests.  A
> negative test consists of tests/qapi-schema/NAME.{json,out,err,exit}.
> Positive tests can be added to tests/qapi-schema/qapi-schema-test.json,
> or to a separate test schema, in case that's more convenient.
>
> To get the most mileage out of positive tests, test-qapi.py should be
> extended to show the resulting QAPIDoc.  Sketch appended.
>
>
Thanks a lot for the feedback, I have done many changes based on it.

I'll work on adding some tests and send the new version, hopefully this
week.

If you have further comments based on this reply, I'll try to take them as
well with the next iteration.


> diff --git a/tests/qapi-schema/test-qapi.py
> b/tests/qapi-schema/test-qapi.py
> index ef74e2c..93cc709 100644
> --- a/tests/qapi-schema/test-qapi.py
> +++ b/tests/qapi-schema/test-qapi.py
> @@ -55,3 +55,13 @@ class QAPISchemaTestVisitor(QAPISchemaVisitor):
>
>  schema = QAPISchema(sys.argv[1])
>  schema.visit(QAPISchemaTestVisitor())
> +
> +for doc in schema.docs:
> +    expr_elem = doc.expr_elem
> +    expr_info = expr_elem and expr_elem['info']
> +    print 'doc %s %s' % (doc.symbol, expr_info)
> +    for arg, text in doc.args.iteritems():
> +        print '    arg=%s %s' % (arg, text)
> +    for key, text in doc.meta:
> +        print '    meta %s %s' % (key, text)
> +    print '    body=%s' % doc.body
>
> --
Marc-André Lureau

^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2016-11-15 17:18 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-11-07  7:30 [Qemu-devel] [PATCH v3 00/14] qapi doc generation (whole version, squashed) Marc-André Lureau
2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 01/14] qapi: add missing 'bus' argument in device_add Marc-André Lureau
2016-11-07 15:10   ` Markus Armbruster
2016-11-07 22:55   ` Eric Blake
2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 02/14] qga/schema: fix double-return in doc Marc-André Lureau
2016-11-07 22:59   ` Eric Blake
2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 03/14] qga/schema: improve guest-set-vcpus Returns: section Marc-André Lureau
2016-11-07 15:25   ` Markus Armbruster
2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 04/14] qapi: fix schema symbol sections Marc-André Lureau
2016-11-07 23:07   ` Eric Blake
2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 05/14] qapi: fix missing symbol @prefix Marc-André Lureau
2016-11-07 23:08   ` Eric Blake
2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 06/14] qapi: fix various symbols mismatch in documentation Marc-André Lureau
2016-11-07 15:40   ` Markus Armbruster
2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 07/14] qapi: use one symbol per line Marc-André Lureau
2016-11-07 15:57   ` Markus Armbruster
2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 08/14] qapi: add missing colon-ending for section name Marc-André Lureau
2016-11-07 15:58   ` Markus Armbruster
2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 09/14] qapi: add some sections in docs Marc-André Lureau
2016-11-07 15:59   ` Markus Armbruster
2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 10/14] docs: add master qapi texi files Marc-André Lureau
2016-11-08 14:19   ` Markus Armbruster
2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 11/14] qapi: add qapi2texi script Marc-André Lureau
2016-11-10 16:37   ` Markus Armbruster
2016-11-15 17:17     ` Marc-André Lureau
2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 12/14] texi2pod: learn quotation, deftp and deftypefn Marc-André Lureau
2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 13/14] qmp-commands: (SQUASHED) move doc to schema Marc-André Lureau
2016-11-07  7:30 ` [Qemu-devel] [PATCH v3 14/14] build-sys: add qapi doc generation targets Marc-André Lureau

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.