import
This commit is contained in:
116
qemu/scripts/create_config
Executable file
116
qemu/scripts/create_config
Executable file
@@ -0,0 +1,116 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "/* Automatically generated by create_config - do not modify */"
|
||||
|
||||
while read line; do
|
||||
|
||||
case $line in
|
||||
VERSION=*) # configuration
|
||||
version=${line#*=}
|
||||
echo "#define QEMU_VERSION \"$version\""
|
||||
;;
|
||||
PKGVERSION=*) # configuration
|
||||
pkgversion=${line#*=}
|
||||
echo "#define QEMU_PKGVERSION \"$pkgversion\""
|
||||
;;
|
||||
qemu_*dir=*) # qemu-specific directory configuration
|
||||
name=${line%=*}
|
||||
value=${line#*=}
|
||||
define_name=`echo $name | LC_ALL=C tr '[a-z]' '[A-Z]'`
|
||||
eval "define_value=\"$value\""
|
||||
echo "#define CONFIG_$define_name \"$define_value\""
|
||||
# save for the next definitions
|
||||
eval "$name=\$define_value"
|
||||
;;
|
||||
prefix=*)
|
||||
# save for the next definitions
|
||||
prefix=${line#*=}
|
||||
;;
|
||||
IASL=*) # iasl executable
|
||||
value=${line#*=}
|
||||
echo "#define CONFIG_IASL $value"
|
||||
;;
|
||||
CONFIG_AUDIO_DRIVERS=*)
|
||||
drivers=${line#*=}
|
||||
echo "#define CONFIG_AUDIO_DRIVERS \\"
|
||||
for drv in $drivers; do
|
||||
echo " &${drv}_audio_driver,\\"
|
||||
done
|
||||
echo ""
|
||||
;;
|
||||
CONFIG_BDRV_RW_WHITELIST=*)
|
||||
echo "#define CONFIG_BDRV_RW_WHITELIST\\"
|
||||
for drv in ${line#*=}; do
|
||||
echo " \"${drv}\",\\"
|
||||
done
|
||||
echo " NULL"
|
||||
;;
|
||||
CONFIG_BDRV_RO_WHITELIST=*)
|
||||
echo "#define CONFIG_BDRV_RO_WHITELIST\\"
|
||||
for drv in ${line#*=}; do
|
||||
echo " \"${drv}\",\\"
|
||||
done
|
||||
echo " NULL"
|
||||
;;
|
||||
CONFIG_*=y) # configuration
|
||||
name=${line%=*}
|
||||
echo "#define $name 1"
|
||||
;;
|
||||
CONFIG_*=*) # configuration
|
||||
name=${line%=*}
|
||||
value=${line#*=}
|
||||
echo "#define $name $value"
|
||||
;;
|
||||
ARCH=*) # configuration
|
||||
arch=${line#*=}
|
||||
arch_name=`echo $arch | LC_ALL=C tr '[a-z]' '[A-Z]'`
|
||||
echo "#define HOST_$arch_name 1"
|
||||
;;
|
||||
HOST_USB=*)
|
||||
# do nothing
|
||||
;;
|
||||
HOST_CC=*)
|
||||
# do nothing
|
||||
;;
|
||||
HOST_*=y) # configuration
|
||||
name=${line%=*}
|
||||
echo "#define $name 1"
|
||||
;;
|
||||
HOST_*=*) # configuration
|
||||
name=${line%=*}
|
||||
value=${line#*=}
|
||||
echo "#define $name $value"
|
||||
;;
|
||||
TARGET_BASE_ARCH=*) # configuration
|
||||
target_base_arch=${line#*=}
|
||||
base_arch_name=`echo $target_base_arch | LC_ALL=C tr '[a-z]' '[A-Z]'`
|
||||
echo "#define TARGET_$base_arch_name 1"
|
||||
;;
|
||||
TARGET_XML_FILES=*)
|
||||
# do nothing
|
||||
;;
|
||||
TARGET_ABI_DIR=*)
|
||||
# do nothing
|
||||
;;
|
||||
TARGET_NAME=*)
|
||||
target_name=${line#*=}
|
||||
echo "#define TARGET_NAME \"$target_name\""
|
||||
;;
|
||||
TARGET_DIRS=*)
|
||||
# do nothing
|
||||
;;
|
||||
TARGET_*=y) # configuration
|
||||
name=${line%=*}
|
||||
echo "#define $name 1"
|
||||
;;
|
||||
TARGET_*=*) # configuration
|
||||
name=${line%=*}
|
||||
value=${line#*=}
|
||||
echo "#define $name $value"
|
||||
;;
|
||||
DSOSUF=*)
|
||||
echo "#define HOST_DSOSUF \"${line#*=}\""
|
||||
;;
|
||||
esac
|
||||
|
||||
done # read
|
||||
339
qemu/scripts/dump-guest-memory.py
Normal file
339
qemu/scripts/dump-guest-memory.py
Normal file
@@ -0,0 +1,339 @@
|
||||
# This python script adds a new gdb command, "dump-guest-memory". It
|
||||
# should be loaded with "source dump-guest-memory.py" at the (gdb)
|
||||
# prompt.
|
||||
#
|
||||
# Copyright (C) 2013, Red Hat, Inc.
|
||||
#
|
||||
# Authors:
|
||||
# Laszlo Ersek <lersek@redhat.com>
|
||||
#
|
||||
# This work is licensed under the terms of the GNU GPL, version 2 or later. See
|
||||
# the COPYING file in the top-level directory.
|
||||
#
|
||||
# The leading docstring doesn't have idiomatic Python formatting. It is
|
||||
# printed by gdb's "help" command (the first line is printed in the
|
||||
# "help data" summary), and it should match how other help texts look in
|
||||
# gdb.
|
||||
|
||||
import struct
|
||||
|
||||
class DumpGuestMemory(gdb.Command):
|
||||
"""Extract guest vmcore from qemu process coredump.
|
||||
|
||||
The sole argument is FILE, identifying the target file to write the
|
||||
guest vmcore to.
|
||||
|
||||
This GDB command reimplements the dump-guest-memory QMP command in
|
||||
python, using the representation of guest memory as captured in the qemu
|
||||
coredump. The qemu process that has been dumped must have had the
|
||||
command line option "-machine dump-guest-core=on".
|
||||
|
||||
For simplicity, the "paging", "begin" and "end" parameters of the QMP
|
||||
command are not supported -- no attempt is made to get the guest's
|
||||
internal paging structures (ie. paging=false is hard-wired), and guest
|
||||
memory is always fully dumped.
|
||||
|
||||
Only x86_64 guests are supported.
|
||||
|
||||
The CORE/NT_PRSTATUS and QEMU notes (that is, the VCPUs' statuses) are
|
||||
not written to the vmcore. Preparing these would require context that is
|
||||
only present in the KVM host kernel module when the guest is alive. A
|
||||
fake ELF note is written instead, only to keep the ELF parser of "crash"
|
||||
happy.
|
||||
|
||||
Dependent on how busted the qemu process was at the time of the
|
||||
coredump, this command might produce unpredictable results. If qemu
|
||||
deliberately called abort(), or it was dumped in response to a signal at
|
||||
a halfway fortunate point, then its coredump should be in reasonable
|
||||
shape and this command should mostly work."""
|
||||
|
||||
TARGET_PAGE_SIZE = 0x1000
|
||||
TARGET_PAGE_MASK = 0xFFFFFFFFFFFFF000
|
||||
|
||||
# Various ELF constants
|
||||
EM_X86_64 = 62 # AMD x86-64 target machine
|
||||
ELFDATA2LSB = 1 # little endian
|
||||
ELFCLASS64 = 2
|
||||
ELFMAG = "\x7FELF"
|
||||
EV_CURRENT = 1
|
||||
ET_CORE = 4
|
||||
PT_LOAD = 1
|
||||
PT_NOTE = 4
|
||||
|
||||
# Special value for e_phnum. This indicates that the real number of
|
||||
# program headers is too large to fit into e_phnum. Instead the real
|
||||
# value is in the field sh_info of section 0.
|
||||
PN_XNUM = 0xFFFF
|
||||
|
||||
# Format strings for packing and header size calculation.
|
||||
ELF64_EHDR = ("4s" # e_ident/magic
|
||||
"B" # e_ident/class
|
||||
"B" # e_ident/data
|
||||
"B" # e_ident/version
|
||||
"B" # e_ident/osabi
|
||||
"8s" # e_ident/pad
|
||||
"H" # e_type
|
||||
"H" # e_machine
|
||||
"I" # e_version
|
||||
"Q" # e_entry
|
||||
"Q" # e_phoff
|
||||
"Q" # e_shoff
|
||||
"I" # e_flags
|
||||
"H" # e_ehsize
|
||||
"H" # e_phentsize
|
||||
"H" # e_phnum
|
||||
"H" # e_shentsize
|
||||
"H" # e_shnum
|
||||
"H" # e_shstrndx
|
||||
)
|
||||
ELF64_PHDR = ("I" # p_type
|
||||
"I" # p_flags
|
||||
"Q" # p_offset
|
||||
"Q" # p_vaddr
|
||||
"Q" # p_paddr
|
||||
"Q" # p_filesz
|
||||
"Q" # p_memsz
|
||||
"Q" # p_align
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
super(DumpGuestMemory, self).__init__("dump-guest-memory",
|
||||
gdb.COMMAND_DATA,
|
||||
gdb.COMPLETE_FILENAME)
|
||||
self.uintptr_t = gdb.lookup_type("uintptr_t")
|
||||
self.elf64_ehdr_le = struct.Struct("<%s" % self.ELF64_EHDR)
|
||||
self.elf64_phdr_le = struct.Struct("<%s" % self.ELF64_PHDR)
|
||||
|
||||
def int128_get64(self, val):
|
||||
assert (val["hi"] == 0)
|
||||
return val["lo"]
|
||||
|
||||
def qtailq_foreach(self, head, field_str):
|
||||
var_p = head["tqh_first"]
|
||||
while (var_p != 0):
|
||||
var = var_p.dereference()
|
||||
yield var
|
||||
var_p = var[field_str]["tqe_next"]
|
||||
|
||||
def qemu_get_ram_block(self, ram_addr):
|
||||
ram_blocks = gdb.parse_and_eval("ram_list.blocks")
|
||||
for block in self.qtailq_foreach(ram_blocks, "next"):
|
||||
if (ram_addr - block["offset"] < block["length"]):
|
||||
return block
|
||||
raise gdb.GdbError("Bad ram offset %x" % ram_addr)
|
||||
|
||||
def qemu_get_ram_ptr(self, ram_addr):
|
||||
block = self.qemu_get_ram_block(ram_addr)
|
||||
return block["host"] + (ram_addr - block["offset"])
|
||||
|
||||
def memory_region_get_ram_ptr(self, mr):
|
||||
if (mr["alias"] != 0):
|
||||
return (self.memory_region_get_ram_ptr(mr["alias"].dereference()) +
|
||||
mr["alias_offset"])
|
||||
return self.qemu_get_ram_ptr(mr["ram_addr"] & self.TARGET_PAGE_MASK)
|
||||
|
||||
def guest_phys_blocks_init(self):
|
||||
self.guest_phys_blocks = []
|
||||
|
||||
def guest_phys_blocks_append(self):
|
||||
print "guest RAM blocks:"
|
||||
print ("target_start target_end host_addr message "
|
||||
"count")
|
||||
print ("---------------- ---------------- ---------------- ------- "
|
||||
"-----")
|
||||
|
||||
current_map_p = gdb.parse_and_eval("address_space_memory.current_map")
|
||||
current_map = current_map_p.dereference()
|
||||
for cur in range(current_map["nr"]):
|
||||
flat_range = (current_map["ranges"] + cur).dereference()
|
||||
mr = flat_range["mr"].dereference()
|
||||
|
||||
# we only care about RAM
|
||||
if (not mr["ram"]):
|
||||
continue
|
||||
|
||||
section_size = self.int128_get64(flat_range["addr"]["size"])
|
||||
target_start = self.int128_get64(flat_range["addr"]["start"])
|
||||
target_end = target_start + section_size
|
||||
host_addr = (self.memory_region_get_ram_ptr(mr) +
|
||||
flat_range["offset_in_region"])
|
||||
predecessor = None
|
||||
|
||||
# find continuity in guest physical address space
|
||||
if (len(self.guest_phys_blocks) > 0):
|
||||
predecessor = self.guest_phys_blocks[-1]
|
||||
predecessor_size = (predecessor["target_end"] -
|
||||
predecessor["target_start"])
|
||||
|
||||
# the memory API guarantees monotonically increasing
|
||||
# traversal
|
||||
assert (predecessor["target_end"] <= target_start)
|
||||
|
||||
# we want continuity in both guest-physical and
|
||||
# host-virtual memory
|
||||
if (predecessor["target_end"] < target_start or
|
||||
predecessor["host_addr"] + predecessor_size != host_addr):
|
||||
predecessor = None
|
||||
|
||||
if (predecessor is None):
|
||||
# isolated mapping, add it to the list
|
||||
self.guest_phys_blocks.append({"target_start": target_start,
|
||||
"target_end" : target_end,
|
||||
"host_addr" : host_addr})
|
||||
message = "added"
|
||||
else:
|
||||
# expand predecessor until @target_end; predecessor's
|
||||
# start doesn't change
|
||||
predecessor["target_end"] = target_end
|
||||
message = "joined"
|
||||
|
||||
print ("%016x %016x %016x %-7s %5u" %
|
||||
(target_start, target_end, host_addr.cast(self.uintptr_t),
|
||||
message, len(self.guest_phys_blocks)))
|
||||
|
||||
def cpu_get_dump_info(self):
|
||||
# We can't synchronize the registers with KVM post-mortem, and
|
||||
# the bits in (first_x86_cpu->env.hflags) seem to be stale; they
|
||||
# may not reflect long mode for example. Hence just assume the
|
||||
# most common values. This also means that instruction pointer
|
||||
# etc. will be bogus in the dump, but at least the RAM contents
|
||||
# should be valid.
|
||||
self.dump_info = {"d_machine": self.EM_X86_64,
|
||||
"d_endian" : self.ELFDATA2LSB,
|
||||
"d_class" : self.ELFCLASS64}
|
||||
|
||||
def encode_elf64_ehdr_le(self):
|
||||
return self.elf64_ehdr_le.pack(
|
||||
self.ELFMAG, # e_ident/magic
|
||||
self.dump_info["d_class"], # e_ident/class
|
||||
self.dump_info["d_endian"], # e_ident/data
|
||||
self.EV_CURRENT, # e_ident/version
|
||||
0, # e_ident/osabi
|
||||
"", # e_ident/pad
|
||||
self.ET_CORE, # e_type
|
||||
self.dump_info["d_machine"], # e_machine
|
||||
self.EV_CURRENT, # e_version
|
||||
0, # e_entry
|
||||
self.elf64_ehdr_le.size, # e_phoff
|
||||
0, # e_shoff
|
||||
0, # e_flags
|
||||
self.elf64_ehdr_le.size, # e_ehsize
|
||||
self.elf64_phdr_le.size, # e_phentsize
|
||||
self.phdr_num, # e_phnum
|
||||
0, # e_shentsize
|
||||
0, # e_shnum
|
||||
0 # e_shstrndx
|
||||
)
|
||||
|
||||
def encode_elf64_note_le(self):
|
||||
return self.elf64_phdr_le.pack(self.PT_NOTE, # p_type
|
||||
0, # p_flags
|
||||
(self.memory_offset -
|
||||
len(self.note)), # p_offset
|
||||
0, # p_vaddr
|
||||
0, # p_paddr
|
||||
len(self.note), # p_filesz
|
||||
len(self.note), # p_memsz
|
||||
0 # p_align
|
||||
)
|
||||
|
||||
def encode_elf64_load_le(self, offset, start_hwaddr, range_size):
|
||||
return self.elf64_phdr_le.pack(self.PT_LOAD, # p_type
|
||||
0, # p_flags
|
||||
offset, # p_offset
|
||||
0, # p_vaddr
|
||||
start_hwaddr, # p_paddr
|
||||
range_size, # p_filesz
|
||||
range_size, # p_memsz
|
||||
0 # p_align
|
||||
)
|
||||
|
||||
def note_init(self, name, desc, type):
|
||||
# name must include a trailing NUL
|
||||
namesz = (len(name) + 1 + 3) / 4 * 4
|
||||
descsz = (len(desc) + 3) / 4 * 4
|
||||
fmt = ("<" # little endian
|
||||
"I" # n_namesz
|
||||
"I" # n_descsz
|
||||
"I" # n_type
|
||||
"%us" # name
|
||||
"%us" # desc
|
||||
% (namesz, descsz))
|
||||
self.note = struct.pack(fmt,
|
||||
len(name) + 1, len(desc), type, name, desc)
|
||||
|
||||
def dump_init(self):
|
||||
self.guest_phys_blocks_init()
|
||||
self.guest_phys_blocks_append()
|
||||
self.cpu_get_dump_info()
|
||||
# we have no way to retrieve the VCPU status from KVM
|
||||
# post-mortem
|
||||
self.note_init("NONE", "EMPTY", 0)
|
||||
|
||||
# Account for PT_NOTE.
|
||||
self.phdr_num = 1
|
||||
|
||||
# We should never reach PN_XNUM for paging=false dumps: there's
|
||||
# just a handful of discontiguous ranges after merging.
|
||||
self.phdr_num += len(self.guest_phys_blocks)
|
||||
assert (self.phdr_num < self.PN_XNUM)
|
||||
|
||||
# Calculate the ELF file offset where the memory dump commences:
|
||||
#
|
||||
# ELF header
|
||||
# PT_NOTE
|
||||
# PT_LOAD: 1
|
||||
# PT_LOAD: 2
|
||||
# ...
|
||||
# PT_LOAD: len(self.guest_phys_blocks)
|
||||
# ELF note
|
||||
# memory dump
|
||||
self.memory_offset = (self.elf64_ehdr_le.size +
|
||||
self.elf64_phdr_le.size * self.phdr_num +
|
||||
len(self.note))
|
||||
|
||||
def dump_begin(self, vmcore):
|
||||
vmcore.write(self.encode_elf64_ehdr_le())
|
||||
vmcore.write(self.encode_elf64_note_le())
|
||||
running = self.memory_offset
|
||||
for block in self.guest_phys_blocks:
|
||||
range_size = block["target_end"] - block["target_start"]
|
||||
vmcore.write(self.encode_elf64_load_le(running,
|
||||
block["target_start"],
|
||||
range_size))
|
||||
running += range_size
|
||||
vmcore.write(self.note)
|
||||
|
||||
def dump_iterate(self, vmcore):
|
||||
qemu_core = gdb.inferiors()[0]
|
||||
for block in self.guest_phys_blocks:
|
||||
cur = block["host_addr"]
|
||||
left = block["target_end"] - block["target_start"]
|
||||
print ("dumping range at %016x for length %016x" %
|
||||
(cur.cast(self.uintptr_t), left))
|
||||
while (left > 0):
|
||||
chunk_size = min(self.TARGET_PAGE_SIZE, left)
|
||||
chunk = qemu_core.read_memory(cur, chunk_size)
|
||||
vmcore.write(chunk)
|
||||
cur += chunk_size
|
||||
left -= chunk_size
|
||||
|
||||
def create_vmcore(self, filename):
|
||||
vmcore = open(filename, "wb")
|
||||
self.dump_begin(vmcore)
|
||||
self.dump_iterate(vmcore)
|
||||
vmcore.close()
|
||||
|
||||
def invoke(self, args, from_tty):
|
||||
# Unwittingly pressing the Enter key after the command should
|
||||
# not dump the same multi-gig coredump to the same file.
|
||||
self.dont_repeat()
|
||||
|
||||
argv = gdb.string_to_argv(args)
|
||||
if (len(argv) != 1):
|
||||
raise gdb.GdbError("usage: dump-guest-memory FILE")
|
||||
|
||||
self.dump_init()
|
||||
self.create_vmcore(argv[0])
|
||||
|
||||
DumpGuestMemory()
|
||||
28
qemu/scripts/make_device_config.sh
Normal file
28
qemu/scripts/make_device_config.sh
Normal file
@@ -0,0 +1,28 @@
|
||||
#! /bin/sh
|
||||
# Construct a target device config file from a default, pulling in any
|
||||
# files from include directives.
|
||||
|
||||
dest=$1.tmp
|
||||
dep=`dirname $1`-`basename $1`.d
|
||||
src=$2
|
||||
src_dir=`dirname $src`
|
||||
all_includes=
|
||||
|
||||
process_includes () {
|
||||
cat $1 | grep '^include' | \
|
||||
while read include file ; do
|
||||
all_includes="$all_includes $src_dir/$file"
|
||||
process_includes $src_dir/$file
|
||||
done
|
||||
}
|
||||
|
||||
f=$src
|
||||
while [ -n "$f" ] ; do
|
||||
f=`cat $f | tr -d '\r' | awk '/^include / {printf "'$src_dir'/%s ", $2}'`
|
||||
[ $? = 0 ] || exit 1
|
||||
all_includes="$all_includes $f"
|
||||
done
|
||||
process_includes $src > $dest
|
||||
|
||||
cat $src $all_includes | grep -v '^include' > $dest
|
||||
echo "$1: $all_includes" > $dep
|
||||
127
qemu/scripts/ordereddict.py
Normal file
127
qemu/scripts/ordereddict.py
Normal file
@@ -0,0 +1,127 @@
|
||||
# Copyright (c) 2009 Raymond Hettinger
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person
|
||||
# obtaining a copy of this software and associated documentation files
|
||||
# (the "Software"), to deal in the Software without restriction,
|
||||
# including without limitation the rights to use, copy, modify, merge,
|
||||
# publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
# and to permit persons to whom the Software is furnished to do so,
|
||||
# subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
# OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
from UserDict import DictMixin
|
||||
|
||||
class OrderedDict(dict, DictMixin):
|
||||
|
||||
def __init__(self, *args, **kwds):
|
||||
if len(args) > 1:
|
||||
raise TypeError('expected at most 1 arguments, got %d' % len(args))
|
||||
try:
|
||||
self.__end
|
||||
except AttributeError:
|
||||
self.clear()
|
||||
self.update(*args, **kwds)
|
||||
|
||||
def clear(self):
|
||||
self.__end = end = []
|
||||
end += [None, end, end] # sentinel node for doubly linked list
|
||||
self.__map = {} # key --> [key, prev, next]
|
||||
dict.clear(self)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
if key not in self:
|
||||
end = self.__end
|
||||
curr = end[1]
|
||||
curr[2] = end[1] = self.__map[key] = [key, curr, end]
|
||||
dict.__setitem__(self, key, value)
|
||||
|
||||
def __delitem__(self, key):
|
||||
dict.__delitem__(self, key)
|
||||
key, prev, next = self.__map.pop(key)
|
||||
prev[2] = next
|
||||
next[1] = prev
|
||||
|
||||
def __iter__(self):
|
||||
end = self.__end
|
||||
curr = end[2]
|
||||
while curr is not end:
|
||||
yield curr[0]
|
||||
curr = curr[2]
|
||||
|
||||
def __reversed__(self):
|
||||
end = self.__end
|
||||
curr = end[1]
|
||||
while curr is not end:
|
||||
yield curr[0]
|
||||
curr = curr[1]
|
||||
|
||||
def popitem(self, last=True):
|
||||
if not self:
|
||||
raise KeyError('dictionary is empty')
|
||||
if last:
|
||||
key = reversed(self).next()
|
||||
else:
|
||||
key = iter(self).next()
|
||||
value = self.pop(key)
|
||||
return key, value
|
||||
|
||||
def __reduce__(self):
|
||||
items = [[k, self[k]] for k in self]
|
||||
tmp = self.__map, self.__end
|
||||
del self.__map, self.__end
|
||||
inst_dict = vars(self).copy()
|
||||
self.__map, self.__end = tmp
|
||||
if inst_dict:
|
||||
return (self.__class__, (items,), inst_dict)
|
||||
return self.__class__, (items,)
|
||||
|
||||
def keys(self):
|
||||
return list(self)
|
||||
|
||||
setdefault = DictMixin.setdefault
|
||||
update = DictMixin.update
|
||||
pop = DictMixin.pop
|
||||
values = DictMixin.values
|
||||
items = DictMixin.items
|
||||
iterkeys = DictMixin.iterkeys
|
||||
itervalues = DictMixin.itervalues
|
||||
iteritems = DictMixin.iteritems
|
||||
|
||||
def __repr__(self):
|
||||
if not self:
|
||||
return '%s()' % (self.__class__.__name__,)
|
||||
return '%s(%r)' % (self.__class__.__name__, self.items())
|
||||
|
||||
def copy(self):
|
||||
return self.__class__(self)
|
||||
|
||||
@classmethod
|
||||
def fromkeys(cls, iterable, value=None):
|
||||
d = cls()
|
||||
for key in iterable:
|
||||
d[key] = value
|
||||
return d
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, OrderedDict):
|
||||
if len(self) != len(other):
|
||||
return False
|
||||
for p, q in zip(self.items(), other.items()):
|
||||
if p != q:
|
||||
return False
|
||||
return True
|
||||
return dict.__eq__(self, other)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self == other
|
||||
368
qemu/scripts/qapi-event.py
Normal file
368
qemu/scripts/qapi-event.py
Normal file
@@ -0,0 +1,368 @@
|
||||
#
|
||||
# QAPI event generator
|
||||
#
|
||||
# Copyright (c) 2014 Wenchao Xia
|
||||
#
|
||||
# Authors:
|
||||
# Wenchao Xia <wenchaoqemu@gmail.com>
|
||||
#
|
||||
# This work is licensed under the terms of the GNU GPL, version 2.
|
||||
# See the COPYING file in the top-level directory.
|
||||
|
||||
from ordereddict import OrderedDict
|
||||
from qapi import *
|
||||
import sys
|
||||
import os
|
||||
import getopt
|
||||
import errno
|
||||
|
||||
def _generate_event_api_name(event_name, params):
|
||||
api_name = "void qapi_event_send_%s(" % c_fun(event_name).lower();
|
||||
l = len(api_name)
|
||||
|
||||
if params:
|
||||
for argname, argentry, optional, structured in parse_args(params):
|
||||
if optional:
|
||||
api_name += "bool has_%s,\n" % c_var(argname)
|
||||
api_name += "".ljust(l)
|
||||
|
||||
api_name += "%s %s,\n" % (c_type(argentry, is_param=True),
|
||||
c_var(argname))
|
||||
api_name += "".ljust(l)
|
||||
|
||||
api_name += "Error **errp)"
|
||||
return api_name;
|
||||
|
||||
|
||||
# Following are the core functions that generate C APIs to emit event.
|
||||
|
||||
def generate_event_declaration(api_name):
|
||||
return mcgen('''
|
||||
|
||||
%(api_name)s;
|
||||
''',
|
||||
api_name = api_name)
|
||||
|
||||
def generate_event_implement(api_name, event_name, params):
|
||||
# step 1: declare any variables
|
||||
ret = mcgen("""
|
||||
|
||||
%(api_name)s
|
||||
{
|
||||
QDict *qmp;
|
||||
Error *local_err = NULL;
|
||||
QMPEventFuncEmit emit;
|
||||
""",
|
||||
api_name = api_name)
|
||||
|
||||
if params:
|
||||
ret += mcgen("""
|
||||
QmpOutputVisitor *qov;
|
||||
Visitor *v;
|
||||
QObject *obj;
|
||||
|
||||
""")
|
||||
|
||||
# step 2: check emit function, create a dict
|
||||
ret += mcgen("""
|
||||
emit = qmp_event_get_func_emit();
|
||||
if (!emit) {
|
||||
return;
|
||||
}
|
||||
|
||||
qmp = qmp_event_build_dict("%(event_name)s");
|
||||
|
||||
""",
|
||||
event_name = event_name)
|
||||
|
||||
# step 3: visit the params if params != None
|
||||
if params:
|
||||
ret += mcgen("""
|
||||
qov = qmp_output_visitor_new();
|
||||
g_assert(qov);
|
||||
|
||||
v = qmp_output_get_visitor(qov);
|
||||
g_assert(v);
|
||||
|
||||
/* Fake visit, as if all members are under a structure */
|
||||
visit_start_struct(v, NULL, "", "%(event_name)s", 0, &local_err);
|
||||
if (local_err) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
""",
|
||||
event_name = event_name)
|
||||
|
||||
for argname, argentry, optional, structured in parse_args(params):
|
||||
if optional:
|
||||
ret += mcgen("""
|
||||
if (has_%(var)s) {
|
||||
""",
|
||||
var = c_var(argname))
|
||||
push_indent()
|
||||
|
||||
if argentry == "str":
|
||||
var_type = "(char **)"
|
||||
else:
|
||||
var_type = ""
|
||||
|
||||
ret += mcgen("""
|
||||
visit_type_%(type)s(v, %(var_type)s&%(var)s, "%(name)s", &local_err);
|
||||
if (local_err) {
|
||||
goto clean;
|
||||
}
|
||||
""",
|
||||
var_type = var_type,
|
||||
var = c_var(argname),
|
||||
type = type_name(argentry),
|
||||
name = argname)
|
||||
|
||||
if optional:
|
||||
pop_indent()
|
||||
ret += mcgen("""
|
||||
}
|
||||
""")
|
||||
|
||||
ret += mcgen("""
|
||||
|
||||
visit_end_struct(v, &local_err);
|
||||
if (local_err) {
|
||||
goto clean;
|
||||
}
|
||||
|
||||
obj = qmp_output_get_qobject(qov);
|
||||
g_assert(obj != NULL);
|
||||
|
||||
qdict_put_obj(qmp, "data", obj);
|
||||
""")
|
||||
|
||||
# step 4: call qmp event api
|
||||
ret += mcgen("""
|
||||
emit(%(event_enum_value)s, qmp, &local_err);
|
||||
|
||||
""",
|
||||
event_enum_value = event_enum_value)
|
||||
|
||||
# step 5: clean up
|
||||
if params:
|
||||
ret += mcgen("""
|
||||
clean:
|
||||
qmp_output_visitor_cleanup(qov);
|
||||
""")
|
||||
ret += mcgen("""
|
||||
error_propagate(errp, local_err);
|
||||
QDECREF(qmp);
|
||||
}
|
||||
""")
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
# Following are the functions that generate an enum type for all defined
|
||||
# events, similar to qapi-types.py. Here we already have enum name and
|
||||
# values which were generated before and recorded in event_enum_*. It also
|
||||
# works around the issue that "import qapi-types" can't work.
|
||||
|
||||
def generate_event_enum_decl(event_enum_name, event_enum_values):
|
||||
lookup_decl = mcgen('''
|
||||
|
||||
extern const char *%(event_enum_name)s_lookup[];
|
||||
''',
|
||||
event_enum_name = event_enum_name)
|
||||
|
||||
enum_decl = mcgen('''
|
||||
typedef enum %(event_enum_name)s
|
||||
{
|
||||
''',
|
||||
event_enum_name = event_enum_name)
|
||||
|
||||
# append automatically generated _MAX value
|
||||
enum_max_value = generate_enum_full_value(event_enum_name, "MAX")
|
||||
enum_values = event_enum_values + [ enum_max_value ]
|
||||
|
||||
i = 0
|
||||
for value in enum_values:
|
||||
enum_decl += mcgen('''
|
||||
%(value)s = %(i)d,
|
||||
''',
|
||||
value = value,
|
||||
i = i)
|
||||
i += 1
|
||||
|
||||
enum_decl += mcgen('''
|
||||
} %(event_enum_name)s;
|
||||
''',
|
||||
event_enum_name = event_enum_name)
|
||||
|
||||
return lookup_decl + enum_decl
|
||||
|
||||
def generate_event_enum_lookup(event_enum_name, event_enum_strings):
|
||||
ret = mcgen('''
|
||||
|
||||
const char *%(event_enum_name)s_lookup[] = {
|
||||
''',
|
||||
event_enum_name = event_enum_name)
|
||||
|
||||
i = 0
|
||||
for string in event_enum_strings:
|
||||
ret += mcgen('''
|
||||
"%(string)s",
|
||||
''',
|
||||
string = string)
|
||||
|
||||
ret += mcgen('''
|
||||
NULL,
|
||||
};
|
||||
''')
|
||||
return ret
|
||||
|
||||
|
||||
# Start the real job
|
||||
|
||||
try:
|
||||
opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:i:o:",
|
||||
["source", "header", "builtins", "prefix=",
|
||||
"input-file=", "output-dir="])
|
||||
except getopt.GetoptError, err:
|
||||
print str(err)
|
||||
sys.exit(1)
|
||||
|
||||
input_file = ""
|
||||
output_dir = ""
|
||||
prefix = ""
|
||||
c_file = 'qapi-event.c'
|
||||
h_file = 'qapi-event.h'
|
||||
|
||||
do_c = False
|
||||
do_h = False
|
||||
do_builtins = False
|
||||
|
||||
for o, a in opts:
|
||||
if o in ("-p", "--prefix"):
|
||||
prefix = a
|
||||
elif o in ("-i", "--input-file"):
|
||||
input_file = a
|
||||
elif o in ("-o", "--output-dir"):
|
||||
output_dir = a + "/"
|
||||
elif o in ("-c", "--source"):
|
||||
do_c = True
|
||||
elif o in ("-h", "--header"):
|
||||
do_h = True
|
||||
elif o in ("-b", "--builtins"):
|
||||
do_builtins = True
|
||||
|
||||
if not do_c and not do_h:
|
||||
do_c = True
|
||||
do_h = True
|
||||
|
||||
c_file = output_dir + prefix + c_file
|
||||
h_file = output_dir + prefix + h_file
|
||||
|
||||
try:
|
||||
os.makedirs(output_dir)
|
||||
except os.error, e:
|
||||
if e.errno != errno.EEXIST:
|
||||
raise
|
||||
|
||||
def maybe_open(really, name, opt):
|
||||
if really:
|
||||
return open(name, opt)
|
||||
else:
|
||||
import StringIO
|
||||
return StringIO.StringIO()
|
||||
|
||||
fdef = maybe_open(do_c, c_file, 'w')
|
||||
fdecl = maybe_open(do_h, h_file, 'w')
|
||||
|
||||
fdef.write(mcgen('''
|
||||
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
|
||||
/*
|
||||
* schema-defined QAPI event functions
|
||||
*
|
||||
* Copyright (c) 2014 Wenchao Xia
|
||||
*
|
||||
* Authors:
|
||||
* Wenchao Xia <wenchaoqemu@gmail.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
||||
* See the COPYING.LIB file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "%(header)s"
|
||||
#include "%(prefix)sqapi-visit.h"
|
||||
#include "qapi/qmp-output-visitor.h"
|
||||
#include "qapi/qmp-event.h"
|
||||
|
||||
''',
|
||||
prefix=prefix, header=basename(h_file)))
|
||||
|
||||
fdecl.write(mcgen('''
|
||||
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
|
||||
/*
|
||||
* schema-defined QAPI event functions
|
||||
*
|
||||
* Copyright (c) 2014 Wenchao Xia
|
||||
*
|
||||
* Authors:
|
||||
* Wenchao Xia <wenchaoqemu@gmail.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
||||
* See the COPYING.LIB file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef %(guard)s
|
||||
#define %(guard)s
|
||||
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "%(prefix)sqapi-types.h"
|
||||
|
||||
''',
|
||||
prefix=prefix, guard=guardname(h_file)))
|
||||
|
||||
exprs = parse_schema(input_file)
|
||||
|
||||
event_enum_name = prefix.upper().replace('-', '_') + "QAPIEvent"
|
||||
event_enum_values = []
|
||||
event_enum_strings = []
|
||||
|
||||
for expr in exprs:
|
||||
if expr.has_key('event'):
|
||||
event_name = expr['event']
|
||||
params = expr.get('data')
|
||||
if params and len(params) == 0:
|
||||
params = None
|
||||
|
||||
api_name = _generate_event_api_name(event_name, params)
|
||||
ret = generate_event_declaration(api_name)
|
||||
fdecl.write(ret)
|
||||
|
||||
# We need an enum value per event
|
||||
event_enum_value = generate_enum_full_value(event_enum_name,
|
||||
event_name)
|
||||
ret = generate_event_implement(api_name, event_name, params)
|
||||
fdef.write(ret)
|
||||
|
||||
# Record it, and generate enum later
|
||||
event_enum_values.append(event_enum_value)
|
||||
event_enum_strings.append(event_name)
|
||||
|
||||
ret = generate_event_enum_decl(event_enum_name, event_enum_values)
|
||||
fdecl.write(ret)
|
||||
ret = generate_event_enum_lookup(event_enum_name, event_enum_strings)
|
||||
fdef.write(ret)
|
||||
|
||||
fdecl.write('''
|
||||
#endif
|
||||
''')
|
||||
|
||||
fdecl.flush()
|
||||
fdecl.close()
|
||||
|
||||
fdef.flush()
|
||||
fdef.close()
|
||||
460
qemu/scripts/qapi-types.py
Normal file
460
qemu/scripts/qapi-types.py
Normal file
@@ -0,0 +1,460 @@
|
||||
#
|
||||
# QAPI types generator
|
||||
#
|
||||
# Copyright IBM, Corp. 2011
|
||||
#
|
||||
# Authors:
|
||||
# Anthony Liguori <aliguori@us.ibm.com>
|
||||
#
|
||||
# This work is licensed under the terms of the GNU GPL, version 2.
|
||||
# See the COPYING file in the top-level directory.
|
||||
|
||||
from ordereddict import OrderedDict
|
||||
from qapi import *
|
||||
import sys
|
||||
import os
|
||||
import getopt
|
||||
import errno
|
||||
|
||||
def generate_fwd_struct(name, members, builtin_type=False):
|
||||
if builtin_type:
|
||||
return mcgen('''
|
||||
|
||||
typedef struct %(name)sList
|
||||
{
|
||||
union {
|
||||
%(type)s value;
|
||||
uint64_t padding;
|
||||
};
|
||||
struct %(name)sList *next;
|
||||
} %(name)sList;
|
||||
''',
|
||||
type=c_type(name),
|
||||
name=name)
|
||||
|
||||
return mcgen('''
|
||||
|
||||
typedef struct %(name)s %(name)s;
|
||||
|
||||
typedef struct %(name)sList
|
||||
{
|
||||
union {
|
||||
%(name)s *value;
|
||||
uint64_t padding;
|
||||
};
|
||||
struct %(name)sList *next;
|
||||
} %(name)sList;
|
||||
''',
|
||||
name=name)
|
||||
|
||||
def generate_fwd_enum_struct(name, members):
|
||||
return mcgen('''
|
||||
typedef struct %(name)sList
|
||||
{
|
||||
union {
|
||||
%(name)s value;
|
||||
uint64_t padding;
|
||||
};
|
||||
struct %(name)sList *next;
|
||||
} %(name)sList;
|
||||
''',
|
||||
name=name)
|
||||
|
||||
def generate_struct_fields(members):
|
||||
ret = ''
|
||||
|
||||
for argname, argentry, optional, structured in parse_args(members):
|
||||
if optional:
|
||||
ret += mcgen('''
|
||||
bool has_%(c_name)s;
|
||||
''',
|
||||
c_name=c_var(argname))
|
||||
if structured:
|
||||
push_indent()
|
||||
ret += generate_struct({ "field": argname, "data": argentry})
|
||||
pop_indent()
|
||||
else:
|
||||
ret += mcgen('''
|
||||
%(c_type)s %(c_name)s;
|
||||
''',
|
||||
c_type=c_type(argentry), c_name=c_var(argname))
|
||||
|
||||
return ret
|
||||
|
||||
def generate_struct(expr):
|
||||
|
||||
structname = expr.get('type', "")
|
||||
fieldname = expr.get('field', "")
|
||||
members = expr['data']
|
||||
base = expr.get('base')
|
||||
|
||||
ret = mcgen('''
|
||||
struct %(name)s
|
||||
{
|
||||
''',
|
||||
name=structname)
|
||||
|
||||
if base:
|
||||
ret += generate_struct_fields({'base': base})
|
||||
|
||||
ret += generate_struct_fields(members)
|
||||
|
||||
if len(fieldname):
|
||||
fieldname = " " + fieldname
|
||||
ret += mcgen('''
|
||||
}%(field)s;
|
||||
''',
|
||||
field=fieldname)
|
||||
|
||||
return ret
|
||||
|
||||
def generate_enum_lookup(name, values):
|
||||
ret = mcgen('''
|
||||
const char *%(name)s_lookup[] = {
|
||||
''',
|
||||
name=name)
|
||||
i = 0
|
||||
for value in values:
|
||||
ret += mcgen('''
|
||||
"%(value)s",
|
||||
''',
|
||||
value=value)
|
||||
|
||||
ret += mcgen('''
|
||||
NULL,
|
||||
};
|
||||
|
||||
''')
|
||||
return ret
|
||||
|
||||
def generate_enum(name, values):
|
||||
lookup_decl = mcgen('''
|
||||
extern const char *%(name)s_lookup[];
|
||||
''',
|
||||
name=name)
|
||||
|
||||
enum_decl = mcgen('''
|
||||
typedef enum %(name)s
|
||||
{
|
||||
''',
|
||||
name=name)
|
||||
|
||||
# append automatically generated _MAX value
|
||||
enum_values = values + [ 'MAX' ]
|
||||
|
||||
i = 0
|
||||
for value in enum_values:
|
||||
enum_full_value = generate_enum_full_value(name, value)
|
||||
enum_decl += mcgen('''
|
||||
%(enum_full_value)s = %(i)d,
|
||||
''',
|
||||
enum_full_value = enum_full_value,
|
||||
i=i)
|
||||
i += 1
|
||||
|
||||
enum_decl += mcgen('''
|
||||
} %(name)s;
|
||||
''',
|
||||
name=name)
|
||||
|
||||
return lookup_decl + enum_decl
|
||||
|
||||
def generate_anon_union_qtypes(expr):
|
||||
|
||||
name = expr['union']
|
||||
members = expr['data']
|
||||
|
||||
ret = mcgen('''
|
||||
const int %(name)s_qtypes[QTYPE_MAX] = {
|
||||
''',
|
||||
name=name)
|
||||
|
||||
for key in members:
|
||||
qapi_type = members[key]
|
||||
if builtin_type_qtypes.has_key(qapi_type):
|
||||
qtype = builtin_type_qtypes[qapi_type]
|
||||
elif find_struct(qapi_type):
|
||||
qtype = "QTYPE_QDICT"
|
||||
elif find_union(qapi_type):
|
||||
qtype = "QTYPE_QDICT"
|
||||
elif find_enum(qapi_type):
|
||||
qtype = "QTYPE_QSTRING"
|
||||
else:
|
||||
assert False, "Invalid anonymous union member"
|
||||
|
||||
ret += mcgen('''
|
||||
[ %(qtype)s ] = %(abbrev)s_KIND_%(enum)s,
|
||||
''',
|
||||
qtype = qtype,
|
||||
abbrev = de_camel_case(name).upper(),
|
||||
enum = c_fun(de_camel_case(key),False).upper())
|
||||
|
||||
ret += mcgen('''
|
||||
};
|
||||
''')
|
||||
return ret
|
||||
|
||||
|
||||
def generate_union(expr):
|
||||
|
||||
name = expr['union']
|
||||
typeinfo = expr['data']
|
||||
|
||||
base = expr.get('base')
|
||||
discriminator = expr.get('discriminator')
|
||||
|
||||
enum_define = discriminator_find_enum_define(expr)
|
||||
if enum_define:
|
||||
discriminator_type_name = enum_define['enum_name']
|
||||
else:
|
||||
discriminator_type_name = '%sKind' % (name)
|
||||
|
||||
ret = mcgen('''
|
||||
struct %(name)s
|
||||
{
|
||||
%(discriminator_type_name)s kind;
|
||||
union {
|
||||
void *data;
|
||||
''',
|
||||
name=name,
|
||||
discriminator_type_name=discriminator_type_name)
|
||||
|
||||
for key in typeinfo:
|
||||
ret += mcgen('''
|
||||
%(c_type)s %(c_name)s;
|
||||
''',
|
||||
c_type=c_type(typeinfo[key]),
|
||||
c_name=c_fun(key))
|
||||
|
||||
ret += mcgen('''
|
||||
};
|
||||
''')
|
||||
|
||||
if base:
|
||||
base_fields = find_struct(base)['data']
|
||||
if discriminator:
|
||||
base_fields = base_fields.copy()
|
||||
del base_fields[discriminator]
|
||||
ret += generate_struct_fields(base_fields)
|
||||
else:
|
||||
assert not discriminator
|
||||
|
||||
ret += mcgen('''
|
||||
};
|
||||
''')
|
||||
if discriminator == {}:
|
||||
ret += mcgen('''
|
||||
extern const int %(name)s_qtypes[];
|
||||
''',
|
||||
name=name)
|
||||
|
||||
|
||||
return ret
|
||||
|
||||
def generate_type_cleanup_decl(name):
|
||||
ret = mcgen('''
|
||||
void qapi_free_%(type)s(%(c_type)s obj);
|
||||
''',
|
||||
c_type=c_type(name),type=name)
|
||||
return ret
|
||||
|
||||
def generate_type_cleanup(name):
|
||||
ret = mcgen('''
|
||||
|
||||
void qapi_free_%(type)s(%(c_type)s obj)
|
||||
{
|
||||
QapiDeallocVisitor *md;
|
||||
Visitor *v;
|
||||
|
||||
if (!obj) {
|
||||
return;
|
||||
}
|
||||
|
||||
md = qapi_dealloc_visitor_new();
|
||||
v = qapi_dealloc_get_visitor(md);
|
||||
visit_type_%(type)s(v, &obj, NULL, NULL);
|
||||
qapi_dealloc_visitor_cleanup(md);
|
||||
}
|
||||
''',
|
||||
c_type=c_type(name),type=name)
|
||||
return ret
|
||||
|
||||
|
||||
try:
|
||||
opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:i:o:",
|
||||
["source", "header", "builtins",
|
||||
"prefix=", "input-file=", "output-dir="])
|
||||
except getopt.GetoptError, err:
|
||||
print str(err)
|
||||
sys.exit(1)
|
||||
|
||||
output_dir = ""
|
||||
input_file = ""
|
||||
prefix = ""
|
||||
c_file = 'qapi-types.c'
|
||||
h_file = 'qapi-types.h'
|
||||
|
||||
do_c = False
|
||||
do_h = False
|
||||
do_builtins = False
|
||||
|
||||
for o, a in opts:
|
||||
if o in ("-p", "--prefix"):
|
||||
prefix = a
|
||||
elif o in ("-i", "--input-file"):
|
||||
input_file = a
|
||||
elif o in ("-o", "--output-dir"):
|
||||
output_dir = a + "/"
|
||||
elif o in ("-c", "--source"):
|
||||
do_c = True
|
||||
elif o in ("-h", "--header"):
|
||||
do_h = True
|
||||
elif o in ("-b", "--builtins"):
|
||||
do_builtins = True
|
||||
|
||||
if not do_c and not do_h:
|
||||
do_c = True
|
||||
do_h = True
|
||||
|
||||
c_file = output_dir + prefix + c_file
|
||||
h_file = output_dir + prefix + h_file
|
||||
|
||||
try:
|
||||
os.makedirs(output_dir)
|
||||
except os.error, e:
|
||||
if e.errno != errno.EEXIST:
|
||||
raise
|
||||
|
||||
def maybe_open(really, name, opt):
|
||||
if really:
|
||||
return open(name, opt)
|
||||
else:
|
||||
import StringIO
|
||||
return StringIO.StringIO()
|
||||
|
||||
fdef = maybe_open(do_c, c_file, 'w')
|
||||
fdecl = maybe_open(do_h, h_file, 'w')
|
||||
|
||||
fdef.write(mcgen('''
|
||||
/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
|
||||
/*
|
||||
* deallocation functions for schema-defined QAPI types
|
||||
*
|
||||
* Copyright IBM, Corp. 2011
|
||||
*
|
||||
* Authors:
|
||||
* Anthony Liguori <aliguori@us.ibm.com>
|
||||
* Michael Roth <mdroth@linux.vnet.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
||||
* See the COPYING.LIB file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qapi/dealloc-visitor.h"
|
||||
#include "%(prefix)sqapi-types.h"
|
||||
#include "%(prefix)sqapi-visit.h"
|
||||
|
||||
''', prefix=prefix))
|
||||
|
||||
fdecl.write(mcgen('''
|
||||
/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
|
||||
/*
|
||||
* schema-defined QAPI types
|
||||
*
|
||||
* Copyright IBM, Corp. 2011
|
||||
*
|
||||
* Authors:
|
||||
* Anthony Liguori <aliguori@us.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
||||
* See the COPYING.LIB file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef %(guard)s
|
||||
#define %(guard)s
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
''',
|
||||
guard=guardname(h_file)))
|
||||
|
||||
exprs = parse_schema(input_file)
|
||||
exprs = filter(lambda expr: not expr.has_key('gen'), exprs)
|
||||
|
||||
fdecl.write(guardstart("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
|
||||
for typename in builtin_types:
|
||||
fdecl.write(generate_fwd_struct(typename, None, builtin_type=True))
|
||||
fdecl.write(guardend("QAPI_TYPES_BUILTIN_STRUCT_DECL"))
|
||||
|
||||
for expr in exprs:
|
||||
ret = "\n"
|
||||
if expr.has_key('type'):
|
||||
ret += generate_fwd_struct(expr['type'], expr['data'])
|
||||
elif expr.has_key('enum'):
|
||||
ret += generate_enum(expr['enum'], expr['data']) + "\n"
|
||||
ret += generate_fwd_enum_struct(expr['enum'], expr['data'])
|
||||
fdef.write(generate_enum_lookup(expr['enum'], expr['data']))
|
||||
elif expr.has_key('union'):
|
||||
ret += generate_fwd_struct(expr['union'], expr['data']) + "\n"
|
||||
enum_define = discriminator_find_enum_define(expr)
|
||||
if not enum_define:
|
||||
ret += generate_enum('%sKind' % expr['union'], expr['data'].keys())
|
||||
fdef.write(generate_enum_lookup('%sKind' % expr['union'],
|
||||
expr['data'].keys()))
|
||||
if expr.get('discriminator') == {}:
|
||||
fdef.write(generate_anon_union_qtypes(expr))
|
||||
else:
|
||||
continue
|
||||
fdecl.write(ret)
|
||||
|
||||
# to avoid header dependency hell, we always generate declarations
|
||||
# for built-in types in our header files and simply guard them
|
||||
fdecl.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
|
||||
for typename in builtin_types:
|
||||
fdecl.write(generate_type_cleanup_decl(typename + "List"))
|
||||
fdecl.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DECL"))
|
||||
|
||||
# ...this doesn't work for cases where we link in multiple objects that
|
||||
# have the functions defined, so we use -b option to provide control
|
||||
# over these cases
|
||||
if do_builtins:
|
||||
fdef.write(guardstart("QAPI_TYPES_BUILTIN_CLEANUP_DEF"))
|
||||
for typename in builtin_types:
|
||||
fdef.write(generate_type_cleanup(typename + "List"))
|
||||
fdef.write(guardend("QAPI_TYPES_BUILTIN_CLEANUP_DEF"))
|
||||
|
||||
for expr in exprs:
|
||||
ret = "\n"
|
||||
if expr.has_key('type'):
|
||||
ret += generate_struct(expr) + "\n"
|
||||
ret += generate_type_cleanup_decl(expr['type'] + "List")
|
||||
fdef.write(generate_type_cleanup(expr['type'] + "List") + "\n")
|
||||
ret += generate_type_cleanup_decl(expr['type'])
|
||||
fdef.write(generate_type_cleanup(expr['type']) + "\n")
|
||||
elif expr.has_key('union'):
|
||||
ret += generate_union(expr)
|
||||
ret += generate_type_cleanup_decl(expr['union'] + "List")
|
||||
fdef.write(generate_type_cleanup(expr['union'] + "List") + "\n")
|
||||
ret += generate_type_cleanup_decl(expr['union'])
|
||||
fdef.write(generate_type_cleanup(expr['union']) + "\n")
|
||||
elif expr.has_key('enum'):
|
||||
ret += generate_type_cleanup_decl(expr['enum'] + "List")
|
||||
fdef.write(generate_type_cleanup(expr['enum'] + "List") + "\n")
|
||||
else:
|
||||
continue
|
||||
fdecl.write(ret)
|
||||
|
||||
fdecl.write('''
|
||||
#endif
|
||||
''')
|
||||
|
||||
fdecl.flush()
|
||||
fdecl.close()
|
||||
|
||||
fdef.flush()
|
||||
fdef.close()
|
||||
593
qemu/scripts/qapi-visit.py
Normal file
593
qemu/scripts/qapi-visit.py
Normal file
@@ -0,0 +1,593 @@
|
||||
#
|
||||
# QAPI visitor generator
|
||||
#
|
||||
# Copyright IBM, Corp. 2011
|
||||
# Copyright (C) 2014 Red Hat, Inc.
|
||||
#
|
||||
# Authors:
|
||||
# Anthony Liguori <aliguori@us.ibm.com>
|
||||
# Michael Roth <mdroth@linux.vnet.ibm.com>
|
||||
# Markus Armbruster <armbru@redhat.com>
|
||||
#
|
||||
# This work is licensed under the terms of the GNU GPL, version 2.
|
||||
# See the COPYING file in the top-level directory.
|
||||
|
||||
from ordereddict import OrderedDict
|
||||
from qapi import *
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
import getopt
|
||||
import errno
|
||||
|
||||
implicit_structs = []
|
||||
|
||||
def generate_visit_implicit_struct(type):
|
||||
global implicit_structs
|
||||
if type in implicit_structs:
|
||||
return ''
|
||||
implicit_structs.append(type)
|
||||
return mcgen('''
|
||||
|
||||
static void visit_type_implicit_%(c_type)s(Visitor *m, %(c_type)s **obj, Error **errp)
|
||||
{
|
||||
Error *err = NULL;
|
||||
|
||||
visit_start_implicit_struct(m, (void **)obj, sizeof(%(c_type)s), &err);
|
||||
if (!err) {
|
||||
visit_type_%(c_type)s_fields(m, obj, errp);
|
||||
visit_end_implicit_struct(m, &err);
|
||||
}
|
||||
error_propagate(errp, err);
|
||||
}
|
||||
''',
|
||||
c_type=type_name(type))
|
||||
|
||||
def generate_visit_struct_fields(name, field_prefix, fn_prefix, members, base = None):
|
||||
substructs = []
|
||||
ret = ''
|
||||
if not fn_prefix:
|
||||
full_name = name
|
||||
else:
|
||||
full_name = "%s_%s" % (name, fn_prefix)
|
||||
|
||||
for argname, argentry, optional, structured in parse_args(members):
|
||||
if structured:
|
||||
if not fn_prefix:
|
||||
nested_fn_prefix = argname
|
||||
else:
|
||||
nested_fn_prefix = "%s_%s" % (fn_prefix, argname)
|
||||
|
||||
nested_field_prefix = "%s%s." % (field_prefix, argname)
|
||||
ret += generate_visit_struct_fields(name, nested_field_prefix,
|
||||
nested_fn_prefix, argentry)
|
||||
ret += mcgen('''
|
||||
|
||||
static void visit_type_%(full_name)s_field_%(c_name)s(Visitor *m, %(name)s **obj, Error **errp)
|
||||
{
|
||||
''',
|
||||
name=name, full_name=full_name, c_name=c_var(argname))
|
||||
ret += generate_visit_struct_body(full_name, argname, argentry)
|
||||
ret += mcgen('''
|
||||
}
|
||||
''')
|
||||
|
||||
if base:
|
||||
ret += generate_visit_implicit_struct(base)
|
||||
|
||||
ret += mcgen('''
|
||||
|
||||
static void visit_type_%(full_name)s_fields(Visitor *m, %(name)s **obj, Error **errp)
|
||||
{
|
||||
Error *err = NULL;
|
||||
''',
|
||||
name=name, full_name=full_name)
|
||||
push_indent()
|
||||
|
||||
if base:
|
||||
ret += mcgen('''
|
||||
visit_type_implicit_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, &err);
|
||||
if (err) {
|
||||
goto out;
|
||||
}
|
||||
''',
|
||||
c_prefix=c_var(field_prefix),
|
||||
type=type_name(base), c_name=c_var('base'))
|
||||
|
||||
for argname, argentry, optional, structured in parse_args(members):
|
||||
if optional:
|
||||
ret += mcgen('''
|
||||
visit_optional(m, &(*obj)->%(c_prefix)shas_%(c_name)s, "%(name)s", &err);
|
||||
if (!err && (*obj)->%(prefix)shas_%(c_name)s) {
|
||||
''',
|
||||
c_prefix=c_var(field_prefix), prefix=field_prefix,
|
||||
c_name=c_var(argname), name=argname)
|
||||
push_indent()
|
||||
|
||||
if structured:
|
||||
ret += mcgen('''
|
||||
visit_type_%(full_name)s_field_%(c_name)s(m, obj, &err);
|
||||
''',
|
||||
full_name=full_name, c_name=c_var(argname))
|
||||
else:
|
||||
ret += mcgen('''
|
||||
visit_type_%(type)s(m, &(*obj)->%(c_prefix)s%(c_name)s, "%(name)s", &err);
|
||||
''',
|
||||
c_prefix=c_var(field_prefix), prefix=field_prefix,
|
||||
type=type_name(argentry), c_name=c_var(argname),
|
||||
name=argname)
|
||||
|
||||
if optional:
|
||||
pop_indent()
|
||||
ret += mcgen('''
|
||||
}
|
||||
''')
|
||||
ret += mcgen('''
|
||||
if (err) {
|
||||
goto out;
|
||||
}
|
||||
''')
|
||||
|
||||
pop_indent()
|
||||
if re.search('^ *goto out\\;', ret, re.MULTILINE):
|
||||
ret += mcgen('''
|
||||
|
||||
out:
|
||||
''')
|
||||
ret += mcgen('''
|
||||
error_propagate(errp, err);
|
||||
}
|
||||
''')
|
||||
return ret
|
||||
|
||||
|
||||
def generate_visit_struct_body(field_prefix, name, members):
|
||||
ret = mcgen('''
|
||||
Error *err = NULL;
|
||||
|
||||
''')
|
||||
|
||||
if not field_prefix:
|
||||
full_name = name
|
||||
else:
|
||||
full_name = "%s_%s" % (field_prefix, name)
|
||||
|
||||
if len(field_prefix):
|
||||
ret += mcgen('''
|
||||
visit_start_struct(m, NULL, "", "%(name)s", 0, &err);
|
||||
''',
|
||||
name=name)
|
||||
else:
|
||||
ret += mcgen('''
|
||||
visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
|
||||
''',
|
||||
name=name)
|
||||
|
||||
ret += mcgen('''
|
||||
if (!err) {
|
||||
if (*obj) {
|
||||
visit_type_%(name)s_fields(m, obj, errp);
|
||||
}
|
||||
visit_end_struct(m, &err);
|
||||
}
|
||||
error_propagate(errp, err);
|
||||
''',
|
||||
name=full_name)
|
||||
|
||||
return ret
|
||||
|
||||
def generate_visit_struct(expr):
|
||||
|
||||
name = expr['type']
|
||||
members = expr['data']
|
||||
base = expr.get('base')
|
||||
|
||||
ret = generate_visit_struct_fields(name, "", "", members, base)
|
||||
|
||||
ret += mcgen('''
|
||||
|
||||
void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
|
||||
{
|
||||
''',
|
||||
name=name)
|
||||
|
||||
ret += generate_visit_struct_body("", name, members)
|
||||
|
||||
ret += mcgen('''
|
||||
}
|
||||
''')
|
||||
return ret
|
||||
|
||||
def generate_visit_list(name, members):
|
||||
return mcgen('''
|
||||
|
||||
void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp)
|
||||
{
|
||||
Error *err = NULL;
|
||||
GenericList *i, **prev;
|
||||
|
||||
visit_start_list(m, name, &err);
|
||||
if (err) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (prev = (GenericList **)obj;
|
||||
!err && (i = visit_next_list(m, prev, &err)) != NULL;
|
||||
prev = &i) {
|
||||
%(name)sList *native_i = (%(name)sList *)i;
|
||||
visit_type_%(name)s(m, &native_i->value, NULL, &err);
|
||||
}
|
||||
|
||||
error_propagate(errp, err);
|
||||
err = NULL;
|
||||
visit_end_list(m, &err);
|
||||
out:
|
||||
error_propagate(errp, err);
|
||||
}
|
||||
''',
|
||||
name=name)
|
||||
|
||||
def generate_visit_enum(name, members):
|
||||
return mcgen('''
|
||||
|
||||
void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp)
|
||||
{
|
||||
visit_type_enum(m, (int *)obj, %(name)s_lookup, "%(name)s", name, errp);
|
||||
}
|
||||
''',
|
||||
name=name)
|
||||
|
||||
def generate_visit_anon_union(name, members):
|
||||
ret = mcgen('''
|
||||
|
||||
void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
|
||||
{
|
||||
Error *err = NULL;
|
||||
|
||||
visit_start_implicit_struct(m, (void**) obj, sizeof(%(name)s), &err);
|
||||
if (err) {
|
||||
goto out;
|
||||
}
|
||||
visit_get_next_type(m, (int*) &(*obj)->kind, %(name)s_qtypes, name, &err);
|
||||
if (err) {
|
||||
goto out_end;
|
||||
}
|
||||
switch ((*obj)->kind) {
|
||||
''',
|
||||
name=name)
|
||||
|
||||
# For anon union, always use the default enum type automatically generated
|
||||
# as "'%sKind' % (name)"
|
||||
disc_type = '%sKind' % (name)
|
||||
|
||||
for key in members:
|
||||
assert (members[key] in builtin_types
|
||||
or find_struct(members[key])
|
||||
or find_union(members[key])
|
||||
or find_enum(members[key])), "Invalid anonymous union member"
|
||||
|
||||
enum_full_value = generate_enum_full_value(disc_type, key)
|
||||
ret += mcgen('''
|
||||
case %(enum_full_value)s:
|
||||
visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, name, &err);
|
||||
break;
|
||||
''',
|
||||
enum_full_value = enum_full_value,
|
||||
c_type = type_name(members[key]),
|
||||
c_name = c_fun(key))
|
||||
|
||||
ret += mcgen('''
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
out_end:
|
||||
error_propagate(errp, err);
|
||||
err = NULL;
|
||||
visit_end_implicit_struct(m, &err);
|
||||
out:
|
||||
error_propagate(errp, err);
|
||||
}
|
||||
''')
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def generate_visit_union(expr):
|
||||
|
||||
name = expr['union']
|
||||
members = expr['data']
|
||||
|
||||
base = expr.get('base')
|
||||
discriminator = expr.get('discriminator')
|
||||
|
||||
if discriminator == {}:
|
||||
assert not base
|
||||
return generate_visit_anon_union(name, members)
|
||||
|
||||
enum_define = discriminator_find_enum_define(expr)
|
||||
if enum_define:
|
||||
# Use the enum type as discriminator
|
||||
ret = ""
|
||||
disc_type = enum_define['enum_name']
|
||||
else:
|
||||
# There will always be a discriminator in the C switch code, by default it
|
||||
# is an enum type generated silently as "'%sKind' % (name)"
|
||||
ret = generate_visit_enum('%sKind' % name, members.keys())
|
||||
disc_type = '%sKind' % (name)
|
||||
|
||||
if base:
|
||||
base_fields = find_struct(base)['data']
|
||||
if discriminator:
|
||||
base_fields = base_fields.copy()
|
||||
del base_fields[discriminator]
|
||||
ret += generate_visit_struct_fields(name, "", "", base_fields)
|
||||
|
||||
if discriminator:
|
||||
for key in members:
|
||||
ret += generate_visit_implicit_struct(members[key])
|
||||
|
||||
ret += mcgen('''
|
||||
|
||||
void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp)
|
||||
{
|
||||
Error *err = NULL;
|
||||
|
||||
visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err);
|
||||
if (err) {
|
||||
goto out;
|
||||
}
|
||||
if (*obj) {
|
||||
''',
|
||||
name=name)
|
||||
|
||||
if base:
|
||||
ret += mcgen('''
|
||||
visit_type_%(name)s_fields(m, obj, &err);
|
||||
if (err) {
|
||||
goto out_obj;
|
||||
}
|
||||
''',
|
||||
name=name)
|
||||
|
||||
if not discriminator:
|
||||
disc_key = "type"
|
||||
else:
|
||||
disc_key = discriminator
|
||||
ret += mcgen('''
|
||||
visit_type_%(disc_type)s(m, &(*obj)->kind, "%(disc_key)s", &err);
|
||||
if (err) {
|
||||
goto out_obj;
|
||||
}
|
||||
if (!visit_start_union(m, !!(*obj)->data, &err) || err) {
|
||||
goto out_obj;
|
||||
}
|
||||
switch ((*obj)->kind) {
|
||||
''',
|
||||
disc_type = disc_type,
|
||||
disc_key = disc_key)
|
||||
|
||||
for key in members:
|
||||
if not discriminator:
|
||||
fmt = 'visit_type_%(c_type)s(m, &(*obj)->%(c_name)s, "data", &err);'
|
||||
else:
|
||||
fmt = 'visit_type_implicit_%(c_type)s(m, &(*obj)->%(c_name)s, &err);'
|
||||
|
||||
enum_full_value = generate_enum_full_value(disc_type, key)
|
||||
ret += mcgen('''
|
||||
case %(enum_full_value)s:
|
||||
''' + fmt + '''
|
||||
break;
|
||||
''',
|
||||
enum_full_value = enum_full_value,
|
||||
c_type=type_name(members[key]),
|
||||
c_name=c_fun(key))
|
||||
|
||||
ret += mcgen('''
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
out_obj:
|
||||
error_propagate(errp, err);
|
||||
err = NULL;
|
||||
visit_end_union(m, !!(*obj)->data, &err);
|
||||
error_propagate(errp, err);
|
||||
err = NULL;
|
||||
}
|
||||
visit_end_struct(m, &err);
|
||||
out:
|
||||
error_propagate(errp, err);
|
||||
}
|
||||
''')
|
||||
|
||||
return ret
|
||||
|
||||
def generate_declaration(name, members, genlist=True, builtin_type=False):
|
||||
ret = ""
|
||||
if not builtin_type:
|
||||
ret += mcgen('''
|
||||
|
||||
void visit_type_%(name)s(Visitor *m, %(name)s **obj, const char *name, Error **errp);
|
||||
''',
|
||||
name=name)
|
||||
|
||||
if genlist:
|
||||
ret += mcgen('''
|
||||
void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
|
||||
''',
|
||||
name=name)
|
||||
|
||||
return ret
|
||||
|
||||
def generate_enum_declaration(name, members, genlist=True):
|
||||
ret = ""
|
||||
if genlist:
|
||||
ret += mcgen('''
|
||||
void visit_type_%(name)sList(Visitor *m, %(name)sList **obj, const char *name, Error **errp);
|
||||
''',
|
||||
name=name)
|
||||
|
||||
return ret
|
||||
|
||||
def generate_decl_enum(name, members, genlist=True):
|
||||
return mcgen('''
|
||||
|
||||
void visit_type_%(name)s(Visitor *m, %(name)s *obj, const char *name, Error **errp);
|
||||
''',
|
||||
name=name)
|
||||
|
||||
try:
|
||||
opts, args = getopt.gnu_getopt(sys.argv[1:], "chbp:i:o:",
|
||||
["source", "header", "builtins", "prefix=",
|
||||
"input-file=", "output-dir="])
|
||||
except getopt.GetoptError, err:
|
||||
print str(err)
|
||||
sys.exit(1)
|
||||
|
||||
input_file = ""
|
||||
output_dir = ""
|
||||
prefix = ""
|
||||
c_file = 'qapi-visit.c'
|
||||
h_file = 'qapi-visit.h'
|
||||
|
||||
do_c = False
|
||||
do_h = False
|
||||
do_builtins = False
|
||||
|
||||
for o, a in opts:
|
||||
if o in ("-p", "--prefix"):
|
||||
prefix = a
|
||||
elif o in ("-i", "--input-file"):
|
||||
input_file = a
|
||||
elif o in ("-o", "--output-dir"):
|
||||
output_dir = a + "/"
|
||||
elif o in ("-c", "--source"):
|
||||
do_c = True
|
||||
elif o in ("-h", "--header"):
|
||||
do_h = True
|
||||
elif o in ("-b", "--builtins"):
|
||||
do_builtins = True
|
||||
|
||||
if not do_c and not do_h:
|
||||
do_c = True
|
||||
do_h = True
|
||||
|
||||
c_file = output_dir + prefix + c_file
|
||||
h_file = output_dir + prefix + h_file
|
||||
|
||||
try:
|
||||
os.makedirs(output_dir)
|
||||
except os.error, e:
|
||||
if e.errno != errno.EEXIST:
|
||||
raise
|
||||
|
||||
def maybe_open(really, name, opt):
|
||||
if really:
|
||||
return open(name, opt)
|
||||
else:
|
||||
import StringIO
|
||||
return StringIO.StringIO()
|
||||
|
||||
fdef = maybe_open(do_c, c_file, 'w')
|
||||
fdecl = maybe_open(do_h, h_file, 'w')
|
||||
|
||||
fdef.write(mcgen('''
|
||||
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
|
||||
/*
|
||||
* schema-defined QAPI visitor functions
|
||||
*
|
||||
* Copyright IBM, Corp. 2011
|
||||
*
|
||||
* Authors:
|
||||
* Anthony Liguori <aliguori@us.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
||||
* See the COPYING.LIB file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "%(header)s"
|
||||
''',
|
||||
header=basename(h_file)))
|
||||
|
||||
fdecl.write(mcgen('''
|
||||
/* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
|
||||
/*
|
||||
* schema-defined QAPI visitor functions
|
||||
*
|
||||
* Copyright IBM, Corp. 2011
|
||||
*
|
||||
* Authors:
|
||||
* Anthony Liguori <aliguori@us.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
|
||||
* See the COPYING.LIB file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef %(guard)s
|
||||
#define %(guard)s
|
||||
|
||||
#include "qapi/visitor.h"
|
||||
#include "%(prefix)sqapi-types.h"
|
||||
|
||||
''',
|
||||
prefix=prefix, guard=guardname(h_file)))
|
||||
|
||||
exprs = parse_schema(input_file)
|
||||
|
||||
# to avoid header dependency hell, we always generate declarations
|
||||
# for built-in types in our header files and simply guard them
|
||||
fdecl.write(guardstart("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
|
||||
for typename in builtin_types:
|
||||
fdecl.write(generate_declaration(typename, None, genlist=True,
|
||||
builtin_type=True))
|
||||
fdecl.write(guardend("QAPI_VISIT_BUILTIN_VISITOR_DECL"))
|
||||
|
||||
# ...this doesn't work for cases where we link in multiple objects that
|
||||
# have the functions defined, so we use -b option to provide control
|
||||
# over these cases
|
||||
if do_builtins:
|
||||
for typename in builtin_types:
|
||||
fdef.write(generate_visit_list(typename, None))
|
||||
|
||||
for expr in exprs:
|
||||
if expr.has_key('type'):
|
||||
ret = generate_visit_struct(expr)
|
||||
ret += generate_visit_list(expr['type'], expr['data'])
|
||||
fdef.write(ret)
|
||||
|
||||
ret = generate_declaration(expr['type'], expr['data'])
|
||||
fdecl.write(ret)
|
||||
elif expr.has_key('union'):
|
||||
ret = generate_visit_union(expr)
|
||||
ret += generate_visit_list(expr['union'], expr['data'])
|
||||
fdef.write(ret)
|
||||
|
||||
enum_define = discriminator_find_enum_define(expr)
|
||||
ret = ""
|
||||
if not enum_define:
|
||||
ret = generate_decl_enum('%sKind' % expr['union'],
|
||||
expr['data'].keys())
|
||||
ret += generate_declaration(expr['union'], expr['data'])
|
||||
fdecl.write(ret)
|
||||
elif expr.has_key('enum'):
|
||||
ret = generate_visit_list(expr['enum'], expr['data'])
|
||||
ret += generate_visit_enum(expr['enum'], expr['data'])
|
||||
fdef.write(ret)
|
||||
|
||||
ret = generate_decl_enum(expr['enum'], expr['data'])
|
||||
ret += generate_enum_declaration(expr['enum'], expr['data'])
|
||||
fdecl.write(ret)
|
||||
|
||||
fdecl.write('''
|
||||
#endif
|
||||
''')
|
||||
|
||||
fdecl.flush()
|
||||
fdecl.close()
|
||||
|
||||
fdef.flush()
|
||||
fdef.close()
|
||||
600
qemu/scripts/qapi.py
Normal file
600
qemu/scripts/qapi.py
Normal file
@@ -0,0 +1,600 @@
|
||||
#
|
||||
# QAPI helper library
|
||||
#
|
||||
# Copyright IBM, Corp. 2011
|
||||
# Copyright (c) 2013 Red Hat Inc.
|
||||
#
|
||||
# Authors:
|
||||
# Anthony Liguori <aliguori@us.ibm.com>
|
||||
# Markus Armbruster <armbru@redhat.com>
|
||||
#
|
||||
# This work is licensed under the terms of the GNU GPL, version 2.
|
||||
# See the COPYING file in the top-level directory.
|
||||
|
||||
import re
|
||||
from ordereddict import OrderedDict
|
||||
import os
|
||||
import sys
|
||||
|
||||
builtin_types = [
|
||||
'str', 'int', 'number', 'bool',
|
||||
'int8', 'int16', 'int32', 'int64',
|
||||
'uint8', 'uint16', 'uint32', 'uint64'
|
||||
]
|
||||
|
||||
builtin_type_qtypes = {
|
||||
'str': 'QTYPE_QSTRING',
|
||||
'int': 'QTYPE_QINT',
|
||||
'number': 'QTYPE_QFLOAT',
|
||||
'bool': 'QTYPE_QBOOL',
|
||||
'int8': 'QTYPE_QINT',
|
||||
'int16': 'QTYPE_QINT',
|
||||
'int32': 'QTYPE_QINT',
|
||||
'int64': 'QTYPE_QINT',
|
||||
'uint8': 'QTYPE_QINT',
|
||||
'uint16': 'QTYPE_QINT',
|
||||
'uint32': 'QTYPE_QINT',
|
||||
'uint64': 'QTYPE_QINT',
|
||||
}
|
||||
|
||||
def error_path(parent):
|
||||
res = ""
|
||||
while parent:
|
||||
res = ("In file included from %s:%d:\n" % (parent['file'],
|
||||
parent['line'])) + res
|
||||
parent = parent['parent']
|
||||
return res
|
||||
|
||||
class QAPISchemaError(Exception):
|
||||
def __init__(self, schema, msg):
|
||||
self.input_file = schema.input_file
|
||||
self.msg = msg
|
||||
self.col = 1
|
||||
self.line = schema.line
|
||||
for ch in schema.src[schema.line_pos:schema.pos]:
|
||||
if ch == '\t':
|
||||
self.col = (self.col + 7) % 8 + 1
|
||||
else:
|
||||
self.col += 1
|
||||
self.info = schema.parent_info
|
||||
|
||||
def __str__(self):
|
||||
return error_path(self.info) + \
|
||||
"%s:%d:%d: %s" % (self.input_file, self.line, self.col, self.msg)
|
||||
|
||||
class QAPIExprError(Exception):
|
||||
def __init__(self, expr_info, msg):
|
||||
self.info = expr_info
|
||||
self.msg = msg
|
||||
|
||||
def __str__(self):
|
||||
return error_path(self.info['parent']) + \
|
||||
"%s:%d: %s" % (self.info['file'], self.info['line'], self.msg)
|
||||
|
||||
class QAPISchema:
|
||||
|
||||
def __init__(self, fp, input_relname=None, include_hist=[],
|
||||
previously_included=[], parent_info=None):
|
||||
""" include_hist is a stack used to detect inclusion cycles
|
||||
previously_included is a global state used to avoid multiple
|
||||
inclusions of the same file"""
|
||||
input_fname = os.path.abspath(fp.name)
|
||||
if input_relname is None:
|
||||
input_relname = fp.name
|
||||
self.input_dir = os.path.dirname(input_fname)
|
||||
self.input_file = input_relname
|
||||
self.include_hist = include_hist + [(input_relname, input_fname)]
|
||||
previously_included.append(input_fname)
|
||||
self.parent_info = parent_info
|
||||
self.src = fp.read()
|
||||
if self.src == '' or self.src[-1] != '\n':
|
||||
self.src += '\n'
|
||||
self.cursor = 0
|
||||
self.line = 1
|
||||
self.line_pos = 0
|
||||
self.exprs = []
|
||||
self.accept()
|
||||
|
||||
while self.tok != None:
|
||||
expr_info = {'file': input_relname, 'line': self.line, 'parent': self.parent_info}
|
||||
expr = self.get_expr(False)
|
||||
if isinstance(expr, dict) and "include" in expr:
|
||||
if len(expr) != 1:
|
||||
raise QAPIExprError(expr_info, "Invalid 'include' directive")
|
||||
include = expr["include"]
|
||||
if not isinstance(include, str):
|
||||
raise QAPIExprError(expr_info,
|
||||
'Expected a file name (string), got: %s'
|
||||
% include)
|
||||
include_path = os.path.join(self.input_dir, include)
|
||||
for elem in self.include_hist:
|
||||
if include_path == elem[1]:
|
||||
raise QAPIExprError(expr_info, "Inclusion loop for %s"
|
||||
% include)
|
||||
# skip multiple include of the same file
|
||||
if include_path in previously_included:
|
||||
continue
|
||||
try:
|
||||
fobj = open(include_path, 'r')
|
||||
except IOError, e:
|
||||
raise QAPIExprError(expr_info,
|
||||
'%s: %s' % (e.strerror, include))
|
||||
exprs_include = QAPISchema(fobj, include, self.include_hist,
|
||||
previously_included, expr_info)
|
||||
self.exprs.extend(exprs_include.exprs)
|
||||
else:
|
||||
expr_elem = {'expr': expr,
|
||||
'info': expr_info}
|
||||
self.exprs.append(expr_elem)
|
||||
|
||||
def accept(self):
|
||||
while True:
|
||||
self.tok = self.src[self.cursor]
|
||||
self.pos = self.cursor
|
||||
self.cursor += 1
|
||||
self.val = None
|
||||
|
||||
if self.tok == '#':
|
||||
self.cursor = self.src.find('\n', self.cursor)
|
||||
elif self.tok in ['{', '}', ':', ',', '[', ']']:
|
||||
return
|
||||
elif self.tok == "'":
|
||||
string = ''
|
||||
esc = False
|
||||
while True:
|
||||
ch = self.src[self.cursor]
|
||||
self.cursor += 1
|
||||
if ch == '\n':
|
||||
raise QAPISchemaError(self,
|
||||
'Missing terminating "\'"')
|
||||
if esc:
|
||||
string += ch
|
||||
esc = False
|
||||
elif ch == "\\":
|
||||
esc = True
|
||||
elif ch == "'":
|
||||
self.val = string
|
||||
return
|
||||
else:
|
||||
string += ch
|
||||
elif self.tok == '\n':
|
||||
if self.cursor == len(self.src):
|
||||
self.tok = None
|
||||
return
|
||||
self.line += 1
|
||||
self.line_pos = self.cursor
|
||||
elif not self.tok.isspace():
|
||||
raise QAPISchemaError(self, 'Stray "%s"' % self.tok)
|
||||
|
||||
def get_members(self):
|
||||
expr = OrderedDict()
|
||||
if self.tok == '}':
|
||||
self.accept()
|
||||
return expr
|
||||
if self.tok != "'":
|
||||
raise QAPISchemaError(self, 'Expected string or "}"')
|
||||
while True:
|
||||
key = self.val
|
||||
self.accept()
|
||||
if self.tok != ':':
|
||||
raise QAPISchemaError(self, 'Expected ":"')
|
||||
self.accept()
|
||||
if key in expr:
|
||||
raise QAPISchemaError(self, 'Duplicate key "%s"' % key)
|
||||
expr[key] = self.get_expr(True)
|
||||
if self.tok == '}':
|
||||
self.accept()
|
||||
return expr
|
||||
if self.tok != ',':
|
||||
raise QAPISchemaError(self, 'Expected "," or "}"')
|
||||
self.accept()
|
||||
if self.tok != "'":
|
||||
raise QAPISchemaError(self, 'Expected string')
|
||||
|
||||
def get_values(self):
|
||||
expr = []
|
||||
if self.tok == ']':
|
||||
self.accept()
|
||||
return expr
|
||||
if not self.tok in [ '{', '[', "'" ]:
|
||||
raise QAPISchemaError(self, 'Expected "{", "[", "]" or string')
|
||||
while True:
|
||||
expr.append(self.get_expr(True))
|
||||
if self.tok == ']':
|
||||
self.accept()
|
||||
return expr
|
||||
if self.tok != ',':
|
||||
raise QAPISchemaError(self, 'Expected "," or "]"')
|
||||
self.accept()
|
||||
|
||||
def get_expr(self, nested):
|
||||
if self.tok != '{' and not nested:
|
||||
raise QAPISchemaError(self, 'Expected "{"')
|
||||
if self.tok == '{':
|
||||
self.accept()
|
||||
expr = self.get_members()
|
||||
elif self.tok == '[':
|
||||
self.accept()
|
||||
expr = self.get_values()
|
||||
elif self.tok == "'":
|
||||
expr = self.val
|
||||
self.accept()
|
||||
else:
|
||||
raise QAPISchemaError(self, 'Expected "{", "[" or string')
|
||||
return expr
|
||||
|
||||
def find_base_fields(base):
|
||||
base_struct_define = find_struct(base)
|
||||
if not base_struct_define:
|
||||
return None
|
||||
return base_struct_define['data']
|
||||
|
||||
# Return the discriminator enum define if discriminator is specified as an
|
||||
# enum type, otherwise return None.
|
||||
def discriminator_find_enum_define(expr):
|
||||
base = expr.get('base')
|
||||
discriminator = expr.get('discriminator')
|
||||
|
||||
if not (discriminator and base):
|
||||
return None
|
||||
|
||||
base_fields = find_base_fields(base)
|
||||
if not base_fields:
|
||||
return None
|
||||
|
||||
discriminator_type = base_fields.get(discriminator)
|
||||
if not discriminator_type:
|
||||
return None
|
||||
|
||||
return find_enum(discriminator_type)
|
||||
|
||||
def check_event(expr, expr_info):
|
||||
params = expr.get('data')
|
||||
if params:
|
||||
for argname, argentry, optional, structured in parse_args(params):
|
||||
if structured:
|
||||
raise QAPIExprError(expr_info,
|
||||
"Nested structure define in event is not "
|
||||
"supported, event '%s', argname '%s'"
|
||||
% (expr['event'], argname))
|
||||
|
||||
def check_union(expr, expr_info):
|
||||
name = expr['union']
|
||||
base = expr.get('base')
|
||||
discriminator = expr.get('discriminator')
|
||||
members = expr['data']
|
||||
|
||||
# If the object has a member 'base', its value must name a complex type.
|
||||
if base:
|
||||
base_fields = find_base_fields(base)
|
||||
if not base_fields:
|
||||
raise QAPIExprError(expr_info,
|
||||
"Base '%s' is not a valid type"
|
||||
% base)
|
||||
|
||||
# If the union object has no member 'discriminator', it's an
|
||||
# ordinary union.
|
||||
if not discriminator:
|
||||
enum_define = None
|
||||
|
||||
# Else if the value of member 'discriminator' is {}, it's an
|
||||
# anonymous union.
|
||||
elif discriminator == {}:
|
||||
enum_define = None
|
||||
|
||||
# Else, it's a flat union.
|
||||
else:
|
||||
# The object must have a member 'base'.
|
||||
if not base:
|
||||
raise QAPIExprError(expr_info,
|
||||
"Flat union '%s' must have a base field"
|
||||
% name)
|
||||
# The value of member 'discriminator' must name a member of the
|
||||
# base type.
|
||||
discriminator_type = base_fields.get(discriminator)
|
||||
if not discriminator_type:
|
||||
raise QAPIExprError(expr_info,
|
||||
"Discriminator '%s' is not a member of base "
|
||||
"type '%s'"
|
||||
% (discriminator, base))
|
||||
enum_define = find_enum(discriminator_type)
|
||||
# Do not allow string discriminator
|
||||
if not enum_define:
|
||||
raise QAPIExprError(expr_info,
|
||||
"Discriminator '%s' must be of enumeration "
|
||||
"type" % discriminator)
|
||||
|
||||
# Check every branch
|
||||
for (key, value) in members.items():
|
||||
# If this named member's value names an enum type, then all members
|
||||
# of 'data' must also be members of the enum type.
|
||||
if enum_define and not key in enum_define['enum_values']:
|
||||
raise QAPIExprError(expr_info,
|
||||
"Discriminator value '%s' is not found in "
|
||||
"enum '%s'" %
|
||||
(key, enum_define["enum_name"]))
|
||||
# Todo: add checking for values. Key is checked as above, value can be
|
||||
# also checked here, but we need more functions to handle array case.
|
||||
|
||||
def check_exprs(schema):
|
||||
for expr_elem in schema.exprs:
|
||||
expr = expr_elem['expr']
|
||||
if expr.has_key('union'):
|
||||
check_union(expr, expr_elem['info'])
|
||||
if expr.has_key('event'):
|
||||
check_event(expr, expr_elem['info'])
|
||||
|
||||
def parse_schema(input_file):
|
||||
try:
|
||||
schema = QAPISchema(open(input_file, "r"))
|
||||
except (QAPISchemaError, QAPIExprError), e:
|
||||
print >>sys.stderr, e
|
||||
exit(1)
|
||||
|
||||
exprs = []
|
||||
|
||||
for expr_elem in schema.exprs:
|
||||
expr = expr_elem['expr']
|
||||
if expr.has_key('enum'):
|
||||
add_enum(expr['enum'], expr['data'])
|
||||
elif expr.has_key('union'):
|
||||
add_union(expr)
|
||||
elif expr.has_key('type'):
|
||||
add_struct(expr)
|
||||
exprs.append(expr)
|
||||
|
||||
# Try again for hidden UnionKind enum
|
||||
for expr_elem in schema.exprs:
|
||||
expr = expr_elem['expr']
|
||||
if expr.has_key('union'):
|
||||
if not discriminator_find_enum_define(expr):
|
||||
add_enum('%sKind' % expr['union'])
|
||||
|
||||
try:
|
||||
check_exprs(schema)
|
||||
except QAPIExprError, e:
|
||||
print >>sys.stderr, e
|
||||
exit(1)
|
||||
|
||||
return exprs
|
||||
|
||||
def parse_args(typeinfo):
|
||||
if isinstance(typeinfo, basestring):
|
||||
struct = find_struct(typeinfo)
|
||||
assert struct != None
|
||||
typeinfo = struct['data']
|
||||
|
||||
for member in typeinfo:
|
||||
argname = member
|
||||
argentry = typeinfo[member]
|
||||
optional = False
|
||||
structured = False
|
||||
if member.startswith('*'):
|
||||
argname = member[1:]
|
||||
optional = True
|
||||
if isinstance(argentry, OrderedDict):
|
||||
structured = True
|
||||
yield (argname, argentry, optional, structured)
|
||||
|
||||
def de_camel_case(name):
|
||||
new_name = ''
|
||||
for ch in name:
|
||||
if ch.isupper() and new_name:
|
||||
new_name += '_'
|
||||
if ch == '-':
|
||||
new_name += '_'
|
||||
else:
|
||||
new_name += ch.lower()
|
||||
return new_name
|
||||
|
||||
def camel_case(name):
|
||||
new_name = ''
|
||||
first = True
|
||||
for ch in name:
|
||||
if ch in ['_', '-']:
|
||||
first = True
|
||||
elif first:
|
||||
new_name += ch.upper()
|
||||
first = False
|
||||
else:
|
||||
new_name += ch.lower()
|
||||
return new_name
|
||||
|
||||
def c_var(name, protect=True):
|
||||
# ANSI X3J11/88-090, 3.1.1
|
||||
c89_words = set(['auto', 'break', 'case', 'char', 'const', 'continue',
|
||||
'default', 'do', 'double', 'else', 'enum', 'extern', 'float',
|
||||
'for', 'goto', 'if', 'int', 'long', 'register', 'return',
|
||||
'short', 'signed', 'sizeof', 'static', 'struct', 'switch',
|
||||
'typedef', 'union', 'unsigned', 'void', 'volatile', 'while'])
|
||||
# ISO/IEC 9899:1999, 6.4.1
|
||||
c99_words = set(['inline', 'restrict', '_Bool', '_Complex', '_Imaginary'])
|
||||
# ISO/IEC 9899:2011, 6.4.1
|
||||
c11_words = set(['_Alignas', '_Alignof', '_Atomic', '_Generic', '_Noreturn',
|
||||
'_Static_assert', '_Thread_local'])
|
||||
# GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html
|
||||
# excluding _.*
|
||||
gcc_words = set(['asm', 'typeof'])
|
||||
# C++ ISO/IEC 14882:2003 2.11
|
||||
cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete',
|
||||
'dynamic_cast', 'explicit', 'false', 'friend', 'mutable',
|
||||
'namespace', 'new', 'operator', 'private', 'protected',
|
||||
'public', 'reinterpret_cast', 'static_cast', 'template',
|
||||
'this', 'throw', 'true', 'try', 'typeid', 'typename',
|
||||
'using', 'virtual', 'wchar_t',
|
||||
# alternative representations
|
||||
'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not',
|
||||
'not_eq', 'or', 'or_eq', 'xor', 'xor_eq'])
|
||||
# namespace pollution:
|
||||
polluted_words = set(['unix', 'errno'])
|
||||
if protect and (name in c89_words | c99_words | c11_words | gcc_words | cpp_words | polluted_words):
|
||||
return "q_" + name
|
||||
return name.replace('-', '_').lstrip("*")
|
||||
|
||||
def c_fun(name, protect=True):
|
||||
return c_var(name, protect).replace('.', '_')
|
||||
|
||||
def c_list_type(name):
|
||||
return '%sList' % name
|
||||
|
||||
def type_name(name):
|
||||
if type(name) == list:
|
||||
return c_list_type(name[0])
|
||||
return name
|
||||
|
||||
enum_types = []
|
||||
struct_types = []
|
||||
union_types = []
|
||||
|
||||
def add_struct(definition):
|
||||
global struct_types
|
||||
struct_types.append(definition)
|
||||
|
||||
def find_struct(name):
|
||||
global struct_types
|
||||
for struct in struct_types:
|
||||
if struct['type'] == name:
|
||||
return struct
|
||||
return None
|
||||
|
||||
def add_union(definition):
|
||||
global union_types
|
||||
union_types.append(definition)
|
||||
|
||||
def find_union(name):
|
||||
global union_types
|
||||
for union in union_types:
|
||||
if union['union'] == name:
|
||||
return union
|
||||
return None
|
||||
|
||||
def add_enum(name, enum_values = None):
|
||||
global enum_types
|
||||
enum_types.append({"enum_name": name, "enum_values": enum_values})
|
||||
|
||||
def find_enum(name):
|
||||
global enum_types
|
||||
for enum in enum_types:
|
||||
if enum['enum_name'] == name:
|
||||
return enum
|
||||
return None
|
||||
|
||||
def is_enum(name):
|
||||
return find_enum(name) != None
|
||||
|
||||
eatspace = '\033EATSPACE.'
|
||||
|
||||
# A special suffix is added in c_type() for pointer types, and it's
|
||||
# stripped in mcgen(). So please notice this when you check the return
|
||||
# value of c_type() outside mcgen().
|
||||
def c_type(name, is_param=False):
|
||||
if name == 'str':
|
||||
if is_param:
|
||||
return 'const char *' + eatspace
|
||||
return 'char *' + eatspace
|
||||
|
||||
elif name == 'int':
|
||||
return 'int64_t'
|
||||
elif (name == 'int8' or name == 'int16' or name == 'int32' or
|
||||
name == 'int64' or name == 'uint8' or name == 'uint16' or
|
||||
name == 'uint32' or name == 'uint64'):
|
||||
return name + '_t'
|
||||
elif name == 'size':
|
||||
return 'uint64_t'
|
||||
elif name == 'bool':
|
||||
return 'bool'
|
||||
elif name == 'number':
|
||||
return 'double'
|
||||
elif type(name) == list:
|
||||
return '%s *%s' % (c_list_type(name[0]), eatspace)
|
||||
elif is_enum(name):
|
||||
return name
|
||||
elif name == None or len(name) == 0:
|
||||
return 'void'
|
||||
elif name == name.upper():
|
||||
return '%sEvent *%s' % (camel_case(name), eatspace)
|
||||
else:
|
||||
return '%s *%s' % (name, eatspace)
|
||||
|
||||
def is_c_ptr(name):
|
||||
suffix = "*" + eatspace
|
||||
return c_type(name).endswith(suffix)
|
||||
|
||||
def genindent(count):
|
||||
ret = ""
|
||||
for i in range(count):
|
||||
ret += " "
|
||||
return ret
|
||||
|
||||
indent_level = 0
|
||||
|
||||
def push_indent(indent_amount=4):
|
||||
global indent_level
|
||||
indent_level += indent_amount
|
||||
|
||||
def pop_indent(indent_amount=4):
|
||||
global indent_level
|
||||
indent_level -= indent_amount
|
||||
|
||||
def cgen(code, **kwds):
|
||||
indent = genindent(indent_level)
|
||||
lines = code.split('\n')
|
||||
lines = map(lambda x: indent + x, lines)
|
||||
return '\n'.join(lines) % kwds + '\n'
|
||||
|
||||
def mcgen(code, **kwds):
|
||||
raw = cgen('\n'.join(code.split('\n')[1:-1]), **kwds)
|
||||
return re.sub(re.escape(eatspace) + ' *', '', raw)
|
||||
|
||||
def basename(filename):
|
||||
return filename.split("/")[-1]
|
||||
|
||||
def guardname(filename):
|
||||
guard = basename(filename).rsplit(".", 1)[0]
|
||||
for substr in [".", " ", "-"]:
|
||||
guard = guard.replace(substr, "_")
|
||||
return guard.upper() + '_H'
|
||||
|
||||
def guardstart(name):
|
||||
return mcgen('''
|
||||
|
||||
#ifndef %(name)s
|
||||
#define %(name)s
|
||||
|
||||
''',
|
||||
name=guardname(name))
|
||||
|
||||
def guardend(name):
|
||||
return mcgen('''
|
||||
|
||||
#endif /* %(name)s */
|
||||
|
||||
''',
|
||||
name=guardname(name))
|
||||
|
||||
# ENUMName -> ENUM_NAME, EnumName1 -> ENUM_NAME1
|
||||
# ENUM_NAME -> ENUM_NAME, ENUM_NAME1 -> ENUM_NAME1, ENUM_Name2 -> ENUM_NAME2
|
||||
# ENUM24_Name -> ENUM24_NAME
|
||||
def _generate_enum_string(value):
|
||||
c_fun_str = c_fun(value, False)
|
||||
if value.isupper():
|
||||
return c_fun_str
|
||||
|
||||
new_name = ''
|
||||
l = len(c_fun_str)
|
||||
for i in range(l):
|
||||
c = c_fun_str[i]
|
||||
# When c is upper and no "_" appears before, do more checks
|
||||
if c.isupper() and (i > 0) and c_fun_str[i - 1] != "_":
|
||||
# Case 1: next string is lower
|
||||
# Case 2: previous string is digit
|
||||
if (i < (l - 1) and c_fun_str[i + 1].islower()) or \
|
||||
c_fun_str[i - 1].isdigit():
|
||||
new_name += '_'
|
||||
new_name += c
|
||||
return new_name.lstrip('_').upper()
|
||||
|
||||
def generate_enum_full_value(enum_name, enum_value):
|
||||
abbrev_string = _generate_enum_string(enum_name)
|
||||
value_string = _generate_enum_string(enum_value)
|
||||
return "%s_%s" % (abbrev_string, value_string)
|
||||
Reference in New Issue
Block a user