mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-28 11:31:16 +00:00
Invoke the generator twice and introduce separate meson targets for headers and C sources. Signed-off-by: Ján Tomko <jtomko@redhat.com> Reviewed-by: Pavel Hrdina <phrdina@redhat.com>
1721 lines
60 KiB
Python
Executable File
1721 lines
60 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
#
|
|
# esx_vi_generator.py: generates most of the SOAP type mapping code
|
|
#
|
|
# Copyright (C) 2014 Red Hat, Inc.
|
|
# Copyright (C) 2010-2012 Matthias Bolte <matthias.bolte@googlemail.com>
|
|
# Copyright (C) 2013 Ata E Husain Bohra <ata.husain@hotmail.com>
|
|
#
|
|
# This library is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU Lesser General Public
|
|
# License as published by the Free Software Foundation; either
|
|
# version 2.1 of the License, or (at your option) any later version.
|
|
#
|
|
# This library 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
|
|
# Lesser General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Lesser General Public
|
|
# License along with this library. If not, see
|
|
# <http://www.gnu.org/licenses/>.
|
|
#
|
|
|
|
import sys
|
|
import os
|
|
import os.path
|
|
|
|
|
|
OCCURRENCE__REQUIRED_ITEM = "r"
|
|
OCCURRENCE__REQUIRED_LIST = "rl"
|
|
OCCURRENCE__OPTIONAL_ITEM = "o"
|
|
OCCURRENCE__OPTIONAL_LIST = "ol"
|
|
OCCURRENCE__IGNORED = "i"
|
|
|
|
valid_occurrences = [OCCURRENCE__REQUIRED_ITEM,
|
|
OCCURRENCE__REQUIRED_LIST,
|
|
OCCURRENCE__OPTIONAL_ITEM,
|
|
OCCURRENCE__OPTIONAL_LIST,
|
|
OCCURRENCE__IGNORED]
|
|
|
|
autobind_names = set()
|
|
|
|
separator = "/* " + ("* " * 37) + "*\n"
|
|
|
|
|
|
def aligned(left, right, length=59):
|
|
return left.ljust(length, ' ') + right
|
|
|
|
|
|
class Member:
|
|
def __init__(self, type, occurrence):
|
|
self.type = type
|
|
self.occurrence = occurrence
|
|
|
|
def is_enum(self):
|
|
return self.type in predefined_enums or self.type in enums_by_name
|
|
|
|
def is_object(self):
|
|
return self.type in predefined_objects or self.type in objects_by_name
|
|
|
|
def is_type_generated(self):
|
|
return self.type in enums_by_name or self.type in objects_by_name
|
|
|
|
def get_occurrence_comment(self):
|
|
occurrence_map = {
|
|
OCCURRENCE__REQUIRED_ITEM: "/* required */",
|
|
OCCURRENCE__REQUIRED_LIST: "/* required, list */",
|
|
OCCURRENCE__OPTIONAL_ITEM: "/* optional */",
|
|
OCCURRENCE__OPTIONAL_LIST: "/* optional, list */"
|
|
}
|
|
try:
|
|
return occurrence_map[self.occurrence]
|
|
except KeyError:
|
|
raise ValueError("unknown occurrence value '%s'" % self.occurrence)
|
|
|
|
|
|
class Parameter(Member):
|
|
def __init__(self, type, name, occurrence):
|
|
Member.__init__(self, type, occurrence)
|
|
|
|
if ':' in name and name.startswith("_this"):
|
|
self.name, self.autobind_name = name.split(":")
|
|
else:
|
|
self.name = name
|
|
self.autobind_name = None
|
|
|
|
def generate_parameter(self, is_last=False, is_header=True, offset=0):
|
|
if self.occurrence == OCCURRENCE__IGNORED:
|
|
raise ValueError("invalid function parameter occurrence value '%s'"
|
|
% self.occurrence)
|
|
elif self.autobind_name is not None:
|
|
return ""
|
|
else:
|
|
string = " "
|
|
string += " " * offset
|
|
string += "%s%s" % (self.get_type_string(), self.name)
|
|
|
|
if is_last:
|
|
if is_header:
|
|
string += "); "
|
|
else:
|
|
string += "), "
|
|
else:
|
|
string += ", "
|
|
|
|
return aligned(string, self.get_occurrence_comment() + "\n")
|
|
|
|
def generate_return(self, offset=0, end_of_line=";"):
|
|
if self.occurrence == OCCURRENCE__IGNORED:
|
|
raise ValueError("invalid function parameter occurrence value '%s'"
|
|
% self.occurrence)
|
|
else:
|
|
string = " "
|
|
string += " " * offset
|
|
string += "%s%s)%s" \
|
|
% (self.get_type_string(True), self.name, end_of_line)
|
|
|
|
return aligned(string, self.get_occurrence_comment() + "\n")
|
|
|
|
def generate_require_code(self):
|
|
if self.occurrence in [OCCURRENCE__REQUIRED_ITEM,
|
|
OCCURRENCE__REQUIRED_LIST]:
|
|
return " ESX_VI__METHOD__PARAMETER__REQUIRE(%s)\n" % self.name
|
|
else:
|
|
return ""
|
|
|
|
def generate_serialize_code(self):
|
|
if self.occurrence in [OCCURRENCE__REQUIRED_LIST,
|
|
OCCURRENCE__OPTIONAL_LIST]:
|
|
return " ESX_VI__METHOD__PARAMETER__SERIALIZE_LIST(%s, %s)\n" \
|
|
% (self.type, self.name)
|
|
elif self.type == "String":
|
|
return " ESX_VI__METHOD__PARAMETER__SERIALIZE_VALUE(String, %s)\n" \
|
|
% self.name
|
|
else:
|
|
return " ESX_VI__METHOD__PARAMETER__SERIALIZE(%s, %s)\n" \
|
|
% (self.type, self.name)
|
|
|
|
def get_type_string(self, as_return_value=False):
|
|
string = ""
|
|
|
|
if self.type == "String" and \
|
|
self.occurrence not in [OCCURRENCE__REQUIRED_LIST,
|
|
OCCURRENCE__OPTIONAL_LIST]:
|
|
if as_return_value:
|
|
string += "char *"
|
|
else:
|
|
string += "const char *"
|
|
elif self.is_enum():
|
|
string += "esxVI_%s " % self.type
|
|
else:
|
|
string += "esxVI_%s *" % self.type
|
|
|
|
if as_return_value:
|
|
string += "*"
|
|
|
|
return string
|
|
|
|
def get_occurrence_short_enum(self):
|
|
if self.occurrence == OCCURRENCE__REQUIRED_ITEM:
|
|
return "RequiredItem"
|
|
elif self.occurrence == OCCURRENCE__REQUIRED_LIST:
|
|
return "RequiredList"
|
|
elif self.occurrence == OCCURRENCE__OPTIONAL_ITEM:
|
|
return "OptionalItem"
|
|
elif self.occurrence == OCCURRENCE__OPTIONAL_LIST:
|
|
return "OptionalList"
|
|
|
|
raise ValueError("unknown occurrence value '%s'" % self.occurrence)
|
|
|
|
|
|
class Method:
|
|
def __init__(self, name, parameters, returns):
|
|
self.name = name
|
|
self.parameters = []
|
|
self.autobind_parameter = None
|
|
self.returns = returns
|
|
|
|
for parameter in parameters:
|
|
if parameter.autobind_name is None:
|
|
self.parameters.append(parameter)
|
|
else:
|
|
self.autobind_parameter = parameter
|
|
|
|
def generate_header(self):
|
|
header = "int esxVI_%s\n" % self.name
|
|
header += " (esxVI_Context *ctx"
|
|
|
|
if len(self.parameters) > 0 or self.returns is not None:
|
|
header += ",\n"
|
|
|
|
for parameter in self.parameters[:-1]:
|
|
header += parameter.generate_parameter()
|
|
|
|
if self.returns is None:
|
|
header += self.parameters[-1].generate_parameter(is_last=True)
|
|
else:
|
|
header += self.parameters[-1].generate_parameter()
|
|
header += self.returns.generate_return()
|
|
else:
|
|
header += ");\n"
|
|
|
|
header += "\n"
|
|
|
|
return header
|
|
|
|
def generate_source(self):
|
|
source = "/* esxVI_%s */\n" % self.name
|
|
source += "ESX_VI__METHOD(%s," % self.name
|
|
|
|
if self.autobind_parameter is not None:
|
|
autobind_names.add(self.autobind_parameter.autobind_name)
|
|
source += " %s,\n" % self.autobind_parameter.autobind_name
|
|
else:
|
|
source += " /* explicit _this */,\n"
|
|
|
|
source += " (esxVI_Context *ctx"
|
|
|
|
if len(self.parameters) > 0 or self.returns is not None:
|
|
source += ",\n"
|
|
|
|
for parameter in self.parameters[:-1]:
|
|
source += parameter.generate_parameter(is_header=False,
|
|
offset=9)
|
|
|
|
if self.returns is None:
|
|
source += self.parameters[-1].generate_parameter(is_last=True,
|
|
is_header=False,
|
|
offset=9)
|
|
else:
|
|
source += self.parameters[-1].generate_parameter(is_header=False,
|
|
offset=9)
|
|
source += self.returns.generate_return(offset=9,
|
|
end_of_line=",")
|
|
else:
|
|
source += "),\n"
|
|
|
|
if self.returns is None:
|
|
source += " void, /* nothing */, None,\n"
|
|
elif self.returns.type == "String":
|
|
source += " String, Value, %s,\n" \
|
|
% self.returns.get_occurrence_short_enum()
|
|
else:
|
|
source += " %s, /* nothing */, %s,\n" \
|
|
% (self.returns.type,
|
|
self.returns.get_occurrence_short_enum())
|
|
|
|
source += "{\n"
|
|
|
|
if self.autobind_parameter is not None:
|
|
source += self.autobind_parameter.generate_require_code()
|
|
|
|
for parameter in self.parameters:
|
|
source += parameter.generate_require_code()
|
|
|
|
source += "},\n"
|
|
source += "{\n"
|
|
|
|
if self.autobind_parameter is not None:
|
|
source += self.autobind_parameter.generate_serialize_code()
|
|
|
|
for parameter in self.parameters:
|
|
source += parameter.generate_serialize_code()
|
|
|
|
source += "})\n\n\n\n"
|
|
|
|
return source
|
|
|
|
|
|
class Property(Member):
|
|
def __init__(self, type, name, occurrence):
|
|
Member.__init__(self, type, occurrence)
|
|
|
|
self.name = name
|
|
|
|
def generate_struct_member(self):
|
|
if self.occurrence == OCCURRENCE__IGNORED:
|
|
return " /* FIXME: %s is currently ignored */\n" % self.name
|
|
else:
|
|
string = " %s%s; " % (self.get_type_string(), self.name)
|
|
|
|
return aligned(string, self.get_occurrence_comment() + "\n")
|
|
|
|
def generate_free_code(self):
|
|
if self.type == "String" and \
|
|
self.occurrence not in [OCCURRENCE__REQUIRED_LIST,
|
|
OCCURRENCE__OPTIONAL_LIST,
|
|
OCCURRENCE__IGNORED]:
|
|
return " VIR_FREE(item->%s);\n" % self.name
|
|
elif self.is_enum():
|
|
return ""
|
|
else:
|
|
if self.occurrence == OCCURRENCE__IGNORED:
|
|
return " /* FIXME: %s is currently ignored */\n" % self.name
|
|
else:
|
|
return " esxVI_%s_Free(&item->%s);\n" % (self.type, self.name)
|
|
|
|
def generate_validate_code(self, managed=False):
|
|
if managed:
|
|
macro = "ESX_VI__TEMPLATE__PROPERTY__MANAGED_REQUIRE"
|
|
else:
|
|
macro = "ESX_VI__TEMPLATE__PROPERTY__REQUIRE"
|
|
|
|
if self.occurrence in [OCCURRENCE__REQUIRED_ITEM,
|
|
OCCURRENCE__REQUIRED_LIST]:
|
|
return " %s(%s)\n" % (macro, self.name)
|
|
elif self.occurrence == OCCURRENCE__IGNORED:
|
|
return " /* FIXME: %s is currently ignored */\n" % self.name
|
|
else:
|
|
return ""
|
|
|
|
def generate_deep_copy_code(self):
|
|
if self.occurrence == OCCURRENCE__IGNORED:
|
|
return " /* FIXME: %s is currently ignored */\n" % self.name
|
|
elif self.occurrence in [OCCURRENCE__REQUIRED_LIST,
|
|
OCCURRENCE__OPTIONAL_LIST]:
|
|
return " ESX_VI__TEMPLATE__PROPERTY__DEEP_COPY_LIST(%s, %s)\n" \
|
|
% (self.type, self.name)
|
|
elif self.type == "String":
|
|
return " ESX_VI__TEMPLATE__PROPERTY__DEEP_COPY_VALUE(String, %s)\n" \
|
|
% self.name
|
|
elif self.is_enum():
|
|
return " (*dest)->%s = src->%s;\n" % (self.name, self.name)
|
|
else:
|
|
return " ESX_VI__TEMPLATE__PROPERTY__DEEP_COPY(%s, %s)\n" \
|
|
% (self.type, self.name)
|
|
|
|
def generate_serialize_code(self):
|
|
if self.occurrence == OCCURRENCE__IGNORED:
|
|
return " /* FIXME: %s is currently ignored */\n" % self.name
|
|
elif self.occurrence in [OCCURRENCE__REQUIRED_LIST,
|
|
OCCURRENCE__OPTIONAL_LIST]:
|
|
return " ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_LIST(%s, %s)\n" \
|
|
% (self.type, self.name)
|
|
elif self.type == "String":
|
|
return " ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_VALUE(String, %s)\n" \
|
|
% self.name
|
|
else:
|
|
return " ESX_VI__TEMPLATE__PROPERTY__SERIALIZE(%s, %s)\n" \
|
|
% (self.type, self.name)
|
|
|
|
def generate_deserialize_code(self):
|
|
if self.occurrence == OCCURRENCE__IGNORED:
|
|
return " ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_IGNORE(%s) /* FIXME */\n" \
|
|
% self.name
|
|
elif self.occurrence in [OCCURRENCE__REQUIRED_LIST,
|
|
OCCURRENCE__OPTIONAL_LIST]:
|
|
return " ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_LIST(%s, %s)\n" \
|
|
% (self.type, self.name)
|
|
elif self.type == "String":
|
|
return " ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, %s)\n" \
|
|
% self.name
|
|
else:
|
|
return " ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(%s, %s)\n" \
|
|
% (self.type, self.name)
|
|
|
|
def generate_lookup_code(self):
|
|
if self.occurrence == OCCURRENCE__IGNORED:
|
|
return " ESX_VI__TEMPLATE__PROPERTY__CAST_FROM_ANY_TYPE_IGNORE(%s) /* FIXME */\n" \
|
|
% self.name
|
|
elif self.occurrence in [OCCURRENCE__REQUIRED_LIST,
|
|
OCCURRENCE__OPTIONAL_LIST]:
|
|
return " ESX_VI__TEMPLATE__PROPERTY__CAST_LIST_FROM_ANY_TYPE(%s, %s)\n" \
|
|
% (self.type, self.name)
|
|
elif self.type == "String":
|
|
return " ESX_VI__TEMPLATE__PROPERTY__CAST_VALUE_FROM_ANY_TYPE(String, %s)\n" \
|
|
% self.name
|
|
else:
|
|
return " ESX_VI__TEMPLATE__PROPERTY__CAST_FROM_ANY_TYPE(%s, %s)\n" \
|
|
% (self.type, self.name)
|
|
|
|
def get_type_string(self):
|
|
if self.type == "String" and \
|
|
self.occurrence not in [OCCURRENCE__REQUIRED_LIST,
|
|
OCCURRENCE__OPTIONAL_LIST]:
|
|
return "char *"
|
|
elif self.is_enum():
|
|
return "esxVI_%s " % self.type
|
|
else:
|
|
return "esxVI_%s *" % self.type
|
|
|
|
|
|
class Type:
|
|
def __init__(self, kind, name):
|
|
self.kind = kind
|
|
self.name = name
|
|
|
|
def generate_typedef(self):
|
|
return "typedef %s _esxVI_%s esxVI_%s;\n" \
|
|
% (self.kind, self.name, self.name)
|
|
|
|
def generate_typeenum(self):
|
|
return " esxVI_Type_%s,\n" % self.name
|
|
|
|
def generate_typetostring(self):
|
|
string = " case esxVI_Type_%s:\n" % self.name
|
|
string += " return \"%s\";\n\n" % self.name
|
|
|
|
return string
|
|
|
|
def generate_typefromstring(self):
|
|
string = " if (STREQ(type, \"%s\"))\n" % self.name
|
|
string += " return esxVI_Type_%s;\n" % self.name
|
|
|
|
return string
|
|
|
|
|
|
class GenericObject(Type):
|
|
FEATURE__DYNAMIC_CAST = (1 << 1)
|
|
FEATURE__LIST = (1 << 2)
|
|
FEATURE__DEEP_COPY = (1 << 3)
|
|
FEATURE__ANY_TYPE = (1 << 4)
|
|
FEATURE__SERIALIZE = (1 << 5)
|
|
FEATURE__DESERIALIZE = (1 << 6)
|
|
|
|
def __init__(self, name, category, managed, generic_objects_by_name):
|
|
Type.__init__(self, "struct", name)
|
|
self.category = category
|
|
self.managed = managed
|
|
self.generic_objects_by_name = generic_objects_by_name
|
|
|
|
def generate_comment(self):
|
|
comment = separator
|
|
comment += " * %s: %s\n" % (self.category, self.name)
|
|
|
|
if self.extends is not None:
|
|
comment += " * %s extends %s\n" \
|
|
% (' ' * len(self.category), self.extends)
|
|
|
|
first = True
|
|
|
|
if self.extended_by is not None:
|
|
for extended_by in self.extended_by:
|
|
if first:
|
|
comment += " * %s extended by %s\n" \
|
|
% (' ' * len(self.category), extended_by)
|
|
first = False
|
|
else:
|
|
comment += " * %s %s\n" \
|
|
% (' ' * len(self.category), extended_by)
|
|
|
|
comment += " */\n\n"
|
|
|
|
return comment
|
|
|
|
def generate_struct_members(self, add_banner=False, struct_gap=False):
|
|
members = ""
|
|
|
|
if struct_gap:
|
|
members += "\n"
|
|
|
|
if self.extends is not None:
|
|
obj = self.generic_objects_by_name[self.extends]
|
|
members += obj.generate_struct_members(add_banner=True,
|
|
struct_gap=False) + "\n"
|
|
|
|
if self.extends is not None or add_banner:
|
|
members += " /* %s */\n" % self.name
|
|
|
|
for property in self.properties:
|
|
members += property.generate_struct_member()
|
|
|
|
if len(self.properties) < 1:
|
|
members += " /* no properties */\n"
|
|
|
|
return members
|
|
|
|
def generate_dispatch(self, suffix, is_first=True):
|
|
source = ""
|
|
|
|
if self.extended_by is not None:
|
|
if not is_first:
|
|
source += "\n"
|
|
|
|
source += " /* %s */\n" % self.name
|
|
|
|
for extended_by in self.extended_by:
|
|
source += " ESX_VI__TEMPLATE__DISPATCH__%s(%s)\n" \
|
|
% (suffix, extended_by)
|
|
|
|
for extended_by in self.extended_by:
|
|
obj = self.generic_objects_by_name[extended_by]
|
|
source += obj.generate_dispatch(suffix, False)
|
|
|
|
return source
|
|
|
|
def generate_free_code(self, add_banner=False):
|
|
source = ""
|
|
|
|
if self.extends is not None:
|
|
obj = self.generic_objects_by_name[self.extends]
|
|
source += obj.generate_free_code(add_banner=True) + "\n"
|
|
|
|
if self.extends is not None or add_banner:
|
|
source += " /* %s */\n" % self.name
|
|
|
|
if len(self.properties) < 1:
|
|
source += " /* no properties */\n"
|
|
else:
|
|
string = ""
|
|
|
|
for property in self.properties:
|
|
string += property.generate_free_code()
|
|
|
|
if len(string) < 1:
|
|
source += " /* no properties to be freed */\n"
|
|
else:
|
|
source += string
|
|
|
|
return source
|
|
|
|
def generate_validate_code(self, add_banner=False):
|
|
source = ""
|
|
|
|
if self.extends is not None:
|
|
obj = self.generic_objects_by_name[self.extends]
|
|
source += obj.generate_validate_code(add_banner=True) + "\n"
|
|
|
|
if self.extends is not None or add_banner:
|
|
source += " /* %s */\n" % self.name
|
|
|
|
if len(self.properties) < 1:
|
|
source += " /* no properties */\n"
|
|
else:
|
|
string = ""
|
|
|
|
for property in self.properties:
|
|
string += property.generate_validate_code(self.managed)
|
|
|
|
if len(string) < 1:
|
|
source += " /* no required properties */\n"
|
|
else:
|
|
source += string
|
|
|
|
return source
|
|
|
|
|
|
class Object(GenericObject):
|
|
def __init__(self, name, extends, properties, features=0, extended_by=None):
|
|
GenericObject.__init__(self, name, 'VI Object', False, objects_by_name)
|
|
self.extends = extends
|
|
self.features = features
|
|
self.properties = properties
|
|
self.extended_by = extended_by
|
|
self.candidate_for_dynamic_cast = False
|
|
|
|
if self.extended_by is not None:
|
|
self.extended_by.sort()
|
|
|
|
def generate_dynamic_cast_code(self, is_first=True):
|
|
source = ""
|
|
|
|
if self.extended_by is not None:
|
|
if not is_first:
|
|
source += "\n"
|
|
|
|
source += " /* %s */\n" % self.name
|
|
|
|
for extended_by in self.extended_by:
|
|
source += " ESX_VI__TEMPLATE__DYNAMIC_CAST__ACCEPT(%s)\n" \
|
|
% extended_by
|
|
|
|
for extended_by in self.extended_by:
|
|
obj = objects_by_name[extended_by]
|
|
source += obj.generate_dynamic_cast_code(False)
|
|
|
|
return source
|
|
|
|
def generate_deep_copy_code(self, add_banner=False):
|
|
source = ""
|
|
|
|
if self.extends is not None:
|
|
obj = objects_by_name[self.extends]
|
|
source += obj.generate_deep_copy_code(add_banner=True) + "\n"
|
|
|
|
if self.extends is not None or add_banner:
|
|
source += " /* %s */\n" % self.name
|
|
|
|
if len(self.properties) < 1:
|
|
source += " /* no properties */\n"
|
|
else:
|
|
string = ""
|
|
|
|
for property in self.properties:
|
|
string += property.generate_deep_copy_code()
|
|
|
|
if len(string) < 1:
|
|
source += " /* no properties to be deep copied */\n"
|
|
else:
|
|
source += string
|
|
|
|
return source
|
|
|
|
def generate_serialize_code(self, add_banner=False):
|
|
source = ""
|
|
|
|
if self.extends is not None:
|
|
obj = objects_by_name[self.extends]
|
|
source += obj.generate_serialize_code(add_banner=True) + "\n"
|
|
|
|
if self.extends is not None or add_banner:
|
|
source += " /* %s */\n" % self.name
|
|
|
|
if len(self.properties) < 1:
|
|
source += " /* no properties */\n"
|
|
else:
|
|
for property in self.properties:
|
|
source += property.generate_serialize_code()
|
|
|
|
return source
|
|
|
|
def generate_deserialize_code(self, add_banner=False):
|
|
source = ""
|
|
|
|
if self.extends is not None:
|
|
obj = objects_by_name[self.extends]
|
|
source += obj.generate_deserialize_code(add_banner=True) + "\n"
|
|
|
|
if self.extends is not None or add_banner:
|
|
source += " /* %s */\n" % self.name
|
|
|
|
if len(self.properties) < 1:
|
|
source += " /* no properties */\n"
|
|
else:
|
|
for property in self.properties:
|
|
source += property.generate_deserialize_code()
|
|
|
|
return source
|
|
|
|
def generate_header(self):
|
|
header = self.generate_comment()
|
|
|
|
# struct
|
|
header += "struct _esxVI_%s {\n" % self.name
|
|
|
|
if self.features & Object.FEATURE__LIST:
|
|
header += aligned(" esxVI_%s *_next; " % self.name,
|
|
"/* optional */\n")
|
|
else:
|
|
header += aligned(" esxVI_%s *_unused; " % self.name,
|
|
"/* optional */\n")
|
|
|
|
header += aligned(" esxVI_Type _type; ", "/* required */\n")
|
|
header += self.generate_struct_members(struct_gap=True)
|
|
header += "};\n\n"
|
|
|
|
# functions
|
|
header += "int esxVI_%s_Alloc(esxVI_%s **item);\n" \
|
|
% (self.name, self.name)
|
|
header += "void esxVI_%s_Free(esxVI_%s **item);\n" \
|
|
% (self.name, self.name)
|
|
header += "int esxVI_%s_Validate(esxVI_%s *item);\n" \
|
|
% (self.name, self.name)
|
|
|
|
if self.features & Object.FEATURE__DYNAMIC_CAST:
|
|
if self.extended_by is not None or self.extends is not None:
|
|
header += "esxVI_%s *esxVI_%s_DynamicCast(void *item);\n" \
|
|
% (self.name, self.name)
|
|
else:
|
|
report_error("cannot add dynamic cast support for an untyped object")
|
|
|
|
if self.features & Object.FEATURE__LIST:
|
|
header += "int esxVI_%s_AppendToList(esxVI_%s **list, esxVI_%s *item);\n" \
|
|
% (self.name, self.name, self.name)
|
|
|
|
if self.features & Object.FEATURE__DEEP_COPY:
|
|
header += "int esxVI_%s_DeepCopy(esxVI_%s **dst, esxVI_%s *src);\n" \
|
|
% (self.name, self.name, self.name)
|
|
|
|
if self.features & Object.FEATURE__LIST:
|
|
header += ((
|
|
"int esxVI_%s_DeepCopyList(esxVI_%s **dstList, "
|
|
" esxVI_%s *srcList);\n") %
|
|
(self.name, self.name, self.name))
|
|
|
|
if self.features & Object.FEATURE__ANY_TYPE:
|
|
header += ((
|
|
"int esxVI_%s_CastFromAnyType(esxVI_AnyType *anyType, "
|
|
" esxVI_%s **item);\n") %
|
|
(self.name, self.name))
|
|
|
|
if self.features & Object.FEATURE__LIST:
|
|
header += ((
|
|
"int esxVI_%s_CastListFromAnyType(esxVI_AnyType *anyType, "
|
|
" esxVI_%s **list);\n") %
|
|
(self.name, self.name))
|
|
|
|
if self.features & Object.FEATURE__SERIALIZE:
|
|
header += ((
|
|
"int esxVI_%s_Serialize(esxVI_%s *item, "
|
|
" const char *element, "
|
|
" virBufferPtr output);\n") %
|
|
(self.name, self.name))
|
|
|
|
if self.features & Object.FEATURE__LIST:
|
|
header += ((
|
|
"int esxVI_%s_SerializeList(esxVI_%s *list, "
|
|
" const char *element, "
|
|
" virBufferPtr output);\n") %
|
|
(self.name, self.name))
|
|
|
|
if self.features & Object.FEATURE__DESERIALIZE:
|
|
header += "int esxVI_%s_Deserialize(xmlNodePtr node, esxVI_%s **item);\n" \
|
|
% (self.name, self.name)
|
|
|
|
if self.features & Object.FEATURE__LIST:
|
|
header += ((
|
|
"int esxVI_%s_DeserializeList(xmlNodePtr node, "
|
|
" esxVI_%s **list);\n") %
|
|
(self.name, self.name))
|
|
|
|
header += "\n\n\n"
|
|
|
|
return header
|
|
|
|
def generate_source(self):
|
|
source = separator
|
|
source += " * VI Object: %s\n" % self.name
|
|
|
|
if self.extends is not None:
|
|
source += " * extends %s\n" % self.extends
|
|
|
|
first = True
|
|
|
|
if self.extended_by is not None:
|
|
for extended_by in self.extended_by:
|
|
if first:
|
|
source += " * extended by %s\n" % extended_by
|
|
first = False
|
|
else:
|
|
source += " * %s\n" % extended_by
|
|
|
|
source += " */\n\n"
|
|
|
|
# functions
|
|
source += "/* esxVI_%s_Alloc */\n" % self.name
|
|
source += "ESX_VI__TEMPLATE__ALLOC(%s)\n\n" % self.name
|
|
|
|
# free
|
|
source += "/* esxVI_%s_Free */\n" % self.name
|
|
|
|
if self.extended_by is None:
|
|
source += "ESX_VI__TEMPLATE__FREE(%s,\n" % self.name
|
|
else:
|
|
source += "ESX_VI__TEMPLATE__DYNAMIC_FREE(%s,\n" % self.name
|
|
source += "{\n"
|
|
source += self.generate_dispatch('FREE')
|
|
source += "},\n"
|
|
|
|
source += "{\n"
|
|
|
|
if self.features & Object.FEATURE__LIST:
|
|
base_class = get_base_class(self)
|
|
if base_class:
|
|
# avoid "dereferencing type-punned pointer will break
|
|
# strict-aliasing rules" warnings
|
|
source += " esxVI_%s *baseNext = (esxVI_%s *)item->_next;\n" \
|
|
% (base_class, base_class)
|
|
source += " esxVI_%s_Free(&baseNext);\n\n" % base_class
|
|
else:
|
|
source += " esxVI_%s_Free(&item->_next);\n\n" % self.name
|
|
|
|
source += self.generate_free_code()
|
|
source += "})\n\n"
|
|
|
|
# validate
|
|
source += "/* esxVI_%s_Validate */\n" % self.name
|
|
source += "ESX_VI__TEMPLATE__VALIDATE(%s,\n" % self.name
|
|
source += "{\n"
|
|
source += self.generate_validate_code()
|
|
source += "})\n\n"
|
|
|
|
# dynamic cast
|
|
if self.features & Object.FEATURE__DYNAMIC_CAST:
|
|
if self.extended_by is not None or self.extends is not None:
|
|
source += "/* esxVI_%s_DynamicCast */\n" % self.name
|
|
source += "ESX_VI__TEMPLATE__DYNAMIC_CAST(%s,\n" % self.name
|
|
source += "{\n"
|
|
source += self.generate_dynamic_cast_code()
|
|
source += "})\n\n"
|
|
else:
|
|
report_error("cannot add dynamic cast support for an untyped object")
|
|
|
|
# append to list
|
|
if self.features & Object.FEATURE__LIST:
|
|
source += "/* esxVI_%s_AppendToList */\n" % self.name
|
|
source += "ESX_VI__TEMPLATE__LIST__APPEND(%s)\n\n" % self.name
|
|
|
|
# deep copy
|
|
if self.features & Object.FEATURE__DEEP_COPY:
|
|
source += "/* esxVI_%s_DeepCopy */\n" % self.name
|
|
|
|
if self.extended_by is None:
|
|
source += "ESX_VI__TEMPLATE__DEEP_COPY(%s,\n" % self.name
|
|
else:
|
|
source += "ESX_VI__TEMPLATE__DYNAMIC_DEEP_COPY(%s,\n" % self.name
|
|
source += "{\n"
|
|
source += self.generate_dispatch('DEEP_COPY')
|
|
source += "},\n"
|
|
|
|
source += "{\n"
|
|
source += self.generate_deep_copy_code()
|
|
source += "})\n\n"
|
|
|
|
if self.features & Object.FEATURE__LIST:
|
|
source += "/* esxVI_%s_DeepCopyList */\n" % self.name
|
|
source += "ESX_VI__TEMPLATE__LIST__DEEP_COPY(%s)\n\n" \
|
|
% self.name
|
|
|
|
# cast from any type
|
|
if self.features & Object.FEATURE__ANY_TYPE:
|
|
source += "/* esxVI_%s_CastFromAnyType */\n" % self.name
|
|
|
|
if self.extended_by is None:
|
|
source += "ESX_VI__TEMPLATE__CAST_FROM_ANY_TYPE(%s)\n\n" \
|
|
% self.name
|
|
else:
|
|
source += "ESX_VI__TEMPLATE__DYNAMIC_CAST_FROM_ANY_TYPE(%s,\n" \
|
|
% self.name
|
|
source += "{\n"
|
|
source += self.generate_dispatch('CAST_FROM_ANY_TYPE')
|
|
source += "})\n\n"
|
|
|
|
if self.features & Object.FEATURE__LIST:
|
|
source += "/* esxVI_%s_CastListFromAnyType */\n" % self.name
|
|
source += "ESX_VI__TEMPLATE__LIST__CAST_FROM_ANY_TYPE(%s)\n\n" \
|
|
% self.name
|
|
|
|
# serialize
|
|
if self.features & Object.FEATURE__SERIALIZE:
|
|
source += "/* esxVI_%s_Serialize */\n" % self.name
|
|
|
|
if self.extended_by is None:
|
|
source += "ESX_VI__TEMPLATE__SERIALIZE(%s,\n" % self.name
|
|
else:
|
|
source += "ESX_VI__TEMPLATE__DYNAMIC_SERIALIZE(%s,\n" % self.name
|
|
source += "{\n"
|
|
source += self.generate_dispatch('SERIALIZE')
|
|
source += "},\n"
|
|
|
|
source += "{\n"
|
|
source += self.generate_serialize_code()
|
|
source += "})\n\n"
|
|
|
|
if self.features & Object.FEATURE__LIST:
|
|
source += "/* esxVI_%s_SerializeList */\n" % self.name
|
|
source += "ESX_VI__TEMPLATE__LIST__SERIALIZE(%s)\n\n" \
|
|
% self.name
|
|
|
|
# deserialize
|
|
if self.features & Object.FEATURE__DESERIALIZE:
|
|
source += "/* esxVI_%s_Deserialize */\n" % self.name
|
|
|
|
if self.extended_by is None:
|
|
source += "ESX_VI__TEMPLATE__DESERIALIZE(%s,\n" % self.name
|
|
else:
|
|
source += "ESX_VI__TEMPLATE__DYNAMIC_DESERIALIZE(%s,\n" \
|
|
% self.name
|
|
source += "{\n"
|
|
source += self.generate_dispatch('DESERIALIZE')
|
|
source += "},\n"
|
|
|
|
source += "{\n"
|
|
source += self.generate_deserialize_code()
|
|
source += "})\n\n"
|
|
|
|
if self.features & Object.FEATURE__LIST:
|
|
source += "/* esxVI_%s_DeserializeList */\n" % self.name
|
|
source += "ESX_VI__TEMPLATE__LIST__DESERIALIZE(%s)\n\n" \
|
|
% self.name
|
|
|
|
source += "\n\n"
|
|
|
|
return source
|
|
|
|
|
|
class ManagedObject(GenericObject):
|
|
def __init__(self, name, extends, properties, features=0, extended_by=None):
|
|
GenericObject.__init__(self, name, 'VI Managed Object', True,
|
|
managed_objects_by_name)
|
|
self.extends = extends
|
|
self.features = features
|
|
self.properties = properties
|
|
self.extended_by = extended_by
|
|
|
|
if self.extended_by is not None:
|
|
self.extended_by.sort()
|
|
|
|
def generate_lookup_code1(self, add_banner=False):
|
|
source = ""
|
|
|
|
if self.extends is not None:
|
|
obj = managed_objects_by_name[self.extends]
|
|
source += obj.generate_lookup_code1(add_banner=True) + "\n"
|
|
|
|
if self.extends is not None or add_banner:
|
|
source += " /* %s */\n" % self.name
|
|
|
|
if len(self.properties) < 1:
|
|
source += " /* no properties */\n"
|
|
else:
|
|
string = ""
|
|
|
|
for property in self.properties:
|
|
string += " \"%s\\0\"\n" % property.name
|
|
|
|
if len(string) < 1:
|
|
source += " /* no properties */\n"
|
|
else:
|
|
source += string
|
|
|
|
return source
|
|
|
|
def generate_lookup_code2(self, add_banner=False):
|
|
source = ""
|
|
|
|
if self.extends is not None:
|
|
obj = managed_objects_by_name[self.extends]
|
|
source += obj.generate_lookup_code2(add_banner=True) + "\n"
|
|
|
|
if self.extends is not None or add_banner:
|
|
source += " /* %s */\n" % self.name
|
|
|
|
if len(self.properties) < 1:
|
|
source += " /* no properties */\n"
|
|
else:
|
|
string = ""
|
|
|
|
for property in self.properties:
|
|
string += property.generate_lookup_code()
|
|
|
|
if len(string) < 1:
|
|
source += " /* no properties */\n"
|
|
else:
|
|
source += string
|
|
|
|
return source
|
|
|
|
def generate_header(self):
|
|
header = self.generate_comment()
|
|
|
|
# struct
|
|
header += "struct _esxVI_%s {\n" % self.name
|
|
|
|
if self.features & Object.FEATURE__LIST:
|
|
header += aligned(" esxVI_%s *_next; " % self.name,
|
|
"/* optional */\n")
|
|
else:
|
|
header += aligned(" esxVI_%s *_unused; " % self.name,
|
|
"/* optional */\n")
|
|
|
|
header += aligned(" esxVI_Type _type; ", "/* required */\n")
|
|
header += aligned(" esxVI_ManagedObjectReference *_reference; ",
|
|
"/* required */\n")
|
|
header += "\n"
|
|
header += self.generate_struct_members()
|
|
header += "};\n\n"
|
|
|
|
# functions
|
|
header += "int esxVI_%s_Alloc(esxVI_%s **item);\n" % (self.name, self.name)
|
|
header += "void esxVI_%s_Free(esxVI_%s **item);\n" % (self.name, self.name)
|
|
header += ("int esxVI_%s_Validate(esxVI_%s *item, "
|
|
" esxVI_String *selectedPropertyNameList);\n") \
|
|
% (self.name, self.name)
|
|
|
|
if self.features & Object.FEATURE__LIST:
|
|
header += "int esxVI_%s_AppendToList(esxVI_%s **list, esxVI_%s *item);\n" \
|
|
% (self.name, self.name, self.name)
|
|
|
|
header += "\n\n\n"
|
|
|
|
return header
|
|
|
|
def generate_helper_header(self):
|
|
# functions
|
|
return (
|
|
"int esxVI_Lookup%(name)s(esxVI_Context *ctx,"
|
|
" const char *name,"
|
|
" esxVI_ManagedObjectReference *root,"
|
|
" esxVI_String *selectedPropertyNameList,"
|
|
" esxVI_%(name)s **item,"
|
|
" esxVI_Occurrence occurrence);\n\n"
|
|
% {"name": self.name}
|
|
)
|
|
|
|
def generate_source(self):
|
|
source = self.generate_comment()
|
|
|
|
# functions
|
|
source += "/* esxVI_%s_Alloc */\n" % self.name
|
|
source += "ESX_VI__TEMPLATE__ALLOC(%s)\n\n" % self.name
|
|
|
|
# free
|
|
source += "/* esxVI_%s_Free */\n" % self.name
|
|
|
|
if self.extended_by is None:
|
|
source += "ESX_VI__TEMPLATE__FREE(%s,\n" % self.name
|
|
else:
|
|
source += "ESX_VI__TEMPLATE__DYNAMIC_FREE(%s,\n" % self.name
|
|
source += "{\n"
|
|
source += self.generate_dispatch('FREE')
|
|
source += "},\n"
|
|
|
|
source += "{\n"
|
|
|
|
if self.features & ManagedObject.FEATURE__LIST:
|
|
if self.extends is not None:
|
|
# avoid "dereferencing type-punned pointer will break
|
|
# strict-aliasing rules" warnings
|
|
source += " esxVI_%s *next = (esxVI_%s *)item->_next;\n\n" \
|
|
% (self.extends, self.extends)
|
|
source += " esxVI_%s_Free(&next);\n" % self.extends
|
|
source += " item->_next = (esxVI_%s *)next;\n\n" % self.name
|
|
else:
|
|
source += " esxVI_%s_Free(&item->_next);\n" % self.name
|
|
|
|
source += " esxVI_ManagedObjectReference_Free(&item->_reference);\n\n"
|
|
source += self.generate_free_code()
|
|
source += "})\n\n"
|
|
|
|
# validate
|
|
source += "/* esxVI_%s_Validate */\n" % self.name
|
|
source += "ESX_VI__TEMPLATE__MANAGED_VALIDATE(%s,\n" % self.name
|
|
source += "{\n"
|
|
|
|
source += self.generate_validate_code()
|
|
|
|
source += "})\n\n"
|
|
|
|
# append to list
|
|
if self.features & ManagedObject.FEATURE__LIST:
|
|
source += "/* esxVI_%s_AppendToList */\n" % self.name
|
|
source += "ESX_VI__TEMPLATE__LIST__APPEND(%s)\n\n" % self.name
|
|
|
|
source += "\n\n"
|
|
|
|
return source
|
|
|
|
def generate_helper_source(self):
|
|
# lookup
|
|
return (
|
|
"/* esxVI_Lookup%(name)s */\n"
|
|
"ESX_VI__TEMPLATE__LOOKUP(%(name)s,\n"
|
|
"{\n"
|
|
"%(lookup_code1)s},\n"
|
|
"{\n"
|
|
"%(lookup_code2)s})"
|
|
"\n\n\n\n"
|
|
% {"name": self.name,
|
|
"lookup_code1": self.generate_lookup_code1(),
|
|
"lookup_code2": self.generate_lookup_code2()}
|
|
)
|
|
|
|
|
|
class Enum(Type):
|
|
FEATURE__ANY_TYPE = (1 << 1)
|
|
FEATURE__SERIALIZE = (1 << 2)
|
|
FEATURE__DESERIALIZE = (1 << 3)
|
|
|
|
def __init__(self, name, values, features=0):
|
|
Type.__init__(self, "enum", name)
|
|
self.values = values
|
|
self.features = features
|
|
|
|
def generate_header(self):
|
|
header = separator
|
|
header += " * VI Enum: %s\n" % self.name
|
|
header += " */\n\n"
|
|
header += "enum _esxVI_%s {\n" % self.name
|
|
header += " esxVI_%s_Undefined = 0,\n" % self.name
|
|
|
|
for value in self.values:
|
|
header += " esxVI_%s_%s,\n" % (self.name, capitalize_first(value))
|
|
|
|
header += "};\n\n"
|
|
|
|
# functions
|
|
if self.features & Enum.FEATURE__ANY_TYPE:
|
|
header += ("int esxVI_%s_CastFromAnyType(esxVI_AnyType *anyType, "
|
|
" esxVI_%s *item);\n") \
|
|
% (self.name, self.name)
|
|
|
|
if self.features & Enum.FEATURE__SERIALIZE:
|
|
header += ("int esxVI_%s_Serialize(esxVI_%s item, const char *element, "
|
|
" virBufferPtr output);\n") \
|
|
% (self.name, self.name)
|
|
|
|
if self.features & Enum.FEATURE__DESERIALIZE:
|
|
header += ("int esxVI_%s_Deserialize(xmlNodePtr node, "
|
|
" esxVI_%s *item);\n") \
|
|
% (self.name, self.name)
|
|
|
|
header += "\n\n\n"
|
|
|
|
return header
|
|
|
|
def generate_source(self):
|
|
source = separator
|
|
source += " * VI Enum: %s\n" % self.name
|
|
source += " */\n\n"
|
|
source += "static const esxVI_Enumeration _esxVI_%s_Enumeration = {\n" \
|
|
% self.name
|
|
source += " esxVI_Type_%s, {\n" % self.name
|
|
|
|
for value in self.values:
|
|
source += " { \"%s\", esxVI_%s_%s },\n" \
|
|
% (value, self.name, capitalize_first(value))
|
|
|
|
source += " { NULL, -1 },\n"
|
|
source += " },\n"
|
|
source += "};\n\n"
|
|
|
|
# functions
|
|
if self.features & Enum.FEATURE__ANY_TYPE:
|
|
source += "/* esxVI_%s_CastFromAnyType */\n" % self.name
|
|
source += "ESX_VI__TEMPLATE__ENUMERATION__CAST_FROM_ANY_TYPE(%s)\n\n" \
|
|
% self.name
|
|
|
|
if self.features & Enum.FEATURE__SERIALIZE:
|
|
source += "/* esxVI_%s_Serialize */\n" % self.name
|
|
source += "ESX_VI__TEMPLATE__ENUMERATION__SERIALIZE(%s)\n\n" \
|
|
% self.name
|
|
|
|
if self.features & Enum.FEATURE__DESERIALIZE:
|
|
source += "/* esxVI_%s_Deserialize */\n" % self.name
|
|
source += "ESX_VI__TEMPLATE__ENUMERATION__DESERIALIZE(%s)\n\n" \
|
|
% self.name
|
|
|
|
source += "\n\n"
|
|
|
|
return source
|
|
|
|
|
|
def report_error(message):
|
|
print("error: " + message)
|
|
sys.exit(1)
|
|
|
|
|
|
def capitalize_first(string):
|
|
return string[:1].upper() + string[1:]
|
|
|
|
|
|
def parse_object(block):
|
|
# expected format: [managed] object <name> [extends <name>]
|
|
header_items = block[0][1].split()
|
|
managed = False
|
|
|
|
if header_items[0] == "managed":
|
|
managed = True
|
|
del header_items[0]
|
|
|
|
if len(header_items) < 2:
|
|
report_error("line %d: invalid block header" % (number))
|
|
|
|
assert header_items[0] == "object"
|
|
|
|
name = header_items[1]
|
|
extends = None
|
|
|
|
if len(header_items) > 2:
|
|
if header_items[2] != "extends":
|
|
report_error("line %d: invalid block header" % (number))
|
|
else:
|
|
extends = header_items[3]
|
|
|
|
properties = []
|
|
|
|
for line in block[1:]:
|
|
# expected format: <type> <name> <occurrence>
|
|
items = line[1].split()
|
|
|
|
if len(items) != 3:
|
|
report_error("line %d: invalid property" % line[0])
|
|
|
|
if items[2] not in valid_occurrences:
|
|
report_error("line %d: invalid occurrence" % line[0])
|
|
|
|
properties.append(Property(type=items[0], name=items[1],
|
|
occurrence=items[2]))
|
|
|
|
if managed:
|
|
return ManagedObject(name=name, extends=extends, properties=properties)
|
|
else:
|
|
return Object(name=name, extends=extends, properties=properties)
|
|
|
|
|
|
def parse_enum(block):
|
|
# expected format: enum <name>
|
|
header_items = block[0][1].split()
|
|
|
|
if len(header_items) < 2:
|
|
report_error("line %d: invalid block header" % (number))
|
|
|
|
assert header_items[0] == "enum"
|
|
|
|
name = header_items[1]
|
|
|
|
values = []
|
|
|
|
for line in block[1:]:
|
|
# expected format: <value>
|
|
values.append(line[1])
|
|
|
|
return Enum(name=name, values=values)
|
|
|
|
|
|
def parse_method(block):
|
|
# expected format: method <name> [returns <type> <occurrence>]
|
|
header_items = block[0][1].split()
|
|
|
|
if len(header_items) < 2:
|
|
report_error("line %d: invalid block header" % (number))
|
|
|
|
assert header_items[0] == "method"
|
|
|
|
name = header_items[1]
|
|
returns = None
|
|
|
|
if len(header_items) > 2:
|
|
if header_items[2] != "returns":
|
|
report_error("line %d: invalid block header" % (number))
|
|
else:
|
|
returns = Parameter(type=header_items[3], name="output",
|
|
occurrence=header_items[4])
|
|
|
|
parameters = []
|
|
|
|
for line in block[1:]:
|
|
# expected format: <type> <name> <occurrence>
|
|
items = line[1].split()
|
|
|
|
if len(items) != 3:
|
|
report_error("line %d: invalid property" % line[0])
|
|
|
|
if items[2] not in valid_occurrences:
|
|
report_error("line %d: invalid occurrence" % line[0])
|
|
|
|
parameters.append(Parameter(type=items[0], name=items[1],
|
|
occurrence=items[2]))
|
|
|
|
return Method(name=name, parameters=parameters, returns=returns)
|
|
|
|
|
|
def is_known_type(type):
|
|
return (type in predefined_objects or
|
|
type in predefined_enums or
|
|
type in objects_by_name or
|
|
type in managed_objects_by_name or
|
|
type in enums_by_name)
|
|
|
|
|
|
def get_base_class(obj):
|
|
if not obj.extends:
|
|
return None
|
|
base_class = None
|
|
try:
|
|
base_class = base_class_by_name[obj.extends]
|
|
except KeyError:
|
|
parent = objects_by_name[obj.extends]
|
|
base_class = get_base_class(parent)
|
|
if not base_class:
|
|
base_class = parent.name
|
|
base_class_by_name[name] = base_class
|
|
return base_class
|
|
|
|
|
|
def open_file(filename):
|
|
return open(filename, "wt")
|
|
|
|
|
|
predefined_enums = ["Boolean"]
|
|
|
|
predefined_objects = ["AnyType",
|
|
"Byte",
|
|
"Int",
|
|
"Long",
|
|
"String",
|
|
"DateTime",
|
|
"MethodFault",
|
|
"ManagedObjectReference"]
|
|
|
|
additional_enum_features = {
|
|
"ManagedEntityStatus": Enum.FEATURE__ANY_TYPE,
|
|
"TaskInfoState": Enum.FEATURE__ANY_TYPE,
|
|
"VirtualMachinePowerState": Enum.FEATURE__ANY_TYPE
|
|
}
|
|
|
|
additional_object_features = {
|
|
"AutoStartDefaults": Object.FEATURE__ANY_TYPE,
|
|
"AutoStartPowerInfo": Object.FEATURE__ANY_TYPE,
|
|
"DatastoreHostMount": (Object.FEATURE__DEEP_COPY | Object.FEATURE__LIST |
|
|
Object.FEATURE__ANY_TYPE),
|
|
"DatastoreInfo": Object.FEATURE__ANY_TYPE | Object.FEATURE__DYNAMIC_CAST,
|
|
"GuestNicInfo": Object.FEATURE__LIST | Object.FEATURE__ANY_TYPE,
|
|
"HostConfigManager": Object.FEATURE__ANY_TYPE,
|
|
"HostCpuIdInfo": Object.FEATURE__LIST | Object.FEATURE__ANY_TYPE,
|
|
"HostDatastoreBrowserSearchResults": (Object.FEATURE__LIST |
|
|
Object.FEATURE__ANY_TYPE),
|
|
"HostHostBusAdapter": Object.FEATURE__LIST | Object.FEATURE__ANY_TYPE,
|
|
"HostInternetScsiHba": (Object.FEATURE__DYNAMIC_CAST |
|
|
Object.FEATURE__DEEP_COPY),
|
|
"HostInternetScsiTargetTransport": Object.FEATURE__DYNAMIC_CAST,
|
|
"HostScsiDisk": (Object.FEATURE__LIST | Object.FEATURE__ANY_TYPE |
|
|
Object.FEATURE__DYNAMIC_CAST),
|
|
"HostScsiTopologyInterface": (Object.FEATURE__LIST |
|
|
Object.FEATURE__ANY_TYPE),
|
|
"HostScsiTopologyLun": (Object.FEATURE__ANY_TYPE | Object.FEATURE__LIST |
|
|
Object.FEATURE__DEEP_COPY),
|
|
"HostScsiTopologyTarget": Object.FEATURE__ANY_TYPE | Object.FEATURE__LIST,
|
|
"HostPortGroup": Object.FEATURE__LIST | Object.FEATURE__ANY_TYPE,
|
|
"HostVirtualSwitch": (Object.FEATURE__DEEP_COPY | Object.FEATURE__LIST |
|
|
Object.FEATURE__ANY_TYPE),
|
|
"ManagedObjectReference": Object.FEATURE__ANY_TYPE,
|
|
"ObjectContent": Object.FEATURE__DEEP_COPY,
|
|
"PhysicalNic": (Object.FEATURE__DEEP_COPY | Object.FEATURE__LIST |
|
|
Object.FEATURE__ANY_TYPE),
|
|
"ResourcePoolResourceUsage": Object.FEATURE__ANY_TYPE,
|
|
"ScsiLun": (Object.FEATURE__LIST | Object.FEATURE__ANY_TYPE |
|
|
Object.FEATURE__DEEP_COPY),
|
|
"ScsiLunDurableName": Object.FEATURE__LIST,
|
|
"ServiceContent": Object.FEATURE__DESERIALIZE,
|
|
"SharesInfo": Object.FEATURE__ANY_TYPE,
|
|
"TaskInfo": Object.FEATURE__LIST | Object.FEATURE__ANY_TYPE,
|
|
"UserSession": Object.FEATURE__ANY_TYPE,
|
|
"VirtualMachineQuestionInfo": Object.FEATURE__ANY_TYPE,
|
|
"VirtualMachineSnapshotTree": (Object.FEATURE__DEEP_COPY |
|
|
Object.FEATURE__ANY_TYPE),
|
|
"VmEventArgument": Object.FEATURE__DESERIALIZE
|
|
}
|
|
|
|
removed_object_features = {}
|
|
|
|
if len(sys.argv) != 4:
|
|
report_error("usage: %s srcdir builddir header" % sys.argv[0])
|
|
|
|
input_filename = os.path.join(sys.argv[1], "esx/esx_vi_generator.input")
|
|
output_dirname = os.path.join(sys.argv[2], "esx")
|
|
header = sys.argv[3] == "header"
|
|
|
|
|
|
if header:
|
|
types_typedef = open_file(os.path.join(output_dirname, "esx_vi_types.generated.typedef"))
|
|
types_typeenum = open_file(os.path.join(output_dirname, "esx_vi_types.generated.typeenum"))
|
|
types_header = open_file(os.path.join(output_dirname, "esx_vi_types.generated.h"))
|
|
methods_header = open_file(os.path.join(output_dirname, "esx_vi_methods.generated.h"))
|
|
helpers_header = open_file(os.path.join(output_dirname, "esx_vi.generated.h"))
|
|
else:
|
|
types_typetostring = open_file(os.path.join(output_dirname, "esx_vi_types.generated.typetostring"))
|
|
types_typefromstring = open_file(os.path.join(output_dirname, "esx_vi_types.generated.typefromstring"))
|
|
types_source = open_file(os.path.join(output_dirname, "esx_vi_types.generated.c"))
|
|
methods_macro = open_file(os.path.join(output_dirname, "esx_vi_methods.generated.macro"))
|
|
methods_source = open_file(os.path.join(output_dirname, "esx_vi_methods.generated.c"))
|
|
helpers_source = open_file(os.path.join(output_dirname, "esx_vi.generated.c"))
|
|
|
|
|
|
number = 0
|
|
objects_by_name = {}
|
|
managed_objects_by_name = {}
|
|
enums_by_name = {}
|
|
methods_by_name = {}
|
|
block = None
|
|
base_class_by_name = {}
|
|
|
|
|
|
# parse input file
|
|
for line in open(input_filename, "rt").readlines():
|
|
number += 1
|
|
|
|
if "#" in line:
|
|
line = line[:line.index("#")]
|
|
|
|
line = line.lstrip().rstrip()
|
|
|
|
if len(line) < 1:
|
|
continue
|
|
|
|
if line.startswith("object") or line.startswith("managed object") or \
|
|
line.startswith("enum") or line.startswith("method"):
|
|
if block is not None:
|
|
report_error("line %d: nested block found" % (number))
|
|
else:
|
|
block = []
|
|
|
|
if block is not None:
|
|
if line == "end":
|
|
if block[0][1].startswith("object"):
|
|
obj = parse_object(block)
|
|
objects_by_name[obj.name] = obj
|
|
elif block[0][1].startswith("managed object"):
|
|
obj = parse_object(block)
|
|
managed_objects_by_name[obj.name] = obj
|
|
elif block[0][1].startswith("enum"):
|
|
enum = parse_enum(block)
|
|
enums_by_name[enum.name] = enum
|
|
else:
|
|
method = parse_method(block)
|
|
methods_by_name[method.name] = method
|
|
|
|
block = None
|
|
else:
|
|
block.append((number, line))
|
|
|
|
|
|
for method in methods_by_name.values():
|
|
# method parameter types must be serializable
|
|
for parameter in method.parameters:
|
|
if not parameter.is_type_generated():
|
|
continue
|
|
|
|
if parameter.is_enum():
|
|
enums_by_name[parameter.type].features |= Enum.FEATURE__SERIALIZE
|
|
else:
|
|
objects_by_name[parameter.type].features |= Object.FEATURE__SERIALIZE
|
|
objects_by_name[parameter.type].candidate_for_dynamic_cast = True
|
|
|
|
# detect list usage
|
|
if parameter.occurrence == OCCURRENCE__REQUIRED_LIST or \
|
|
parameter.occurrence == OCCURRENCE__OPTIONAL_LIST:
|
|
if parameter.is_enum():
|
|
report_error("unsupported usage of enum '%s' as list in '%s'"
|
|
% (parameter.type, method.name))
|
|
else:
|
|
objects_by_name[parameter.type].features |= Object.FEATURE__LIST
|
|
|
|
# method return types must be deserializable
|
|
if method.returns and method.returns.is_type_generated():
|
|
if method.returns.is_enum():
|
|
enums_by_name[method.returns.type].features |= Enum.FEATURE__DESERIALIZE
|
|
else:
|
|
objects_by_name[method.returns.type].features |= Object.FEATURE__DESERIALIZE
|
|
objects_by_name[method.returns.type].candidate_for_dynamic_cast = True
|
|
|
|
# detect list usage
|
|
if method.returns.occurrence == OCCURRENCE__REQUIRED_LIST or \
|
|
method.returns.occurrence == OCCURRENCE__OPTIONAL_LIST:
|
|
if method.returns.is_enum():
|
|
report_error("unsupported usage of enum '%s' as list in '%s'"
|
|
% (method.returns.type, method.name))
|
|
else:
|
|
objects_by_name[method.returns.type].features |= Object.FEATURE__LIST
|
|
|
|
|
|
for enum in enums_by_name.values():
|
|
# apply additional features
|
|
if enum.name in additional_enum_features:
|
|
enum.features |= additional_enum_features[enum.name]
|
|
|
|
if additional_enum_features[enum.name] & Enum.FEATURE__ANY_TYPE:
|
|
enum.features |= Enum.FEATURE__DESERIALIZE
|
|
|
|
|
|
for obj in objects_by_name.values():
|
|
for property in obj.properties:
|
|
if property.occurrence != OCCURRENCE__IGNORED and \
|
|
not is_known_type(property.type):
|
|
report_error("object '%s' contains unknown property type '%s'"
|
|
% (obj.name, property.type))
|
|
|
|
if obj.extends is not None:
|
|
if not is_known_type(obj.extends):
|
|
report_error("object '%s' extends unknown object '%s'"
|
|
% (obj.name, obj.extends))
|
|
|
|
for property in obj.properties:
|
|
if not property.is_type_generated():
|
|
continue
|
|
|
|
if property.is_enum():
|
|
enums_by_name[property.type].candidate_for_dynamic_cast = True
|
|
else:
|
|
objects_by_name[property.type].candidate_for_dynamic_cast = True
|
|
|
|
# detect list usage
|
|
if property.occurrence == OCCURRENCE__REQUIRED_LIST or \
|
|
property.occurrence == OCCURRENCE__OPTIONAL_LIST:
|
|
if property.is_enum():
|
|
report_error("unsupported usage of enum '%s' as list in '%s'"
|
|
% (property.type, obj.type))
|
|
else:
|
|
objects_by_name[property.type].features |= Object.FEATURE__LIST
|
|
|
|
# apply/remove additional features
|
|
if obj.name in additional_object_features:
|
|
obj.features |= additional_object_features[obj.name]
|
|
|
|
if additional_object_features[obj.name] & Object.FEATURE__ANY_TYPE:
|
|
obj.features |= Object.FEATURE__DESERIALIZE
|
|
|
|
if obj.name in removed_object_features:
|
|
obj.features &= ~removed_object_features[obj.name]
|
|
|
|
# detect extended_by relation
|
|
if obj.extends is not None:
|
|
extended_obj = objects_by_name[obj.extends]
|
|
|
|
if extended_obj.extended_by is None:
|
|
extended_obj.extended_by = [obj.name]
|
|
else:
|
|
extended_obj.extended_by.append(obj.name)
|
|
extended_obj.extended_by.sort()
|
|
|
|
|
|
for obj in objects_by_name.values():
|
|
# if an object is a candidate (it is used directly as parameter or return
|
|
# type or is a member of another object) and it is extended by another
|
|
# object then this type needs the dynamic cast feature
|
|
if obj.candidate_for_dynamic_cast and obj.extended_by:
|
|
obj.features |= Object.FEATURE__DYNAMIC_CAST
|
|
|
|
|
|
def propagate_feature(obj, feature):
|
|
global features_have_changed
|
|
|
|
if not (obj.features & feature):
|
|
return
|
|
|
|
for property in obj.properties:
|
|
if (property.occurrence == OCCURRENCE__IGNORED or
|
|
not property.is_type_generated()):
|
|
continue
|
|
|
|
if property.is_enum():
|
|
if (feature == Object.FEATURE__SERIALIZE and
|
|
not (enums_by_name[property.type].features &
|
|
Enum.FEATURE__SERIALIZE)):
|
|
enums_by_name[property.type].features |= Enum.FEATURE__SERIALIZE
|
|
features_have_changed = True
|
|
elif (feature == Object.FEATURE__DESERIALIZE and
|
|
not (enums_by_name[property.type].features &
|
|
Enum.FEATURE__DESERIALIZE)):
|
|
enums_by_name[property.type].features |= Enum.FEATURE__DESERIALIZE
|
|
features_have_changed = True
|
|
elif property.is_object():
|
|
if not (objects_by_name[property.type].features & feature):
|
|
objects_by_name[property.type].features |= feature
|
|
features_have_changed = True
|
|
|
|
if obj.name != property.type:
|
|
propagate_feature(objects_by_name[property.type], feature)
|
|
|
|
|
|
def inherit_features(obj):
|
|
global features_have_changed
|
|
|
|
if obj.extended_by is not None:
|
|
for extended_by in obj.extended_by:
|
|
previous = objects_by_name[extended_by].features
|
|
objects_by_name[extended_by].features |= obj.features
|
|
|
|
if objects_by_name[extended_by].features != previous:
|
|
features_have_changed = True
|
|
|
|
if obj.extends is not None:
|
|
previous = objects_by_name[obj.extends].features
|
|
objects_by_name[obj.extends].features |= obj.features
|
|
|
|
if objects_by_name[obj.extends].features != previous:
|
|
features_have_changed = True
|
|
|
|
if obj.extended_by is not None:
|
|
for extended_by in obj.extended_by:
|
|
inherit_features(objects_by_name[extended_by])
|
|
|
|
|
|
# there are two directions to spread features:
|
|
# 1) up and down the inheritance chain
|
|
# 2) from object types to their member property types
|
|
# spreading needs to be done alternating on both directions because they can
|
|
# affect each other
|
|
features_have_changed = True
|
|
|
|
while features_have_changed:
|
|
features_have_changed = False
|
|
|
|
for obj in objects_by_name.values():
|
|
propagate_feature(obj, Object.FEATURE__DEEP_COPY)
|
|
propagate_feature(obj, Object.FEATURE__SERIALIZE)
|
|
propagate_feature(obj, Object.FEATURE__DESERIALIZE)
|
|
|
|
for obj in objects_by_name.values():
|
|
inherit_features(obj)
|
|
|
|
|
|
for obj in managed_objects_by_name.values():
|
|
for property in obj.properties:
|
|
if property.occurrence != OCCURRENCE__IGNORED and \
|
|
not is_known_type(property.type):
|
|
report_error("object '%s' contains unknown property type '%s'"
|
|
% (obj.name, property.type))
|
|
|
|
if obj.extends is not None:
|
|
if not is_known_type(obj.extends):
|
|
report_error("object '%s' extends unknown object '%s'"
|
|
% (obj.name, obj.extends))
|
|
|
|
# detect extended_by relation
|
|
if obj.extends is not None:
|
|
extended_obj = managed_objects_by_name[obj.extends]
|
|
|
|
if extended_obj.extended_by is None:
|
|
extended_obj.extended_by = [obj.name]
|
|
else:
|
|
extended_obj.extended_by.append(obj.name)
|
|
extended_obj.extended_by.sort()
|
|
|
|
|
|
notice = "/* Generated by esx_vi_generator.py */\n\n\n\n"
|
|
|
|
if (header):
|
|
types_typedef.write(notice)
|
|
types_typeenum.write(notice)
|
|
types_header.write(notice)
|
|
methods_header.write(notice)
|
|
helpers_header.write(notice)
|
|
else:
|
|
types_typetostring.write(notice)
|
|
types_typefromstring.write(notice)
|
|
types_source.write(notice)
|
|
methods_macro.write(notice)
|
|
methods_source.write(notice)
|
|
helpers_source.write(notice)
|
|
|
|
|
|
# output enums
|
|
if header:
|
|
types_typedef.write(separator +
|
|
" * VI Enums\n" +
|
|
" */\n\n")
|
|
|
|
names = sorted(enums_by_name.keys())
|
|
|
|
for name in names:
|
|
if header:
|
|
types_typedef.write(enums_by_name[name].generate_typedef())
|
|
types_typeenum.write(enums_by_name[name].generate_typeenum())
|
|
types_header.write(enums_by_name[name].generate_header())
|
|
else:
|
|
types_typetostring.write(enums_by_name[name].generate_typetostring())
|
|
types_typefromstring.write(enums_by_name[name].generate_typefromstring())
|
|
types_source.write(enums_by_name[name].generate_source())
|
|
|
|
|
|
# output objects
|
|
if header:
|
|
types_typedef.write("\n\n\n" +
|
|
separator +
|
|
" * VI Objects\n" +
|
|
" */\n\n")
|
|
types_typeenum.write("\n")
|
|
else:
|
|
types_typetostring.write("\n")
|
|
types_typefromstring.write("\n")
|
|
|
|
names = sorted(objects_by_name.keys())
|
|
|
|
for name in names:
|
|
if header:
|
|
types_typedef.write(objects_by_name[name].generate_typedef())
|
|
types_typeenum.write(objects_by_name[name].generate_typeenum())
|
|
types_header.write(objects_by_name[name].generate_header())
|
|
else:
|
|
types_typetostring.write(objects_by_name[name].generate_typetostring())
|
|
types_typefromstring.write(objects_by_name[name].generate_typefromstring())
|
|
types_source.write(objects_by_name[name].generate_source())
|
|
|
|
|
|
# output managed objects
|
|
if header:
|
|
types_typedef.write("\n\n\n" +
|
|
separator +
|
|
" * VI Managed Objects\n" +
|
|
" */\n\n")
|
|
types_typeenum.write("\n")
|
|
else:
|
|
types_typetostring.write("\n")
|
|
types_typefromstring.write("\n")
|
|
|
|
names = sorted(managed_objects_by_name.keys())
|
|
|
|
for name in names:
|
|
if header:
|
|
types_typedef.write(managed_objects_by_name[name].generate_typedef())
|
|
types_typeenum.write(managed_objects_by_name[name].generate_typeenum())
|
|
types_header.write(managed_objects_by_name[name].generate_header())
|
|
else:
|
|
types_typetostring.write(managed_objects_by_name[name].generate_typetostring())
|
|
types_typefromstring.write(managed_objects_by_name[name].generate_typefromstring())
|
|
types_source.write(managed_objects_by_name[name].generate_source())
|
|
|
|
|
|
# output methods
|
|
names = sorted(methods_by_name.keys())
|
|
|
|
for name in names:
|
|
if header:
|
|
methods_header.write(methods_by_name[name].generate_header())
|
|
else:
|
|
methods_source.write(methods_by_name[name].generate_source())
|
|
|
|
if not header:
|
|
names = list(autobind_names)
|
|
names.sort()
|
|
|
|
for name in names:
|
|
string = aligned("#define ESX_VI__METHOD__PARAMETER__THIS__%s " % name, "\\\n", 78)
|
|
string += " ESX_VI__METHOD__PARAMETER__THIS_FROM_SERVICE(ManagedObjectReference, \\\n"
|
|
string += aligned("", "%s)\n\n\n\n" % name, 49)
|
|
|
|
methods_macro.write(string)
|
|
|
|
|
|
# output helpers
|
|
names = sorted(managed_objects_by_name.keys())
|
|
|
|
for name in names:
|
|
if header:
|
|
helpers_header.write(managed_objects_by_name[name].generate_helper_header())
|
|
else:
|
|
helpers_source.write(managed_objects_by_name[name].generate_helper_source())
|