summaryrefslogtreecommitdiffstats
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/analyse-locks-simpletrace.py1
-rwxr-xr-xscripts/analyze-migration.py1
-rwxr-xr-xscripts/checkpatch.pl144
-rw-r--r--scripts/cocci-macro-file.h25
-rwxr-xr-xscripts/device-crash-test17
-rwxr-xr-xscripts/fix-multiline-comments.sh62
-rwxr-xr-xscripts/gtester-cat26
-rw-r--r--scripts/qapi/common.py208
-rwxr-xr-xscripts/qapi/doc.py31
-rw-r--r--scripts/qapi/events.py13
-rw-r--r--scripts/qapi/introspect.py17
-rw-r--r--scripts/qapi/types.py10
-rw-r--r--scripts/qapi/visit.py8
-rw-r--r--scripts/qemu.py2
-rwxr-xr-xscripts/replay-dump.py2
-rwxr-xr-xscripts/simpletrace.py1
-rwxr-xr-xscripts/tap-driver.pl378
-rwxr-xr-xscripts/tap-merge.pl110
-rwxr-xr-xscripts/texi2pod.pl2
-rwxr-xr-xscripts/tracetool.py2
-rw-r--r--scripts/tracetool/backend/log.py2
-rw-r--r--scripts/tracetool/format/simpletrace_stap.py2
22 files changed, 872 insertions, 192 deletions
diff --git a/scripts/analyse-locks-simpletrace.py b/scripts/analyse-locks-simpletrace.py
index 30090bdfff..7d9b574300 100755
--- a/scripts/analyse-locks-simpletrace.py
+++ b/scripts/analyse-locks-simpletrace.py
@@ -7,7 +7,6 @@
#
from __future__ import print_function
-import os
import simpletrace
import argparse
import numpy as np
diff --git a/scripts/analyze-migration.py b/scripts/analyze-migration.py
index 5c2010c917..e527eb168e 100755
--- a/scripts/analyze-migration.py
+++ b/scripts/analyze-migration.py
@@ -23,7 +23,6 @@ import json
import os
import argparse
import collections
-import pprint
def mkdir_p(path):
try:
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 60f6f89a27..d10dddf1be 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -7,6 +7,7 @@
use strict;
use warnings;
+use Term::ANSIColor qw(:constants);
my $P = $0;
$P =~ s@.*/@@g;
@@ -26,6 +27,7 @@ my $tst_only;
my $emacs = 0;
my $terse = 0;
my $file = undef;
+my $color = "auto";
my $no_warnings = 0;
my $summary = 1;
my $mailback = 0;
@@ -64,6 +66,8 @@ Options:
is all off)
--test-only=WORD report only warnings/errors containing WORD
literally
+ --color[=WHEN] Use colors 'always', 'never', or only when output
+ is a terminal ('auto'). Default is 'auto'.
-h, --help, --version display this help and exit
When FILE is - read standard input.
@@ -72,6 +76,14 @@ EOM
exit($exitcode);
}
+# Perl's Getopt::Long allows options to take optional arguments after a space.
+# Prevent --color by itself from consuming other arguments
+foreach (@ARGV) {
+ if ($_ eq "--color" || $_ eq "-color") {
+ $_ = "--color=$color";
+ }
+}
+
GetOptions(
'q|quiet+' => \$quiet,
'tree!' => \$tree,
@@ -89,6 +101,8 @@ GetOptions(
'debug=s' => \%debug,
'test-only=s' => \$tst_only,
+ 'color=s' => \$color,
+ 'no-color' => sub { $color = 'never'; },
'h|help' => \$help,
'version' => \$help
) or help(1);
@@ -144,6 +158,16 @@ if (!$chk_patch && !$chk_branch && !$file) {
die "One of --file, --branch, --patch is required\n";
}
+if ($color =~ /^always$/i) {
+ $color = 1;
+} elsif ($color =~ /^never$/i) {
+ $color = 0;
+} elsif ($color =~ /^auto$/i) {
+ $color = (-t STDOUT);
+} else {
+ die "Invalid color mode: $color\n";
+}
+
my $dbg_values = 0;
my $dbg_possible = 0;
my $dbg_type = 0;
@@ -202,7 +226,6 @@ our $Attribute = qr{
QEMU_NORETURN|
QEMU_WARN_UNUSED_RESULT|
QEMU_SENTINEL|
- QEMU_ARTIFICIAL|
QEMU_PACKED|
GCC_FMT_ATTR
}x;
@@ -340,13 +363,18 @@ my @lines = ();
my $vname;
if ($chk_branch) {
my @patches;
+ my %git_commits = ();
my $HASH;
- open($HASH, "-|", "git", "log", "--format=%H", $ARGV[0]) ||
- die "$P: git log --format=%H $ARGV[0] failed - $!\n";
-
- while (<$HASH>) {
- chomp;
- push @patches, $_;
+ open($HASH, "-|", "git", "log", "--reverse", "--no-merges", "--format=%H %s", $ARGV[0]) ||
+ die "$P: git log --reverse --no-merges --format='%H %s' $ARGV[0] failed - $!\n";
+
+ for my $line (<$HASH>) {
+ $line =~ /^([0-9a-fA-F]{40,40}) (.*)$/;
+ next if (!defined($1) || !defined($2));
+ my $sha1 = $1;
+ my $subject = $2;
+ push(@patches, $sha1);
+ $git_commits{$sha1} = $subject;
}
close $HASH;
@@ -354,21 +382,33 @@ if ($chk_branch) {
die "$P: no revisions returned for revlist '$chk_branch'\n"
unless @patches;
+ my $i = 1;
+ my $num_patches = @patches;
for my $hash (@patches) {
my $FILE;
open($FILE, '-|', "git", "show", $hash) ||
die "$P: git show $hash - $!\n";
- $vname = $hash;
while (<$FILE>) {
chomp;
push(@rawlines, $_);
}
close($FILE);
+ $vname = substr($hash, 0, 12) . ' (' . $git_commits{$hash} . ')';
+ if ($num_patches > 1 && $quiet == 0) {
+ my $prefix = "$i/$num_patches";
+ $prefix = BLUE . BOLD . $prefix . RESET if $color;
+ print "$prefix Checking commit $vname\n";
+ $vname = "Patch $i/$num_patches";
+ } else {
+ $vname = "Commit " . $vname;
+ }
if (!process($hash)) {
$exit = 1;
+ print "\n" if ($num_patches > 1 && $quiet == 0);
}
@rawlines = ();
@lines = ();
+ $i++;
}
} else {
for my $filename (@ARGV) {
@@ -387,6 +427,7 @@ if ($chk_branch) {
} else {
$vname = $filename;
}
+ print "Checking $filename...\n" if @ARGV > 1 && $quiet == 0;
while (<$FILE>) {
chomp;
push(@rawlines, $_);
@@ -1166,14 +1207,23 @@ sub possible {
my $prefix = '';
sub report {
- if (defined $tst_only && $_[0] !~ /\Q$tst_only\E/) {
+ my ($level, $msg) = @_;
+ if (defined $tst_only && $msg !~ /\Q$tst_only\E/) {
return 0;
}
- my $line = $prefix . $_[0];
- $line = (split('\n', $line))[0] . "\n" if ($terse);
+ my $output = '';
+ $output .= BOLD if $color;
+ $output .= $prefix;
+ $output .= RED if $color && $level eq 'ERROR';
+ $output .= MAGENTA if $color && $level eq 'WARNING';
+ $output .= $level . ':';
+ $output .= RESET if $color;
+ $output .= ' ' . $msg . "\n";
- push(our @report, $line);
+ $output = (split('\n', $output))[0] . "\n" if ($terse);
+
+ push(our @report, $output);
return 1;
}
@@ -1181,13 +1231,13 @@ sub report_dump {
our @report;
}
sub ERROR {
- if (report("ERROR: $_[0]\n")) {
+ if (report("ERROR", $_[0])) {
our $clean = 0;
our $cnt_error++;
}
}
sub WARN {
- if (report("WARNING: $_[0]\n")) {
+ if (report("WARNING", $_[0])) {
our $clean = 0;
our $cnt_warn++;
}
@@ -1570,6 +1620,54 @@ sub process {
# check we are in a valid C source file if not then ignore this hunk
next if ($realfile !~ /\.(h|c|cpp)$/);
+# Block comment styles
+
+ # Block comments use /* on a line of its own
+ if ($rawline !~ m@^\+.*/\*.*\*/[ \t]*$@ && #inline /*...*/
+ $rawline =~ m@^\+.*/\*\*?[ \t]*.+[ \t]*$@) { # /* or /** non-blank
+ WARN("Block comments use a leading /* on a separate line\n" . $herecurr);
+ }
+
+# Block comments use * on subsequent lines
+ if ($prevline =~ /$;[ \t]*$/ && #ends in comment
+ $prevrawline =~ /^\+.*?\/\*/ && #starting /*
+ $prevrawline !~ /\*\/[ \t]*$/ && #no trailing */
+ $rawline =~ /^\+/ && #line is new
+ $rawline !~ /^\+[ \t]*\*/) { #no leading *
+ WARN("Block comments use * on subsequent lines\n" . $hereprev);
+ }
+
+# Block comments use */ on trailing lines
+ if ($rawline !~ m@^\+[ \t]*\*/[ \t]*$@ && #trailing */
+ $rawline !~ m@^\+.*/\*.*\*/[ \t]*$@ && #inline /*...*/
+ $rawline !~ m@^\+.*\*{2,}/[ \t]*$@ && #trailing **/
+ $rawline =~ m@^\+[ \t]*.+\*\/[ \t]*$@) { #non blank */
+ WARN("Block comments use a trailing */ on a separate line\n" . $herecurr);
+ }
+
+# Block comment * alignment
+ if ($prevline =~ /$;[ \t]*$/ && #ends in comment
+ $line =~ /^\+[ \t]*$;/ && #leading comment
+ $rawline =~ /^\+[ \t]*\*/ && #leading *
+ (($prevrawline =~ /^\+.*?\/\*/ && #leading /*
+ $prevrawline !~ /\*\/[ \t]*$/) || #no trailing */
+ $prevrawline =~ /^\+[ \t]*\*/)) { #leading *
+ my $oldindent;
+ $prevrawline =~ m@^\+([ \t]*/?)\*@;
+ if (defined($1)) {
+ $oldindent = expand_tabs($1);
+ } else {
+ $prevrawline =~ m@^\+(.*/?)\*@;
+ $oldindent = expand_tabs($1);
+ }
+ $rawline =~ m@^\+([ \t]*)\*@;
+ my $newindent = $1;
+ $newindent = expand_tabs($newindent);
+ if (length($oldindent) ne length($newindent)) {
+ WARN("Block comments should align the * on each line\n" . $hereprev);
+ }
+ }
+
# Check for potential 'bare' types
my ($stat, $cond, $line_nr_next, $remain_next, $off_next,
$realline_next);
@@ -2212,6 +2310,11 @@ sub process {
}
}
+ if ($line =~ /^.\s*(Q(?:S?LIST|SIMPLEQ|TAILQ)_HEAD)\s*\(\s*[^,]/ &&
+ $line !~ /^.typedef/) {
+ ERROR("named $1 should be typedefed separately\n" . $herecurr);
+ }
+
# Need a space before open parenthesis after if, while etc
if ($line=~/\b(if|while|for|switch)\(/) {
ERROR("space required before the open parenthesis '('\n" . $herecurr);
@@ -2817,30 +2920,31 @@ sub process {
}
}
+ if ($is_patch && $chk_signoff && $signoff == 0) {
+ ERROR("Missing Signed-off-by: line(s)\n");
+ }
+
# If we have no input at all, then there is nothing to report on
# so just keep quiet.
if ($#rawlines == -1) {
- exit(0);
+ return 1;
}
# In mailback mode only produce a report in the negative, for
# things that appear to be patches.
if ($mailback && ($clean == 1 || !$is_patch)) {
- exit(0);
+ return 1;
}
# This is not a patch, and we are are in 'no-patch' mode so
# just keep quiet.
if (!$chk_patch && !$is_patch) {
- exit(0);
+ return 1;
}
if (!$is_patch) {
ERROR("Does not appear to be a unified-diff format patch\n");
}
- if ($is_patch && $chk_signoff && $signoff == 0) {
- ERROR("Missing Signed-off-by: line(s)\n");
- }
print report_dump();
if ($summary && !($clean == 1 && $quiet == 1)) {
diff --git a/scripts/cocci-macro-file.h b/scripts/cocci-macro-file.h
index 9f2e72e7e1..e485cdccae 100644
--- a/scripts/cocci-macro-file.h
+++ b/scripts/cocci-macro-file.h
@@ -23,7 +23,6 @@
#define QEMU_NORETURN __attribute__ ((__noreturn__))
#define QEMU_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#define QEMU_SENTINEL __attribute__((sentinel))
-#define QEMU_ARTIFICIAL __attribute__((always_inline, artificial))
#define QEMU_PACKED __attribute__((gcc_struct, packed))
#define cat(x,y) x ## y
@@ -93,29 +92,19 @@ struct { \
/*
* Tail queue definitions.
*/
-#define Q_TAILQ_HEAD(name, type, qual) \
-struct name { \
- qual type *tqh_first; /* first element */ \
- qual type *qual *tqh_last; /* addr of last next element */ \
-}
#define QTAILQ_HEAD(name, type) \
-struct name { \
- type *tqh_first; /* first element */ \
- type **tqh_last; /* addr of last next element */ \
+union name { \
+ struct type *tqh_first; /* first element */ \
+ QTailQLink tqh_circ; /* link for last element */ \
}
#define QTAILQ_HEAD_INITIALIZER(head) \
- { NULL, &(head).tqh_first }
+ { .tqh_circ = { NULL, &(head).tqh_circ } }
-#define Q_TAILQ_ENTRY(type, qual) \
-struct { \
- qual type *tqe_next; /* next element */ \
- qual type *qual *tqe_prev; /* address of previous next element */\
-}
#define QTAILQ_ENTRY(type) \
-struct { \
- type *tqe_next; /* next element */ \
- type **tqe_prev; /* address of previous next element */ \
+union { \
+ struct type *tqe_next; /* next element */ \
+ QTailQLink tqe_circ; /* link for prev element */ \
}
/* From glib */
diff --git a/scripts/device-crash-test b/scripts/device-crash-test
index e93a7c0c84..483dafb2fc 100755
--- a/scripts/device-crash-test
+++ b/scripts/device-crash-test
@@ -26,7 +26,6 @@ check for crashes and unexpected errors.
from __future__ import print_function
import sys
-import os
import glob
import logging
import traceback
@@ -83,7 +82,6 @@ ERROR_WHITELIST = [
{'device':'isa-ipmi-bt', 'expected':True}, # IPMI device requires a bmc attribute to be set
{'device':'isa-ipmi-kcs', 'expected':True}, # IPMI device requires a bmc attribute to be set
{'device':'isa-parallel', 'expected':True}, # Can't create serial device, empty char device
- {'device':'ivshmem', 'expected':True}, # You must specify either 'shm' or 'chardev'
{'device':'ivshmem-doorbell', 'expected':True}, # You must specify a 'chardev'
{'device':'ivshmem-plain', 'expected':True}, # You must specify a 'memdev'
{'device':'loader', 'expected':True}, # please include valid arguments
@@ -182,21 +180,6 @@ ERROR_WHITELIST = [
# other exitcode=1 failures not listed above will just generate INFO messages:
{'exitcode':1, 'loglevel':logging.INFO},
- # KNOWN CRASHES:
- # Known crashes will generate error messages, but won't be fatal.
- # Those entries must be removed once we fix the crashes.
- {'exitcode':-6, 'log':r"Device 'serial0' is in use", 'loglevel':logging.ERROR},
- {'exitcode':-6, 'log':r"qemu_net_client_setup: Assertion `!peer->peer' failed", 'loglevel':logging.ERROR},
- {'exitcode':-6, 'log':r'RAMBlock "[\w.-]+" already registered', 'loglevel':logging.ERROR},
- {'exitcode':-6, 'log':r"find_ram_offset: Assertion `size != 0' failed.", 'loglevel':logging.ERROR},
- {'exitcode':-6, 'log':r"add_cpreg_to_hashtable: code should not be reached", 'loglevel':logging.ERROR},
- {'exitcode':-6, 'log':r"qemu_alloc_display: Assertion `surface->image != NULL' failed", 'loglevel':logging.ERROR},
- {'exitcode':-6, 'log':r"Unexpected error in error_set_from_qdev_prop_error", 'loglevel':logging.ERROR},
- {'exitcode':-6, 'log':r"Object .* is not an instance of type spapr-machine", 'loglevel':logging.ERROR},
- {'exitcode':-6, 'log':r"Object .* is not an instance of type generic-pc-machine", 'loglevel':logging.ERROR},
- {'exitcode':-6, 'log':r"Object .* is not an instance of type e500-ccsr", 'loglevel':logging.ERROR},
- {'exitcode':-6, 'log':r"vmstate_register_with_alias_id: Assertion `!se->compat \|\| se->instance_id == 0' failed", 'loglevel':logging.ERROR},
-
# everything else (including SIGABRT and SIGSEGV) will be a fatal error:
{'exitcode':None, 'fatal':True, 'loglevel':logging.FATAL},
]
diff --git a/scripts/fix-multiline-comments.sh b/scripts/fix-multiline-comments.sh
new file mode 100755
index 0000000000..93f9b10669
--- /dev/null
+++ b/scripts/fix-multiline-comments.sh
@@ -0,0 +1,62 @@
+#! /bin/sh
+#
+# Fix multiline comments to match CODING_STYLE
+#
+# Copyright (C) 2018 Red Hat, Inc.
+#
+# Author: Paolo Bonzini
+#
+# Usage: scripts/fix-multiline-comments.sh [-i] FILE...
+#
+# -i edits the file in place (requires gawk 4.1.0).
+#
+# Set the AWK environment variable to choose the awk interpreter to use
+# (default 'awk')
+
+if test "$1" = -i; then
+ # gawk extension
+ inplace="-i inplace"
+ shift
+fi
+${AWK-awk} $inplace 'BEGIN { indent = -1 }
+{
+ line = $0
+ # apply a star to the indent on lines after the first
+ if (indent != -1) {
+ if (line == "") {
+ line = sp " *"
+ } else if (substr(line, 1, indent + 2) == sp " ") {
+ line = sp " *" substr(line, indent + 3)
+ }
+ }
+
+ is_lead = (line ~ /^[ \t]*\/\*/)
+ is_trail = (line ~ /\*\//)
+ if (is_lead && !is_trail) {
+ # grab the indent at the start of a comment, but not for
+ # single-line comments
+ match(line, /^[ \t]*\/\*/)
+ indent = RLENGTH - 2
+ sp = substr(line, 1, indent)
+ }
+
+ # the regular expression filters out lone /*, /**, or */
+ if (indent != -1 && !(line ~ /^[ \t]*(\/\*+|\*\/)[ \t]*$/)) {
+ if (is_lead) {
+ # split the leading /* or /** on a separate line
+ match(line, /^[ \t]*\/\*+/)
+ lead = substr(line, 1, RLENGTH)
+ match(line, /^[ \t]*\/\*+[ \t]*/)
+ line = lead "\n" sp " *" substr(line, RLENGTH)
+ }
+ if (is_trail) {
+ # split the trailing */ on a separate line
+ match(line, /[ \t]*\*\//)
+ line = substr(line, 1, RSTART - 1) "\n" sp " */"
+ }
+ }
+ if (is_trail) {
+ indent = -1
+ }
+ print line
+}' "$@"
diff --git a/scripts/gtester-cat b/scripts/gtester-cat
deleted file mode 100755
index 061a952cad..0000000000
--- a/scripts/gtester-cat
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/bin/sh
-#
-# Copyright IBM, Corp. 2012
-#
-# Authors:
-# Anthony Liguori <aliguori@us.ibm.com>
-#
-# This work is licensed under the terms of the GNU GPLv2 or later.
-# See the COPYING file in the top-level directory.
-
-cat <<EOF
-<?xml version="1.0"?>
-<gtester>
- <info>
- <package>qemu</package>
- <version>0.0</version>
- <revision>rev</revision>
- </info>
-EOF
-
-sed \
- -e '/<?xml/d' \
- -e '/^<gtester>$/d' \
- -e '/<info>/,/<\/info>/d' \
- -e '$b' \
- -e '/^<\/gtester>$/d' "$@"
diff --git a/scripts/qapi/common.py b/scripts/qapi/common.py
index 7b62a4c7b0..c89edc0cb0 100644
--- a/scripts/qapi/common.py
+++ b/scripts/qapi/common.py
@@ -588,11 +588,11 @@ def discriminator_find_enum_define(expr):
if not base_members:
return None
- discriminator_type = base_members.get(discriminator)
- if not discriminator_type:
+ discriminator_value = base_members.get(discriminator)
+ if not discriminator_value:
return None
- return enum_types.get(discriminator_type)
+ return enum_types.get(discriminator_value['type'])
# Names must be letters, numbers, -, and _. They must start with letter,
@@ -704,8 +704,10 @@ def check_type(info, source, value, allow_array=False,
% (source, key))
# Todo: allow dictionaries to represent default values of
# an optional argument.
- check_type(info, "Member '%s' of %s" % (key, source), arg,
- allow_array=True,
+ check_known_keys(info, "member '%s' of %s" % (key, source),
+ arg, ['type'], ['if'])
+ check_type(info, "Member '%s' of %s" % (key, source),
+ arg['type'], allow_array=True,
allow_metas=['built-in', 'union', 'alternate', 'struct',
'enum'])
@@ -740,6 +742,10 @@ def check_event(expr, info):
allow_metas=meta)
+def enum_get_names(expr):
+ return [e['name'] for e in expr['data']]
+
+
def check_union(expr, info):
name = expr['union']
base = expr.get('base')
@@ -772,13 +778,17 @@ def check_union(expr, info):
# member of the base struct.
check_name(info, "Discriminator of flat union '%s'" % name,
discriminator)
- discriminator_type = base_members.get(discriminator)
- if not discriminator_type:
+ discriminator_value = base_members.get(discriminator)
+ if not discriminator_value:
raise QAPISemError(info,
"Discriminator '%s' is not a member of base "
"struct '%s'"
% (discriminator, base))
- enum_define = enum_types.get(discriminator_type)
+ if discriminator_value.get('if'):
+ raise QAPISemError(info, 'The discriminator %s.%s for union %s '
+ 'must not be conditional' %
+ (base, discriminator, name))
+ enum_define = enum_types.get(discriminator_value['type'])
allow_metas = ['struct']
# Do not allow string discriminator
if not enum_define:
@@ -792,14 +802,17 @@ def check_union(expr, info):
for (key, value) in members.items():
check_name(info, "Member of union '%s'" % name, key)
+ check_known_keys(info, "member '%s' of union '%s'" % (key, name),
+ value, ['type'], ['if'])
# Each value must name a known type
check_type(info, "Member '%s' of union '%s'" % (key, name),
- value, allow_array=not base, allow_metas=allow_metas)
+ value['type'],
+ allow_array=not base, allow_metas=allow_metas)
# If the discriminator names an enum type, then all members
# of 'data' must also be members of the enum type.
if enum_define:
- if key not in enum_define['data']:
+ if key not in enum_get_names(enum_define):
raise QAPISemError(info,
"Discriminator value '%s' is not found in "
"enum '%s'"
@@ -818,20 +831,23 @@ def check_alternate(expr, info):
"in 'data'" % name)
for (key, value) in members.items():
check_name(info, "Member of alternate '%s'" % name, key)
+ check_known_keys(info,
+ "member '%s' of alternate '%s'" % (key, name),
+ value, ['type'], ['if'])
+ typ = value['type']
# Ensure alternates have no type conflicts.
- check_type(info, "Member '%s' of alternate '%s'" % (key, name),
- value,
+ check_type(info, "Member '%s' of alternate '%s'" % (key, name), typ,
allow_metas=['built-in', 'union', 'struct', 'enum'])
- qtype = find_alternate_member_qtype(value)
+ qtype = find_alternate_member_qtype(typ)
if not qtype:
raise QAPISemError(info, "Alternate '%s' member '%s' cannot use "
- "type '%s'" % (name, key, value))
+ "type '%s'" % (name, key, typ))
conflicting = set([qtype])
if qtype == 'QTYPE_QSTRING':
- enum_expr = enum_types.get(value)
+ enum_expr = enum_types.get(typ)
if enum_expr:
- for v in enum_expr['data']:
+ for v in enum_get_names(enum_expr):
if v in ['on', 'off']:
conflicting.add('QTYPE_QBOOL')
if re.match(r'[-+0-9.]', v): # lazy, could be tightened
@@ -849,7 +865,7 @@ def check_alternate(expr, info):
def check_enum(expr, info):
name = expr['enum']
- members = expr.get('data')
+ members = expr['data']
prefix = expr.get('prefix')
if not isinstance(members, list):
@@ -858,8 +874,12 @@ def check_enum(expr, info):
if prefix is not None and not isinstance(prefix, str):
raise QAPISemError(info,
"Enum '%s' requires a string for 'prefix'" % name)
+
for member in members:
- check_name(info, "Member of enum '%s'" % name, member,
+ source = "dictionary member of enum '%s'" % name
+ check_known_keys(info, source, member, ['name'], ['if'])
+ check_if(member, info)
+ check_name(info, "Member of enum '%s'" % name, member['name'],
enum_member=True)
@@ -873,6 +893,24 @@ def check_struct(expr, info):
allow_metas=['struct'])
+def check_known_keys(info, source, keys, required, optional):
+
+ def pprint(elems):
+ return ', '.join("'" + e + "'" for e in sorted(elems))
+
+ missing = set(required) - set(keys)
+ if missing:
+ raise QAPISemError(info, "Key%s %s %s missing from %s"
+ % ('s' if len(missing) > 1 else '', pprint(missing),
+ 'are' if len(missing) > 1 else 'is', source))
+ allowed = set(required + optional)
+ unknown = set(keys) - allowed
+ if unknown:
+ raise QAPISemError(info, "Unknown key%s %s in %s\nValid keys are %s."
+ % ('s' if len(unknown) > 1 else '', pprint(unknown),
+ source, pprint(allowed)))
+
+
def check_keys(expr_elem, meta, required, optional=[]):
expr = expr_elem['expr']
info = expr_elem['info']
@@ -880,10 +918,9 @@ def check_keys(expr_elem, meta, required, optional=[]):
if not isinstance(name, str):
raise QAPISemError(info, "'%s' key must have a string value" % meta)
required = required + [meta]
+ source = "%s '%s'" % (meta, name)
+ check_known_keys(info, source, expr.keys(), required, optional)
for (key, value) in expr.items():
- if key not in required and key not in optional:
- raise QAPISemError(info, "Unknown key '%s' in %s '%s'"
- % (key, meta, name))
if key in ['gen', 'success-response'] and value is not False:
raise QAPISemError(info,
"'%s' of %s '%s' should only use false value"
@@ -895,10 +932,20 @@ def check_keys(expr_elem, meta, required, optional=[]):
% (key, meta, name))
if key == 'if':
check_if(expr, info)
- for key in required:
- if key not in expr:
- raise QAPISemError(info, "Key '%s' is missing from %s '%s'"
- % (key, meta, name))
+
+
+def normalize_enum(expr):
+ if isinstance(expr['data'], list):
+ expr['data'] = [m if isinstance(m, dict) else {'name': m}
+ for m in expr['data']]
+
+
+def normalize_members(members):
+ if isinstance(members, OrderedDict):
+ for key, arg in members.items():
+ if isinstance(arg, dict):
+ continue
+ members[key] = {'type': arg}
def check_exprs(exprs):
@@ -924,27 +971,34 @@ def check_exprs(exprs):
if 'enum' in expr:
meta = 'enum'
check_keys(expr_elem, 'enum', ['data'], ['if', 'prefix'])
+ normalize_enum(expr)
enum_types[expr[meta]] = expr
elif 'union' in expr:
meta = 'union'
check_keys(expr_elem, 'union', ['data'],
['base', 'discriminator', 'if'])
+ normalize_members(expr.get('base'))
+ normalize_members(expr['data'])
union_types[expr[meta]] = expr
elif 'alternate' in expr:
meta = 'alternate'
check_keys(expr_elem, 'alternate', ['data'], ['if'])
+ normalize_members(expr['data'])
elif 'struct' in expr:
meta = 'struct'
check_keys(expr_elem, 'struct', ['data'], ['base', 'if'])
+ normalize_members(expr['data'])
struct_types[expr[meta]] = expr
elif 'command' in expr:
meta = 'command'
check_keys(expr_elem, 'command', [],
['data', 'returns', 'gen', 'success-response',
'boxed', 'allow-oob', 'allow-preconfig', 'if'])
+ normalize_members(expr.get('data'))
elif 'event' in expr:
meta = 'event'
check_keys(expr_elem, 'event', [], ['data', 'boxed', 'if'])
+ normalize_members(expr.get('data'))
else:
raise QAPISemError(expr_elem['info'],
"Expression is missing metatype")
@@ -1063,7 +1117,7 @@ class QAPISchemaVisitor(object):
def visit_builtin_type(self, name, info, json_type):
pass
- def visit_enum_type(self, name, info, ifcond, values, prefix):
+ def visit_enum_type(self, name, info, ifcond, members, prefix):
pass
def visit_array_type(self, name, info, ifcond, element_type):
@@ -1161,22 +1215,22 @@ class QAPISchemaBuiltinType(QAPISchemaType):
class QAPISchemaEnumType(QAPISchemaType):
- def __init__(self, name, info, doc, ifcond, values, prefix):
+ def __init__(self, name, info, doc, ifcond, members, prefix):
QAPISchemaType.__init__(self, name, info, doc, ifcond)
- for v in values:
- assert isinstance(v, QAPISchemaMember)
- v.set_owner(name)
+ for m in members:
+ assert isinstance(m, QAPISchemaMember)
+ m.set_owner(name)
assert prefix is None or isinstance(prefix, str)
- self.values = values
+ self.members = members
self.prefix = prefix
def check(self, schema):
QAPISchemaType.check(self, schema)
seen = {}
- for v in self.values:
- v.check_clash(self.info, seen)
+ for m in self.members:
+ m.check_clash(self.info, seen)
if self.doc:
- self.doc.connect_member(v)
+ self.doc.connect_member(m)
def is_implicit(self):
# See QAPISchema._make_implicit_enum_type() and ._def_predefineds()
@@ -1186,14 +1240,14 @@ class QAPISchemaEnumType(QAPISchemaType):
return c_name(self.name)
def member_names(self):
- return [v.name for v in self.values]
+ return [m.name for m in self.members]
def json_type(self):
return 'string'
def visit(self, visitor):
visitor.visit_enum_type(self.name, self.info, self.ifcond,
- self.member_names(), self.prefix)
+ self.members, self.prefix)
class QAPISchemaArrayType(QAPISchemaType):
@@ -1318,9 +1372,10 @@ class QAPISchemaObjectType(QAPISchemaType):
class QAPISchemaMember(object):
role = 'member'
- def __init__(self, name):
+ def __init__(self, name, ifcond=None):
assert isinstance(name, str)
self.name = name
+ self.ifcond = listify_cond(ifcond)
self.owner = None
def set_owner(self, name):
@@ -1361,8 +1416,8 @@ class QAPISchemaMember(object):
class QAPISchemaObjectTypeMember(QAPISchemaMember):
- def __init__(self, name, typ, optional):
- QAPISchemaMember.__init__(self, name)
+ def __init__(self, name, typ, optional, ifcond=None):
+ QAPISchemaMember.__init__(self, name, ifcond)
assert isinstance(typ, str)
assert isinstance(optional, bool)
self._type_name = typ
@@ -1403,9 +1458,10 @@ class QAPISchemaObjectTypeVariants(object):
if self._tag_name: # flat union
# branches that are not explicitly covered get an empty type
cases = set([v.name for v in self.variants])
- for val in self.tag_member.type.values:
- if val.name not in cases:
- v = QAPISchemaObjectTypeVariant(val.name, 'q_empty')
+ for m in self.tag_member.type.members:
+ if m.name not in cases:
+ v = QAPISchemaObjectTypeVariant(m.name, 'q_empty',
+ m.ifcond)
v.set_owner(self.tag_member.owner)
self.variants.append(v)
for v in self.variants:
@@ -1428,8 +1484,8 @@ class QAPISchemaObjectTypeVariants(object):
class QAPISchemaObjectTypeVariant(QAPISchemaObjectTypeMember):
role = 'branch'
- def __init__(self, name, typ):
- QAPISchemaObjectTypeMember.__init__(self, name, typ, False)
+ def __init__(self, name, typ, ifcond=None):
+ QAPISchemaObjectTypeMember.__init__(self, name, typ, False, ifcond)
class QAPISchemaAlternateType(QAPISchemaType):
@@ -1620,14 +1676,16 @@ class QAPISchema(object):
self.the_empty_object_type = QAPISchemaObjectType(
'q_empty', None, None, None, None, [], None)
self._def_entity(self.the_empty_object_type)
- qtype_values = self._make_enum_members(['none', 'qnull', 'qnum',
- 'qstring', 'qdict', 'qlist',
- 'qbool'])
+
+ qtypes = ['none', 'qnull', 'qnum', 'qstring', 'qdict', 'qlist',
+ 'qbool']
+ qtype_values = self._make_enum_members([{'name': n} for n in qtypes])
+
self._def_entity(QAPISchemaEnumType('QType', None, None, None,
qtype_values, 'QTYPE'))
def _make_enum_members(self, values):
- return [QAPISchemaMember(v) for v in values]
+ return [QAPISchemaMember(v['name'], v.get('if')) for v in values]
def _make_implicit_enum_type(self, name, info, ifcond, values):
# See also QAPISchemaObjectTypeMember._pretty_owner()
@@ -1674,7 +1732,7 @@ class QAPISchema(object):
name, info, doc, ifcond,
self._make_enum_members(data), prefix))
- def _make_member(self, name, typ, info):
+ def _make_member(self, name, typ, ifcond, info):
optional = False
if name.startswith('*'):
name = name[1:]
@@ -1682,10 +1740,10 @@ class QAPISchema(object):
if isinstance(typ, list):
assert len(typ) == 1
typ = self._make_array_type(typ[0], info)
- return QAPISchemaObjectTypeMember(name, typ, optional)
+ return QAPISchemaObjectTypeMember(name, typ, optional, ifcond)
def _make_members(self, data, info):
- return [self._make_member(key, value, info)
+ return [self._make_member(key, value['type'], value.get('if'), info)
for (key, value) in data.items()]
def _def_struct_type(self, expr, info, doc):
@@ -1697,17 +1755,17 @@ class QAPISchema(object):
self._make_members(data, info),
None))
- def _make_variant(self, case, typ):
- return QAPISchemaObjectTypeVariant(case, typ)
+ def _make_variant(self, case, typ, ifcond):
+ return QAPISchemaObjectTypeVariant(case, typ, ifcond)
- def _make_simple_variant(self, case, typ, info):
+ def _make_simple_variant(self, case, typ, ifcond, info):
if isinstance(typ, list):
assert len(typ) == 1
typ = self._make_array_type(typ[0], info)
typ = self._make_implicit_object_type(
typ, info, None, self.lookup_type(typ),
- 'wrapper', [self._make_member('data', typ, info)])
- return QAPISchemaObjectTypeVariant(case, typ)
+ 'wrapper', [self._make_member('data', typ, None, info)])
+ return QAPISchemaObjectTypeVariant(case, typ, ifcond)
def _def_union_type(self, expr, info, doc):
name = expr['union']
@@ -1721,14 +1779,15 @@ class QAPISchema(object):
name, info, doc, ifcond,
'base', self._make_members(base, info))
if tag_name:
- variants = [self._make_variant(key, value)
+ variants = [self._make_variant(key, value['type'], value.get('if'))
for (key, value) in data.items()]
members = []
else:
- variants = [self._make_simple_variant(key, value, info)
+ variants = [self._make_simple_variant(key, value['type'],
+ value.get('if'), info)
for (key, value) in data.items()]
- typ = self._make_implicit_enum_type(name, info, ifcond,
- [v.name for v in variants])
+ enum = [{'name': v.name, 'if': v.ifcond} for v in variants]
+ typ = self._make_implicit_enum_type(name, info, ifcond, enum)
tag_member = QAPISchemaObjectTypeMember('type', typ, False)
members = [tag_member]
self._def_entity(
@@ -1741,7 +1800,7 @@ class QAPISchema(object):
name = expr['alternate']
data = expr['data']
ifcond = expr.get('if')
- variants = [self._make_variant(key, value)
+ variants = [self._make_variant(key, value['type'], value.get('if'))
for (key, value) in data.items()]
tag_member = QAPISchemaObjectTypeMember('type', 'QType', False)
self._def_entity(
@@ -2012,19 +2071,21 @@ def _wrap_ifcond(ifcond, before, after):
return out
-def gen_enum_lookup(name, values, prefix=None):
+def gen_enum_lookup(name, members, prefix=None):
ret = mcgen('''
const QEnumLookup %(c_name)s_lookup = {
.array = (const char *const[]) {
''',
c_name=c_name(name))
- for value in values:
- index = c_enum_const(name, value, prefix)
+ for m in members:
+ ret += gen_if(m.ifcond)
+ index = c_enum_const(name, m.name, prefix)
ret += mcgen('''
- [%(index)s] = "%(value)s",
+ [%(index)s] = "%(name)s",
''',
- index=index, value=value)
+ index=index, name=m.name)
+ ret += gen_endif(m.ifcond)
ret += mcgen('''
},
@@ -2035,9 +2096,9 @@ const QEnumLookup %(c_name)s_lookup = {
return ret
-def gen_enum(name, values, prefix=None):
+def gen_enum(name, members, prefix=None):
# append automatically generated _MAX value
- enum_values = values + ['_MAX']
+ enum_members = members + [QAPISchemaMember('_MAX')]
ret = mcgen('''
@@ -2045,14 +2106,13 @@ typedef enum %(c_name)s {
''',
c_name=c_name(name))
- i = 0
- for value in enum_values:
+ for m in enum_members:
+ ret += gen_if(m.ifcond)
ret += mcgen('''
- %(c_enum)s = %(i)d,
+ %(c_enum)s,
''',
- c_enum=c_enum_const(name, value, prefix),
- i=i)
- i += 1
+ c_enum=c_enum_const(name, m.name, prefix))
+ ret += gen_endif(m.ifcond)
ret += mcgen('''
} %(c_name)s;
diff --git a/scripts/qapi/doc.py b/scripts/qapi/doc.py
index 987fd3c943..c03b690161 100755
--- a/scripts/qapi/doc.py
+++ b/scripts/qapi/doc.py
@@ -126,19 +126,27 @@ def texi_body(doc):
return texi_format(doc.body.text)
-def texi_enum_value(value):
+def texi_if(ifcond, prefix='\n', suffix='\n'):
+ """Format the #if condition"""
+ if not ifcond:
+ return ''
+ return '%s@b{If:} @code{%s}%s' % (prefix, ', '.join(ifcond), suffix)
+
+
+def texi_enum_value(value, desc, suffix):
"""Format a table of members item for an enumeration value"""
- return '@item @code{%s}\n' % value.name
+ return '@item @code{%s}\n%s%s' % (
+ value.name, desc, texi_if(value.ifcond, prefix='@*'))
-def texi_member(member, suffix=''):
+def texi_member(member, desc, suffix):
"""Format a table of members item for an object type member"""
typ = member.type.doc_type()
membertype = ': ' + typ if typ else ''
- return '@item @code{%s%s}%s%s\n' % (
+ return '@item @code{%s%s}%s%s\n%s%s' % (
member.name, membertype,
' (optional)' if member.optional else '',
- suffix)
+ suffix, desc, texi_if(member.ifcond, prefix='@*'))
def texi_members(doc, what, base, variants, member_func):
@@ -155,17 +163,17 @@ def texi_members(doc, what, base, variants, member_func):
desc = 'One of ' + members_text + '\n'
else:
desc = 'Not documented\n'
- items += member_func(section.member) + desc
+ items += member_func(section.member, desc, suffix='')
if base:
items += '@item The members of @code{%s}\n' % base.doc_type()
if variants:
for v in variants.variants:
- when = ' when @code{%s} is @t{"%s"}' % (
- variants.tag_member.name, v.name)
+ when = ' when @code{%s} is @t{"%s"}%s' % (
+ variants.tag_member.name, v.name, texi_if(v.ifcond, " (", ")"))
if v.type.is_implicit():
assert not v.type.base and not v.type.variants
for m in v.type.local_members:
- items += member_func(m, when)
+ items += member_func(m, desc='', suffix=when)
else:
items += '@item The members of @code{%s}%s\n' % (
v.type.doc_type(), when)
@@ -185,8 +193,7 @@ def texi_sections(doc, ifcond):
body += texi_example(section.text)
else:
body += texi_format(section.text)
- if ifcond:
- body += '\n\n@b{If:} @code{%s}' % ", ".join(ifcond)
+ body += texi_if(ifcond, suffix='')
return body
@@ -206,7 +213,7 @@ class QAPISchemaGenDocVisitor(qapi.common.QAPISchemaVisitor):
def write(self, output_dir):
self._gen.write(output_dir, self._prefix + 'qapi-doc.texi')
- def visit_enum_type(self, name, info, ifcond, values, prefix):
+ def visit_enum_type(self, name, info, ifcond, members, prefix):
doc = self.cur_doc
self._gen.add(TYPE_FMT(type='Enum',
name=doc.symbol,
diff --git a/scripts/qapi/events.py b/scripts/qapi/events.py
index 2ed7902424..37ee5de682 100644
--- a/scripts/qapi/events.py
+++ b/scripts/qapi/events.py
@@ -143,8 +143,8 @@ class QAPISchemaGenEventVisitor(QAPISchemaModularCVisitor):
QAPISchemaModularCVisitor.__init__(
self, prefix, 'qapi-events',
' * Schema-defined QAPI/QMP events', __doc__)
- self._enum_name = c_name(prefix + 'QAPIEvent', protect=False)
- self._event_names = []
+ self._event_enum_name = c_name(prefix + 'QAPIEvent', protect=False)
+ self._event_enum_members = []
def _begin_module(self, name):
types = self._module_basename('qapi-types', name)
@@ -170,15 +170,16 @@ class QAPISchemaGenEventVisitor(QAPISchemaModularCVisitor):
def visit_end(self):
(genc, genh) = self._module[self._main_module]
- genh.add(gen_enum(self._enum_name, self._event_names))
- genc.add(gen_enum_lookup(self._enum_name, self._event_names))
+ genh.add(gen_enum(self._event_enum_name, self._event_enum_members))
+ genc.add(gen_enum_lookup(self._event_enum_name,
+ self._event_enum_members))
def visit_event(self, name, info, ifcond, arg_type, boxed):
with ifcontext(ifcond, self._genh, self._genc):
self._genh.add(gen_event_send_decl(name, arg_type, boxed))
self._genc.add(gen_event_send(name, arg_type, boxed,
- self._enum_name))
- self._event_names.append(name)
+ self._event_enum_name))
+ self._event_enum_members.append(QAPISchemaMember(name, ifcond))
def gen_events(schema, output_dir, prefix):
diff --git a/scripts/qapi/introspect.py b/scripts/qapi/introspect.py
index 67d6106f77..f7f2ca07e4 100644
--- a/scripts/qapi/introspect.py
+++ b/scripts/qapi/introspect.py
@@ -162,6 +162,8 @@ const QLitObject %(c_name)s = %(c_string)s;
ret = {'name': member.name, 'type': self._use_type(member.type)}
if member.optional:
ret['default'] = None
+ if member.ifcond:
+ ret = (ret, {'if': member.ifcond})
return ret
def _gen_variants(self, tag_name, variants):
@@ -169,13 +171,17 @@ const QLitObject %(c_name)s = %(c_string)s;
'variants': [self._gen_variant(v) for v in variants]}
def _gen_variant(self, variant):
- return {'case': variant.name, 'type': self._use_type(variant.type)}
+ return ({'case': variant.name, 'type': self._use_type(variant.type)},
+ {'if': variant.ifcond})
def visit_builtin_type(self, name, info, json_type):
self._gen_qlit(name, 'builtin', {'json-type': json_type}, [])
- def visit_enum_type(self, name, info, ifcond, values, prefix):
- self._gen_qlit(name, 'enum', {'values': values}, ifcond)
+ def visit_enum_type(self, name, info, ifcond, members, prefix):
+ self._gen_qlit(name, 'enum',
+ {'values':
+ [(m.name, {'if': m.ifcond}) for m in members]},
+ ifcond)
def visit_array_type(self, name, info, ifcond, element_type):
element = self._use_type(element_type)
@@ -191,8 +197,9 @@ const QLitObject %(c_name)s = %(c_string)s;
def visit_alternate_type(self, name, info, ifcond, variants):
self._gen_qlit(name, 'alternate',
- {'members': [{'type': self._use_type(m.type)}
- for m in variants.variants]}, ifcond)
+ {'members': [
+ ({'type': self._use_type(m.type)}, {'if': m.ifcond})
+ for m in variants.variants]}, ifcond)
def visit_command(self, name, info, ifcond, arg_type, ret_type, gen,
success_response, boxed, allow_oob, allow_preconfig):
diff --git a/scripts/qapi/types.py b/scripts/qapi/types.py
index fd7808103c..62d4cf9f95 100644
--- a/scripts/qapi/types.py
+++ b/scripts/qapi/types.py
@@ -43,6 +43,7 @@ struct %(c_name)s {
def gen_struct_members(members):
ret = ''
for memb in members:
+ ret += gen_if(memb.ifcond)
if memb.optional:
ret += mcgen('''
bool has_%(c_name)s;
@@ -52,6 +53,7 @@ def gen_struct_members(members):
%(c_type)s %(c_name)s;
''',
c_type=memb.type.c_type(), c_name=c_name(memb.name))
+ ret += gen_endif(memb.ifcond)
return ret
@@ -131,11 +133,13 @@ def gen_variants(variants):
for var in variants.variants:
if var.type.name == 'q_empty':
continue
+ ret += gen_if(var.ifcond)
ret += mcgen('''
%(c_type)s %(c_name)s;
''',
c_type=var.type.c_unboxed_type(),
c_name=c_name(var.name))
+ ret += gen_endif(var.ifcond)
ret += mcgen('''
} u;
@@ -212,10 +216,10 @@ class QAPISchemaGenTypeVisitor(QAPISchemaModularCVisitor):
self._genh.add(gen_type_cleanup_decl(name))
self._genc.add(gen_type_cleanup(name))
- def visit_enum_type(self, name, info, ifcond, values, prefix):
+ def visit_enum_type(self, name, info, ifcond, members, prefix):
with ifcontext(ifcond, self._genh, self._genc):
- self._genh.preamble_add(gen_enum(name, values, prefix))
- self._genc.add(gen_enum_lookup(name, values, prefix))
+ self._genh.preamble_add(gen_enum(name, members, prefix))
+ self._genc.add(gen_enum_lookup(name, members, prefix))
def visit_array_type(self, name, info, ifcond, element_type):
with ifcontext(ifcond, self._genh, self._genc):
diff --git a/scripts/qapi/visit.py b/scripts/qapi/visit.py
index 460cf12989..82eab72b21 100644
--- a/scripts/qapi/visit.py
+++ b/scripts/qapi/visit.py
@@ -54,6 +54,7 @@ void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
c_type=base.c_name())
for memb in members:
+ ret += gen_if(memb.ifcond)
if memb.optional:
ret += mcgen('''
if (visit_optional(v, "%(name)s", &obj->has_%(c_name)s)) {
@@ -73,6 +74,7 @@ void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
ret += mcgen('''
}
''')
+ ret += gen_endif(memb.ifcond)
if variants:
ret += mcgen('''
@@ -84,6 +86,7 @@ void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
case_str = c_enum_const(variants.tag_member.type.name,
var.name,
variants.tag_member.type.prefix)
+ ret += gen_if(var.ifcond)
if var.type.name == 'q_empty':
# valid variant and nothing to do
ret += mcgen('''
@@ -100,6 +103,7 @@ void visit_type_%(c_name)s_members(Visitor *v, %(c_name)s *obj, Error **errp)
case=case_str,
c_type=var.type.c_name(), c_name=c_name(var.name))
+ ret += gen_endif(var.ifcond)
ret += mcgen('''
default:
abort();
@@ -190,6 +194,7 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error
c_name=c_name(name))
for var in variants.variants:
+ ret += gen_if(var.ifcond)
ret += mcgen('''
case %(case)s:
''',
@@ -217,6 +222,7 @@ void visit_type_%(c_name)s(Visitor *v, const char *name, %(c_name)s **obj, Error
ret += mcgen('''
break;
''')
+ ret += gen_endif(var.ifcond)
ret += mcgen('''
case QTYPE_NONE:
@@ -310,7 +316,7 @@ class QAPISchemaGenVisitVisitor(QAPISchemaModularCVisitor):
''',
types=types))
- def visit_enum_type(self, name, info, ifcond, values, prefix):
+ def visit_enum_type(self, name, info, ifcond, members, prefix):
with ifcontext(ifcond, self._genh, self._genc):
self._genh.add(gen_visit_decl(name, scalar=True))
self._genc.add(gen_visit_enum(name))
diff --git a/scripts/qemu.py b/scripts/qemu.py
index 6e3b0e6771..0a5e02eb56 100644
--- a/scripts/qemu.py
+++ b/scripts/qemu.py
@@ -351,7 +351,7 @@ class QEMUMachine(object):
command = ' '.join(self._qemu_full_args)
else:
command = ''
- LOG.warn(msg, exitcode, command)
+ LOG.warn(msg, -exitcode, command)
self._launched = False
diff --git a/scripts/replay-dump.py b/scripts/replay-dump.py
index 5ae77c8a92..ee7fda2638 100755
--- a/scripts/replay-dump.py
+++ b/scripts/replay-dump.py
@@ -3,7 +3,7 @@
#
# Dump the contents of a recorded execution stream
#
-# Copyright (c) 2017 Alex Bennée <alex.bennee@linaro.org>
+# Copyright (c) 2017 Alex Bennée <alex.bennee@linaro.org>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py
index 4ad34f90cd..45485b864b 100755
--- a/scripts/simpletrace.py
+++ b/scripts/simpletrace.py
@@ -11,7 +11,6 @@
from __future__ import print_function
import struct
-import re
import inspect
from tracetool import read_events, Event
from tracetool.backend.simple import is_string
diff --git a/scripts/tap-driver.pl b/scripts/tap-driver.pl
new file mode 100755
index 0000000000..5e59b5db49
--- /dev/null
+++ b/scripts/tap-driver.pl
@@ -0,0 +1,378 @@
+#! /usr/bin/env perl
+# Copyright (C) 2011-2013 Free Software Foundation, Inc.
+# Copyright (C) 2018 Red Hat, Inc.
+#
+# This program is free software; 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, or (at your option)
+# any later version.
+#
+# This program 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 program. If not, see <https://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# ---------------------------------- #
+# Imports, static data, and setup. #
+# ---------------------------------- #
+
+use warnings FATAL => 'all';
+use strict;
+use Getopt::Long ();
+use TAP::Parser;
+use Term::ANSIColor qw(:constants);
+
+my $ME = "tap-driver.pl";
+my $VERSION = "2018-11-30";
+
+my $USAGE = <<'END';
+Usage:
+ tap-driver [--test-name=TEST] [--color={always|never|auto}]
+ [--verbose] [--show-failures-only]
+END
+
+my $HELP = "$ME: TAP-aware test driver for QEMU testsuite harness." .
+ "\n" . $USAGE;
+
+# It's important that NO_PLAN evaluates "false" as a boolean.
+use constant NO_PLAN => 0;
+use constant EARLY_PLAN => 1;
+use constant LATE_PLAN => 2;
+
+use constant DIAG_STRING => "#";
+
+# ------------------- #
+# Global variables. #
+# ------------------- #
+
+my $testno = 0; # Number of test results seen so far.
+my $bailed_out = 0; # Whether a "Bail out!" directive has been seen.
+my $failed = 0; # Final exit code
+
+# Whether the TAP plan has been seen or not, and if yes, which kind
+# it is ("early" is seen before any test result, "late" otherwise).
+my $plan_seen = NO_PLAN;
+
+# ----------------- #
+# Option parsing. #
+# ----------------- #
+
+my %cfg = (
+ "color" => 0,
+ "verbose" => 0,
+ "show-failures-only" => 0,
+);
+
+my $color = "auto";
+my $test_name = undef;
+
+# Perl's Getopt::Long allows options to take optional arguments after a space.
+# Prevent --color by itself from consuming other arguments
+foreach (@ARGV) {
+ if ($_ eq "--color" || $_ eq "-color") {
+ $_ = "--color=$color";
+ }
+}
+
+Getopt::Long::GetOptions
+ (
+ 'help' => sub { print $HELP; exit 0; },
+ 'version' => sub { print "$ME $VERSION\n"; exit 0; },
+ 'test-name=s' => \$test_name,
+ 'color=s' => \$color,
+ 'show-failures-only' => sub { $cfg{"show-failures-only"} = 1; },
+ 'verbose' => sub { $cfg{"verbose"} = 1; },
+ ) or exit 1;
+
+if ($color =~ /^always$/i) {
+ $cfg{'color'} = 1;
+} elsif ($color =~ /^never$/i) {
+ $cfg{'color'} = 0;
+} elsif ($color =~ /^auto$/i) {
+ $cfg{'color'} = (-t STDOUT);
+} else {
+ die "Invalid color mode: $color\n";
+}
+
+# ------------- #
+# Prototypes. #
+# ------------- #
+
+sub colored ($$);
+sub decorate_result ($);
+sub extract_tap_comment ($);
+sub handle_tap_bailout ($);
+sub handle_tap_plan ($);
+sub handle_tap_result ($);
+sub is_null_string ($);
+sub main ();
+sub report ($;$);
+sub stringify_result_obj ($);
+sub testsuite_error ($);
+
+# -------------- #
+# Subroutines. #
+# -------------- #
+
+# If the given string is undefined or empty, return true, otherwise
+# return false. This function is useful to avoid pitfalls like:
+# if ($message) { print "$message\n"; }
+# which wouldn't print anything if $message is the literal "0".
+sub is_null_string ($)
+{
+ my $str = shift;
+ return ! (defined $str and length $str);
+}
+
+sub stringify_result_obj ($)
+{
+ my $result_obj = shift;
+ if ($result_obj->is_unplanned || $result_obj->number != $testno)
+ {
+ return "ERROR";
+ }
+ elsif ($plan_seen == LATE_PLAN)
+ {
+ return "ERROR";
+ }
+ elsif (!$result_obj->directive)
+ {
+ return $result_obj->is_ok ? "PASS" : "FAIL";
+ }
+ elsif ($result_obj->has_todo)
+ {
+ return $result_obj->is_actual_ok ? "XPASS" : "XFAIL";
+ }
+ elsif ($result_obj->has_skip)
+ {
+ return $result_obj->is_ok ? "SKIP" : "FAIL";
+ }
+ die "$ME: INTERNAL ERROR"; # NOTREACHED
+}
+
+sub colored ($$)
+{
+ my ($color_string, $text) = @_;
+ return $color_string . $text . RESET;
+}
+
+sub decorate_result ($)
+{
+ my $result = shift;
+ return $result unless $cfg{"color"};
+ my %color_for_result =
+ (
+ "ERROR" => BOLD.MAGENTA,
+ "PASS" => GREEN,
+ "XPASS" => BOLD.YELLOW,
+ "FAIL" => BOLD.RED,
+ "XFAIL" => YELLOW,
+ "SKIP" => BLUE,
+ );
+ if (my $color = $color_for_result{$result})
+ {
+ return colored ($color, $result);
+ }
+ else
+ {
+ return $result; # Don't colorize unknown stuff.
+ }
+}
+
+sub report ($;$)
+{
+ my ($msg, $result, $explanation) = (undef, @_);
+ if ($result =~ /^(?:X?(?:PASS|FAIL)|SKIP|ERROR)/)
+ {
+ # Output on console might be colorized.
+ $msg = decorate_result($result);
+ if ($result =~ /^(?:PASS|XFAIL|SKIP)/)
+ {
+ return if $cfg{"show-failures-only"};
+ }
+ else
+ {
+ $failed = 1;
+ }
+ }
+ elsif ($result eq "#")
+ {
+ $msg = " ";
+ }
+ else
+ {
+ die "$ME: INTERNAL ERROR"; # NOTREACHED
+ }
+ $msg .= " $explanation" if defined $explanation;
+ print $msg . "\n";
+}
+
+sub testsuite_error ($)
+{
+ report "ERROR", "- $_[0]";
+}
+
+sub handle_tap_result ($)
+{
+ $testno++;
+ my $result_obj = shift;
+
+ my $test_result = stringify_result_obj $result_obj;
+ my $string = $result_obj->number;
+
+ my $description = $result_obj->description;
+ $string .= " $test_name" unless is_null_string $test_name;
+ $string .= " $description" unless is_null_string $description;
+
+ if ($plan_seen == LATE_PLAN)
+ {
+ $string .= " # AFTER LATE PLAN";
+ }
+ elsif ($result_obj->is_unplanned)
+ {
+ $string .= " # UNPLANNED";
+ }
+ elsif ($result_obj->number != $testno)
+ {
+ $string .= " # OUT-OF-ORDER (expecting $testno)";
+ }
+ elsif (my $directive = $result_obj->directive)
+ {
+ $string .= " # $directive";
+ my $explanation = $result_obj->explanation;
+ $string .= " $explanation"
+ unless is_null_string $explanation;
+ }
+
+ report $test_result, $string;
+}
+
+sub handle_tap_plan ($)
+{
+ my $plan = shift;
+ if ($plan_seen)
+ {
+ # Error, only one plan per stream is acceptable.
+ testsuite_error "multiple test plans";
+ return;
+ }
+ # The TAP plan can come before or after *all* the TAP results; we speak
+ # respectively of an "early" or a "late" plan. If we see the plan line
+ # after at least one TAP result has been seen, assume we have a late
+ # plan; in this case, any further test result seen after the plan will
+ # be flagged as an error.
+ $plan_seen = ($testno >= 1 ? LATE_PLAN : EARLY_PLAN);
+ # If $testno > 0, we have an error ("too many tests run") that will be
+ # automatically dealt with later, so don't worry about it here. If
+ # $plan_seen is true, we have an error due to a repeated plan, and that
+ # has already been dealt with above. Otherwise, we have a valid "plan
+ # with SKIP" specification, and should report it as a particular kind
+ # of SKIP result.
+ if ($plan->directive && $testno == 0)
+ {
+ my $explanation = is_null_string ($plan->explanation) ?
+ undef : "- " . $plan->explanation;
+ report "SKIP", $explanation;
+ }
+}
+
+sub handle_tap_bailout ($)
+{
+ my ($bailout, $msg) = ($_[0], "Bail out!");
+ $bailed_out = 1;
+ $msg .= " " . $bailout->explanation
+ unless is_null_string $bailout->explanation;
+ testsuite_error $msg;
+}
+
+sub extract_tap_comment ($)
+{
+ my $line = shift;
+ if (index ($line, DIAG_STRING) == 0)
+ {
+ # Strip leading `DIAG_STRING' from `$line'.
+ $line = substr ($line, length (DIAG_STRING));
+ # And strip any leading and trailing whitespace left.
+ $line =~ s/(?:^\s*|\s*$)//g;
+ # Return what is left (if any).
+ return $line;
+ }
+ return "";
+}
+
+sub main ()
+{
+ my $iterator = TAP::Parser::Iterator::Stream->new(\*STDIN);
+ my $parser = TAP::Parser->new ({iterator => $iterator });
+
+ while (defined (my $cur = $parser->next))
+ {
+ # Parsing of TAP input should stop after a "Bail out!" directive.
+ next if $bailed_out;
+
+ if ($cur->is_plan)
+ {
+ handle_tap_plan ($cur);
+ }
+ elsif ($cur->is_test)
+ {
+ handle_tap_result ($cur);
+ }
+ elsif ($cur->is_bailout)
+ {
+ handle_tap_bailout ($cur);
+ }
+ elsif ($cfg{"verbose"})
+ {
+ my $comment = extract_tap_comment ($cur->raw);
+ report "#", "$comment" if length $comment;
+ }
+ }
+ # A "Bail out!" directive should cause us to ignore any following TAP
+ # error.
+ if (!$bailed_out)
+ {
+ if (!$plan_seen)
+ {
+ testsuite_error "missing test plan";
+ }
+ elsif ($parser->tests_planned != $parser->tests_run)
+ {
+ my ($planned, $run) = ($parser->tests_planned, $parser->tests_run);
+ my $bad_amount = $run > $planned ? "many" : "few";
+ testsuite_error (sprintf "too %s tests run (expected %d, got %d)",
+ $bad_amount, $planned, $run);
+ }
+ }
+}
+
+# ----------- #
+# Main code. #
+# ----------- #
+
+main;
+exit($failed);
+
+# Local Variables:
+# perl-indent-level: 2
+# perl-continued-statement-offset: 2
+# perl-continued-brace-offset: 0
+# perl-brace-offset: 0
+# perl-brace-imaginary-offset: 0
+# perl-label-offset: -2
+# cperl-indent-level: 2
+# cperl-brace-offset: 0
+# cperl-continued-brace-offset: 0
+# cperl-label-offset: -2
+# cperl-extra-newline-before-brace: t
+# cperl-merge-trailing-else: nil
+# cperl-continued-statement-offset: 2
+# End:
diff --git a/scripts/tap-merge.pl b/scripts/tap-merge.pl
new file mode 100755
index 0000000000..59e3fa5007
--- /dev/null
+++ b/scripts/tap-merge.pl
@@ -0,0 +1,110 @@
+#! /usr/bin/env perl
+# Copyright (C) 2018 Red Hat, Inc.
+#
+# Author: Paolo Bonzini <pbonzini@redhat.com>
+#
+# This program is free software; 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, or (at your option)
+# any later version.
+#
+# This program 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 program. If not, see <https://www.gnu.org/licenses/>.
+
+# ---------------------------------- #
+# Imports, static data, and setup. #
+# ---------------------------------- #
+
+use warnings FATAL => 'all';
+use strict;
+use Getopt::Long ();
+use TAP::Parser;
+
+my $ME = "tap-merge.pl";
+my $VERSION = "2018-11-30";
+
+my $HELP = "$ME: merge multiple TAP inputs from stdin.";
+
+use constant DIAG_STRING => "#";
+
+# ----------------- #
+# Option parsing. #
+# ----------------- #
+
+Getopt::Long::GetOptions
+ (
+ 'help' => sub { print $HELP; exit 0; },
+ 'version' => sub { print "$ME $VERSION\n"; exit 0; },
+ );
+
+# -------------- #
+# Subroutines. #
+# -------------- #
+
+sub main ()
+{
+ my $iterator = TAP::Parser::Iterator::Stream->new(\*STDIN);
+ my $parser = TAP::Parser->new ({iterator => $iterator });
+ my $testno = 0; # Number of test results seen so far.
+ my $bailed_out = 0; # Whether a "Bail out!" directive has been seen.
+
+ while (defined (my $cur = $parser->next))
+ {
+ if ($cur->is_bailout)
+ {
+ $bailed_out = 1;
+ print DIAG_STRING . " " . $cur->as_string . "\n";
+ next;
+ }
+ elsif ($cur->is_plan)
+ {
+ $bailed_out = 0;
+ next;
+ }
+ elsif ($cur->is_test)
+ {
+ $bailed_out = 0 if $cur->number == 1;
+ $testno++;
+ $cur = TAP::Parser::Result::Test->new({
+ ok => $cur->ok,
+ test_num => $testno,
+ directive => $cur->directive,
+ explanation => $cur->explanation,
+ description => $cur->description
+ });
+ }
+ elsif ($cur->is_version)
+ {
+ next if $testno > 0;
+ }
+ print $cur->as_string . "\n" unless $bailed_out;
+ }
+ print "1..$testno\n";
+}
+
+# ----------- #
+# Main code. #
+# ----------- #
+
+main;
+
+# Local Variables:
+# perl-indent-level: 2
+# perl-continued-statement-offset: 2
+# perl-continued-brace-offset: 0
+# perl-brace-offset: 0
+# perl-brace-imaginary-offset: 0
+# perl-label-offset: -2
+# cperl-indent-level: 2
+# cperl-brace-offset: 0
+# cperl-continued-brace-offset: 0
+# cperl-label-offset: -2
+# cperl-extra-newline-before-brace: t
+# cperl-merge-trailing-else: nil
+# cperl-continued-statement-offset: 2
+# End:
diff --git a/scripts/texi2pod.pl b/scripts/texi2pod.pl
index 39ce584a32..839b7917cf 100755
--- a/scripts/texi2pod.pl
+++ b/scripts/texi2pod.pl
@@ -398,7 +398,7 @@ $sects{NAME} = "$fn \- $tl\n";
$sects{FOOTNOTES} .= "=back\n" if exists $sects{FOOTNOTES};
for $sect (qw(NAME SYNOPSIS DESCRIPTION OPTIONS ENVIRONMENT FILES
- BUGS NOTES FOOTNOTES SEEALSO AUTHOR COPYRIGHT)) {
+ BUGS NOTES FOOTNOTES EXAMPLES SEEALSO AUTHOR COPYRIGHT)) {
if(exists $sects{$sect}) {
$head = $sect;
$head =~ s/SEEALSO/SEE ALSO/;
diff --git a/scripts/tracetool.py b/scripts/tracetool.py
index fe2b0771f2..3beaa66bd8 100755
--- a/scripts/tracetool.py
+++ b/scripts/tracetool.py
@@ -15,8 +15,6 @@ __email__ = "stefanha@linux.vnet.ibm.com"
import sys
import getopt
-import os.path
-import re
from tracetool import error_write, out
import tracetool.backend
diff --git a/scripts/tracetool/backend/log.py b/scripts/tracetool/backend/log.py
index 6751f41bc5..33c95af8e9 100644
--- a/scripts/tracetool/backend/log.py
+++ b/scripts/tracetool/backend/log.py
@@ -39,7 +39,7 @@ def generate_h(event, group):
' struct timeval _now;',
' gettimeofday(&_now, NULL);',
' qemu_log("%%d@%%zu.%%06zu:%(name)s " %(fmt)s "\\n",',
- ' getpid(),',
+ ' qemu_get_thread_id(),',
' (size_t)_now.tv_sec, (size_t)_now.tv_usec',
' %(argnames)s);',
' }',
diff --git a/scripts/tracetool/format/simpletrace_stap.py b/scripts/tracetool/format/simpletrace_stap.py
index e7e44842ca..57b04061cf 100644
--- a/scripts/tracetool/format/simpletrace_stap.py
+++ b/scripts/tracetool/format/simpletrace_stap.py
@@ -14,7 +14,7 @@ __email__ = "stefanha@redhat.com"
from tracetool import out
-from tracetool.backend.dtrace import binary, probeprefix
+from tracetool.backend.dtrace import probeprefix
from tracetool.backend.simple import is_string
from tracetool.format.stap import stap_escape