diff options
author | Daniel P. Berrangé <berrange@redhat.com> | 2019-10-08 11:19:30 +0100 |
---|---|---|
committer | Daniel P. Berrangé <berrange@redhat.com> | 2019-12-04 11:42:16 +0000 |
commit | 74f270095a017b0e46657df305d042d9e8617f8a (patch) | |
tree | da2229ff7d7519298dd6cf05bd27c751c9e37712 /scripts | |
parent | 4de5d01a4ee76e6ea31dc61025e26459473d1104 (diff) | |
download | libvirt-74f270095a017b0e46657df305d042d9e8617f8a.tar.gz |
docs: move esx_vi_generator.py to the scripts/ directory
Reviewed-by: Cole Robinson <crobinso@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Diffstat (limited to 'scripts')
-rwxr-xr-x | scripts/esx_vi_generator.py | 1689 |
1 files changed, 1689 insertions, 0 deletions
diff --git a/scripts/esx_vi_generator.py b/scripts/esx_vi_generator.py new file mode 100755 index 0000000000..2f685c0898 --- /dev/null +++ b/scripts/esx_vi_generator.py @@ -0,0 +1,1689 @@ +#!/usr/bin/env python + +# +# 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/>. +# + +from __future__ import print_function + +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: + 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\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 open_and_print(filename): + if filename.startswith("./"): + print(" GEN " + filename[2:]) + else: + print(" GEN " + 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, + "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) != 3: + report_error("usage: %s srcdir builddir" % 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") + + +types_typedef = open_and_print(os.path.join(output_dirname, "esx_vi_types.generated.typedef")) +types_typeenum = open_and_print(os.path.join(output_dirname, "esx_vi_types.generated.typeenum")) +types_typetostring = open_and_print(os.path.join(output_dirname, "esx_vi_types.generated.typetostring")) +types_typefromstring = open_and_print(os.path.join(output_dirname, "esx_vi_types.generated.typefromstring")) +types_header = open_and_print(os.path.join(output_dirname, "esx_vi_types.generated.h")) +types_source = open_and_print(os.path.join(output_dirname, "esx_vi_types.generated.c")) +methods_header = open_and_print(os.path.join(output_dirname, "esx_vi_methods.generated.h")) +methods_source = open_and_print(os.path.join(output_dirname, "esx_vi_methods.generated.c")) +methods_macro = open_and_print(os.path.join(output_dirname, "esx_vi_methods.generated.macro")) +helpers_header = open_and_print(os.path.join(output_dirname, "esx_vi.generated.h")) +helpers_source = open_and_print(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 + + +# 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" + +types_typedef.write(notice) +types_typeenum.write(notice) +types_typetostring.write(notice) +types_typefromstring.write(notice) +types_header.write(notice) +types_source.write(notice) +methods_header.write(notice) +methods_source.write(notice) +methods_macro.write(notice) +helpers_header.write(notice) +helpers_source.write(notice) + + +# output enums +types_typedef.write(separator + + " * VI Enums\n" + + " */\n\n") + +names = sorted(enums_by_name.keys()) + +for name in names: + types_typedef.write(enums_by_name[name].generate_typedef()) + types_typeenum.write(enums_by_name[name].generate_typeenum()) + types_typetostring.write(enums_by_name[name].generate_typetostring()) + types_typefromstring.write(enums_by_name[name].generate_typefromstring()) + types_header.write(enums_by_name[name].generate_header()) + types_source.write(enums_by_name[name].generate_source()) + + +# output objects +types_typedef.write("\n\n\n" + + separator + + " * VI Objects\n" + + " */\n\n") +types_typeenum.write("\n") +types_typetostring.write("\n") +types_typefromstring.write("\n") + +names = sorted(objects_by_name.keys()) + +for name in names: + types_typedef.write(objects_by_name[name].generate_typedef()) + types_typeenum.write(objects_by_name[name].generate_typeenum()) + types_typetostring.write(objects_by_name[name].generate_typetostring()) + types_typefromstring.write(objects_by_name[name].generate_typefromstring()) + types_header.write(objects_by_name[name].generate_header()) + types_source.write(objects_by_name[name].generate_source()) + + +# output managed objects +types_typedef.write("\n\n\n" + + separator + + " * VI Managed Objects\n" + + " */\n\n") +types_typeenum.write("\n") +types_typetostring.write("\n") +types_typefromstring.write("\n") + +names = sorted(managed_objects_by_name.keys()) + +for name in names: + types_typedef.write(managed_objects_by_name[name].generate_typedef()) + types_typeenum.write(managed_objects_by_name[name].generate_typeenum()) + types_typetostring.write(managed_objects_by_name[name].generate_typetostring()) + types_typefromstring.write(managed_objects_by_name[name].generate_typefromstring()) + types_header.write(managed_objects_by_name[name].generate_header()) + types_source.write(managed_objects_by_name[name].generate_source()) + + +# output methods +names = sorted(methods_by_name.keys()) + +for name in names: + methods_header.write(methods_by_name[name].generate_header()) + methods_source.write(methods_by_name[name].generate_source()) + +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: + helpers_header.write(managed_objects_by_name[name].generate_helper_header()) + helpers_source.write(managed_objects_by_name[name].generate_helper_source()) |