2019-12-04 00:29:12 +08:00
|
|
|
#!/usr/bin/env python3
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
#
|
|
|
|
# esx_vi_generator.py: generates most of the SOAP type mapping code
|
|
|
|
#
|
2014-09-04 03:39:21 +08:00
|
|
|
# Copyright (C) 2014 Red Hat, Inc.
|
2012-08-05 01:48:50 +08:00
|
|
|
# Copyright (C) 2010-2012 Matthias Bolte <matthias.bolte@googlemail.com>
|
2013-01-02 14:22:28 +08:00
|
|
|
# Copyright (C) 2013 Ata E Husain Bohra <ata.husain@hotmail.com>
|
2010-03-07 00:56:28 +08:00
|
|
|
#
|
|
|
|
# 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
|
2012-09-21 06:30:55 +08:00
|
|
|
# License along with this library. If not, see
|
2012-07-27 06:58:02 +08:00
|
|
|
# <http://www.gnu.org/licenses/>.
|
2010-03-07 00:56:28 +08:00
|
|
|
#
|
|
|
|
|
|
|
|
import sys
|
|
|
|
import os
|
|
|
|
import os.path
|
|
|
|
|
|
|
|
|
2010-04-13 20:25:52 +08:00
|
|
|
OCCURRENCE__REQUIRED_ITEM = "r"
|
|
|
|
OCCURRENCE__REQUIRED_LIST = "rl"
|
|
|
|
OCCURRENCE__OPTIONAL_ITEM = "o"
|
|
|
|
OCCURRENCE__OPTIONAL_LIST = "ol"
|
|
|
|
OCCURRENCE__IGNORED = "i"
|
2010-03-07 00:56:28 +08:00
|
|
|
|
2010-04-13 20:25:52 +08:00
|
|
|
valid_occurrences = [OCCURRENCE__REQUIRED_ITEM,
|
|
|
|
OCCURRENCE__REQUIRED_LIST,
|
|
|
|
OCCURRENCE__OPTIONAL_ITEM,
|
|
|
|
OCCURRENCE__OPTIONAL_LIST,
|
|
|
|
OCCURRENCE__IGNORED]
|
2010-03-07 00:56:28 +08:00
|
|
|
|
2011-05-01 17:51:19 +08:00
|
|
|
autobind_names = set()
|
2011-05-01 14:05:58 +08:00
|
|
|
|
2011-05-02 03:57:42 +08:00
|
|
|
separator = "/* " + ("* " * 37) + "*\n"
|
|
|
|
|
2010-04-13 20:25:52 +08:00
|
|
|
|
2011-05-01 14:05:58 +08:00
|
|
|
def aligned(left, right, length=59):
|
2018-03-20 14:48:51 +08:00
|
|
|
return left.ljust(length, ' ') + right
|
2010-04-13 20:25:52 +08:00
|
|
|
|
|
|
|
|
2011-05-01 17:29:40 +08:00
|
|
|
class Member:
|
|
|
|
def __init__(self, type, occurrence):
|
2010-04-13 20:25:52 +08:00
|
|
|
self.type = type
|
|
|
|
self.occurrence = occurrence
|
|
|
|
|
|
|
|
def is_enum(self):
|
|
|
|
return self.type in predefined_enums or self.type in enums_by_name
|
|
|
|
|
2011-05-01 16:43:17 +08:00
|
|
|
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
|
|
|
|
|
2011-05-01 17:29:40 +08:00
|
|
|
def get_occurrence_comment(self):
|
2018-03-20 14:48:50 +08:00
|
|
|
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)
|
|
|
|
|
2011-05-01 17:29:40 +08:00
|
|
|
|
|
|
|
class Parameter(Member):
|
|
|
|
def __init__(self, type, name, occurrence):
|
|
|
|
Member.__init__(self, type, occurrence)
|
|
|
|
|
|
|
|
if ':' in name and name.startswith("_this"):
|
2011-05-01 17:51:19 +08:00
|
|
|
self.name, self.autobind_name = name.split(":")
|
2011-05-01 17:29:40 +08:00
|
|
|
else:
|
|
|
|
self.name = name
|
2011-05-01 17:51:19 +08:00
|
|
|
self.autobind_name = None
|
2011-05-01 17:29:40 +08:00
|
|
|
|
2011-05-02 03:57:42 +08:00
|
|
|
def generate_parameter(self, is_last=False, is_header=True, offset=0):
|
2010-04-13 20:25:52 +08:00
|
|
|
if self.occurrence == OCCURRENCE__IGNORED:
|
2011-05-02 03:57:42 +08:00
|
|
|
raise ValueError("invalid function parameter occurrence value '%s'"
|
|
|
|
% self.occurrence)
|
2011-05-01 17:51:19 +08:00
|
|
|
elif self.autobind_name is not None:
|
2010-04-13 20:25:52 +08:00
|
|
|
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 += ", "
|
|
|
|
|
2011-04-10 19:26:47 +08:00
|
|
|
return aligned(string, self.get_occurrence_comment() + "\n")
|
2010-04-13 20:25:52 +08:00
|
|
|
|
2018-03-20 14:48:54 +08:00
|
|
|
def generate_return(self, offset=0, end_of_line=";"):
|
2010-04-13 20:25:52 +08:00
|
|
|
if self.occurrence == OCCURRENCE__IGNORED:
|
2011-05-02 03:57:42 +08:00
|
|
|
raise ValueError("invalid function parameter occurrence value '%s'"
|
|
|
|
% self.occurrence)
|
2010-04-13 20:25:52 +08:00
|
|
|
else:
|
|
|
|
string = " "
|
|
|
|
string += " " * offset
|
2011-05-02 03:57:42 +08:00
|
|
|
string += "%s%s)%s" \
|
|
|
|
% (self.get_type_string(True), self.name, end_of_line)
|
2010-04-13 20:25:52 +08:00
|
|
|
|
2011-04-10 19:26:47 +08:00
|
|
|
return aligned(string, self.get_occurrence_comment() + "\n")
|
2010-04-13 20:25:52 +08:00
|
|
|
|
|
|
|
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]:
|
2011-05-02 03:57:42 +08:00
|
|
|
return " ESX_VI__METHOD__PARAMETER__SERIALIZE_LIST(%s, %s)\n" \
|
|
|
|
% (self.type, self.name)
|
2010-04-13 20:25:52 +08:00
|
|
|
elif self.type == "String":
|
2011-05-02 03:57:42 +08:00
|
|
|
return " ESX_VI__METHOD__PARAMETER__SERIALIZE_VALUE(String, %s)\n" \
|
|
|
|
% self.name
|
2010-04-13 20:25:52 +08:00
|
|
|
else:
|
2011-05-02 03:57:42 +08:00
|
|
|
return " ESX_VI__METHOD__PARAMETER__SERIALIZE(%s, %s)\n" \
|
|
|
|
% (self.type, self.name)
|
2010-04-13 20:25:52 +08:00
|
|
|
|
2011-05-01 17:29:40 +08:00
|
|
|
def get_type_string(self, as_return_value=False):
|
2010-08-30 01:17:10 +08:00
|
|
|
string = ""
|
|
|
|
|
2010-04-13 20:25:52 +08:00
|
|
|
if self.type == "String" and \
|
|
|
|
self.occurrence not in [OCCURRENCE__REQUIRED_LIST,
|
|
|
|
OCCURRENCE__OPTIONAL_LIST]:
|
2010-08-30 01:17:10 +08:00
|
|
|
if as_return_value:
|
|
|
|
string += "char *"
|
|
|
|
else:
|
|
|
|
string += "const char *"
|
2010-04-13 20:25:52 +08:00
|
|
|
elif self.is_enum():
|
2010-08-30 01:17:10 +08:00
|
|
|
string += "esxVI_%s " % self.type
|
2010-04-13 20:25:52 +08:00
|
|
|
else:
|
2010-08-30 01:17:10 +08:00
|
|
|
string += "esxVI_%s *" % self.type
|
|
|
|
|
|
|
|
if as_return_value:
|
|
|
|
string += "*"
|
|
|
|
|
|
|
|
return string
|
2010-04-13 20:25:52 +08:00
|
|
|
|
|
|
|
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:
|
2011-05-01 17:51:19 +08:00
|
|
|
if parameter.autobind_name is None:
|
2010-04-13 20:25:52 +08:00
|
|
|
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:
|
2011-05-02 03:57:42 +08:00
|
|
|
header += self.parameters[-1].generate_parameter(is_last=True)
|
2010-04-13 20:25:52 +08:00
|
|
|
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:
|
2011-05-01 17:51:19 +08:00
|
|
|
autobind_names.add(self.autobind_parameter.autobind_name)
|
|
|
|
source += " %s,\n" % self.autobind_parameter.autobind_name
|
2010-04-13 20:25:52 +08:00
|
|
|
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]:
|
2011-05-02 03:57:42 +08:00
|
|
|
source += parameter.generate_parameter(is_header=False,
|
|
|
|
offset=9)
|
2010-04-13 20:25:52 +08:00
|
|
|
|
|
|
|
if self.returns is None:
|
2011-05-02 03:57:42 +08:00
|
|
|
source += self.parameters[-1].generate_parameter(is_last=True,
|
|
|
|
is_header=False,
|
|
|
|
offset=9)
|
2010-04-13 20:25:52 +08:00
|
|
|
else:
|
2011-05-02 03:57:42 +08:00
|
|
|
source += self.parameters[-1].generate_parameter(is_header=False,
|
|
|
|
offset=9)
|
|
|
|
source += self.returns.generate_return(offset=9,
|
|
|
|
end_of_line=",")
|
2010-04-13 20:25:52 +08:00
|
|
|
else:
|
|
|
|
source += "),\n"
|
|
|
|
|
|
|
|
if self.returns is None:
|
2010-08-30 01:17:10 +08:00
|
|
|
source += " void, /* nothing */, None,\n"
|
|
|
|
elif self.returns.type == "String":
|
2011-05-02 03:57:42 +08:00
|
|
|
source += " String, Value, %s,\n" \
|
|
|
|
% self.returns.get_occurrence_short_enum()
|
2010-04-13 20:25:52 +08:00
|
|
|
else:
|
2011-05-02 03:57:42 +08:00
|
|
|
source += " %s, /* nothing */, %s,\n" \
|
|
|
|
% (self.returns.type,
|
|
|
|
self.returns.get_occurrence_short_enum())
|
2010-04-13 20:25:52 +08:00
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
2011-05-01 17:29:40 +08:00
|
|
|
class Property(Member):
|
2010-03-07 00:56:28 +08:00
|
|
|
def __init__(self, type, name, occurrence):
|
2011-05-01 17:29:40 +08:00
|
|
|
Member.__init__(self, type, occurrence)
|
2011-05-01 16:43:17 +08:00
|
|
|
|
2011-05-01 17:29:40 +08:00
|
|
|
self.name = name
|
2011-05-01 16:43:17 +08:00
|
|
|
|
2010-03-07 00:56:28 +08:00
|
|
|
def generate_struct_member(self):
|
2010-04-13 20:25:52 +08:00
|
|
|
if self.occurrence == OCCURRENCE__IGNORED:
|
2010-03-07 00:56:28 +08:00
|
|
|
return " /* FIXME: %s is currently ignored */\n" % self.name
|
|
|
|
else:
|
|
|
|
string = " %s%s; " % (self.get_type_string(), self.name)
|
|
|
|
|
2011-04-10 19:26:47 +08:00
|
|
|
return aligned(string, self.get_occurrence_comment() + "\n")
|
2010-04-13 20:25:52 +08:00
|
|
|
|
2010-03-07 00:56:28 +08:00
|
|
|
def generate_free_code(self):
|
|
|
|
if self.type == "String" and \
|
2010-04-13 20:25:52 +08:00
|
|
|
self.occurrence not in [OCCURRENCE__REQUIRED_LIST,
|
|
|
|
OCCURRENCE__OPTIONAL_LIST,
|
|
|
|
OCCURRENCE__IGNORED]:
|
2010-03-07 00:56:28 +08:00
|
|
|
return " VIR_FREE(item->%s);\n" % self.name
|
|
|
|
elif self.is_enum():
|
|
|
|
return ""
|
|
|
|
else:
|
2010-04-13 20:25:52 +08:00
|
|
|
if self.occurrence == OCCURRENCE__IGNORED:
|
2010-03-07 00:56:28 +08:00
|
|
|
return " /* FIXME: %s is currently ignored */\n" % self.name
|
|
|
|
else:
|
|
|
|
return " esxVI_%s_Free(&item->%s);\n" % (self.type, self.name)
|
|
|
|
|
2011-04-10 19:27:56 +08:00
|
|
|
def generate_validate_code(self, managed=False):
|
|
|
|
if managed:
|
|
|
|
macro = "ESX_VI__TEMPLATE__PROPERTY__MANAGED_REQUIRE"
|
|
|
|
else:
|
|
|
|
macro = "ESX_VI__TEMPLATE__PROPERTY__REQUIRE"
|
|
|
|
|
2010-04-13 20:25:52 +08:00
|
|
|
if self.occurrence in [OCCURRENCE__REQUIRED_ITEM,
|
|
|
|
OCCURRENCE__REQUIRED_LIST]:
|
2011-04-10 19:27:56 +08:00
|
|
|
return " %s(%s)\n" % (macro, self.name)
|
2010-04-13 20:25:52 +08:00
|
|
|
elif self.occurrence == OCCURRENCE__IGNORED:
|
2010-03-07 00:56:28 +08:00
|
|
|
return " /* FIXME: %s is currently ignored */\n" % self.name
|
|
|
|
else:
|
|
|
|
return ""
|
|
|
|
|
|
|
|
def generate_deep_copy_code(self):
|
2010-04-13 20:25:52 +08:00
|
|
|
if self.occurrence == OCCURRENCE__IGNORED:
|
2010-03-07 00:56:28 +08:00
|
|
|
return " /* FIXME: %s is currently ignored */\n" % self.name
|
2010-04-13 20:25:52 +08:00
|
|
|
elif self.occurrence in [OCCURRENCE__REQUIRED_LIST,
|
|
|
|
OCCURRENCE__OPTIONAL_LIST]:
|
2011-05-02 03:57:42 +08:00
|
|
|
return " ESX_VI__TEMPLATE__PROPERTY__DEEP_COPY_LIST(%s, %s)\n" \
|
|
|
|
% (self.type, self.name)
|
2010-03-07 00:56:28 +08:00
|
|
|
elif self.type == "String":
|
2011-05-02 03:57:42 +08:00
|
|
|
return " ESX_VI__TEMPLATE__PROPERTY__DEEP_COPY_VALUE(String, %s)\n" \
|
|
|
|
% self.name
|
2010-04-07 17:23:53 +08:00
|
|
|
elif self.is_enum():
|
|
|
|
return " (*dest)->%s = src->%s;\n" % (self.name, self.name)
|
2010-03-07 00:56:28 +08:00
|
|
|
else:
|
2011-05-02 03:57:42 +08:00
|
|
|
return " ESX_VI__TEMPLATE__PROPERTY__DEEP_COPY(%s, %s)\n" \
|
|
|
|
% (self.type, self.name)
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
def generate_serialize_code(self):
|
2010-04-13 20:25:52 +08:00
|
|
|
if self.occurrence == OCCURRENCE__IGNORED:
|
2010-03-07 00:56:28 +08:00
|
|
|
return " /* FIXME: %s is currently ignored */\n" % self.name
|
2010-04-13 20:25:52 +08:00
|
|
|
elif self.occurrence in [OCCURRENCE__REQUIRED_LIST,
|
|
|
|
OCCURRENCE__OPTIONAL_LIST]:
|
2011-05-02 03:57:42 +08:00
|
|
|
return " ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_LIST(%s, %s)\n" \
|
|
|
|
% (self.type, self.name)
|
2010-03-07 00:56:28 +08:00
|
|
|
elif self.type == "String":
|
2011-05-02 03:57:42 +08:00
|
|
|
return " ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_VALUE(String, %s)\n" \
|
|
|
|
% self.name
|
2010-03-07 00:56:28 +08:00
|
|
|
else:
|
2011-05-02 03:57:42 +08:00
|
|
|
return " ESX_VI__TEMPLATE__PROPERTY__SERIALIZE(%s, %s)\n" \
|
|
|
|
% (self.type, self.name)
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
def generate_deserialize_code(self):
|
2010-04-13 20:25:52 +08:00
|
|
|
if self.occurrence == OCCURRENCE__IGNORED:
|
2011-05-02 03:57:42 +08:00
|
|
|
return " ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_IGNORE(%s) /* FIXME */\n" \
|
|
|
|
% self.name
|
2010-04-13 20:25:52 +08:00
|
|
|
elif self.occurrence in [OCCURRENCE__REQUIRED_LIST,
|
|
|
|
OCCURRENCE__OPTIONAL_LIST]:
|
2011-05-02 03:57:42 +08:00
|
|
|
return " ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_LIST(%s, %s)\n" \
|
|
|
|
% (self.type, self.name)
|
2010-03-07 00:56:28 +08:00
|
|
|
elif self.type == "String":
|
2011-05-02 03:57:42 +08:00
|
|
|
return " ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, %s)\n" \
|
|
|
|
% self.name
|
2010-03-07 00:56:28 +08:00
|
|
|
else:
|
2011-05-02 03:57:42 +08:00
|
|
|
return " ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(%s, %s)\n" \
|
|
|
|
% (self.type, self.name)
|
2010-03-07 00:56:28 +08:00
|
|
|
|
2011-04-10 19:27:56 +08:00
|
|
|
def generate_lookup_code(self):
|
|
|
|
if self.occurrence == OCCURRENCE__IGNORED:
|
2011-05-02 03:57:42 +08:00
|
|
|
return " ESX_VI__TEMPLATE__PROPERTY__CAST_FROM_ANY_TYPE_IGNORE(%s) /* FIXME */\n" \
|
|
|
|
% self.name
|
2011-04-10 19:27:56 +08:00
|
|
|
elif self.occurrence in [OCCURRENCE__REQUIRED_LIST,
|
|
|
|
OCCURRENCE__OPTIONAL_LIST]:
|
2011-05-02 03:57:42 +08:00
|
|
|
return " ESX_VI__TEMPLATE__PROPERTY__CAST_LIST_FROM_ANY_TYPE(%s, %s)\n" \
|
|
|
|
% (self.type, self.name)
|
2011-04-10 19:27:56 +08:00
|
|
|
elif self.type == "String":
|
2011-05-02 03:57:42 +08:00
|
|
|
return " ESX_VI__TEMPLATE__PROPERTY__CAST_VALUE_FROM_ANY_TYPE(String, %s)\n" \
|
|
|
|
% self.name
|
2011-04-10 19:27:56 +08:00
|
|
|
else:
|
2011-05-02 03:57:42 +08:00
|
|
|
return " ESX_VI__TEMPLATE__PROPERTY__CAST_FROM_ANY_TYPE(%s, %s)\n" \
|
|
|
|
% (self.type, self.name)
|
2011-04-10 19:27:56 +08:00
|
|
|
|
2010-03-07 00:56:28 +08:00
|
|
|
def get_type_string(self):
|
|
|
|
if self.type == "String" and \
|
2010-04-13 20:25:52 +08:00
|
|
|
self.occurrence not in [OCCURRENCE__REQUIRED_LIST,
|
|
|
|
OCCURRENCE__OPTIONAL_LIST]:
|
2010-03-07 00:56:28 +08:00
|
|
|
return "char *"
|
|
|
|
elif self.is_enum():
|
|
|
|
return "esxVI_%s " % self.type
|
|
|
|
else:
|
|
|
|
return "esxVI_%s *" % self.type
|
|
|
|
|
|
|
|
|
2011-05-01 17:29:40 +08:00
|
|
|
class Type:
|
2011-04-10 19:26:47 +08:00
|
|
|
def __init__(self, kind, name):
|
|
|
|
self.kind = kind
|
|
|
|
self.name = name
|
|
|
|
|
|
|
|
def generate_typedef(self):
|
2011-05-02 03:57:42 +08:00
|
|
|
return "typedef %s _esxVI_%s esxVI_%s;\n" \
|
|
|
|
% (self.kind, self.name, self.name)
|
2011-04-10 19:26:47 +08:00
|
|
|
|
|
|
|
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):
|
2019-09-24 23:47:02 +08:00
|
|
|
string = " if (STREQ(type, \"%s\"))\n" % self.name
|
2011-04-10 19:26:47 +08:00
|
|
|
string += " return esxVI_Type_%s;\n" % self.name
|
|
|
|
|
|
|
|
return string
|
|
|
|
|
|
|
|
|
2013-05-01 21:54:30 +08:00
|
|
|
class GenericObject(Type):
|
2010-03-07 00:56:28 +08:00
|
|
|
FEATURE__DYNAMIC_CAST = (1 << 1)
|
2019-09-24 23:47:02 +08:00
|
|
|
FEATURE__LIST = (1 << 2)
|
|
|
|
FEATURE__DEEP_COPY = (1 << 3)
|
|
|
|
FEATURE__ANY_TYPE = (1 << 4)
|
|
|
|
FEATURE__SERIALIZE = (1 << 5)
|
|
|
|
FEATURE__DESERIALIZE = (1 << 6)
|
2010-03-07 00:56:28 +08:00
|
|
|
|
2013-05-01 21:54:30 +08:00
|
|
|
def __init__(self, name, category, managed, generic_objects_by_name):
|
2011-05-01 17:29:40 +08:00
|
|
|
Type.__init__(self, "struct", name)
|
2013-05-01 21:54:30 +08:00
|
|
|
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
|
2010-03-07 00:56:28 +08:00
|
|
|
|
2010-05-19 00:11:59 +08:00
|
|
|
if self.extended_by is not None:
|
2013-05-01 21:54:30 +08:00
|
|
|
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
|
2010-05-19 00:11:59 +08:00
|
|
|
|
2011-04-10 19:26:47 +08:00
|
|
|
def generate_struct_members(self, add_banner=False, struct_gap=False):
|
2010-03-07 00:56:28 +08:00
|
|
|
members = ""
|
|
|
|
|
2011-04-10 19:26:47 +08:00
|
|
|
if struct_gap:
|
2010-03-07 00:56:28 +08:00
|
|
|
members += "\n"
|
|
|
|
|
|
|
|
if self.extends is not None:
|
2019-09-25 00:26:29 +08:00
|
|
|
obj = self.generic_objects_by_name[self.extends]
|
|
|
|
members += obj.generate_struct_members(add_banner=True,
|
|
|
|
struct_gap=False) + "\n"
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2012-10-07 00:30:45 +08:00
|
|
|
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:
|
2019-09-25 00:26:29 +08:00
|
|
|
obj = self.generic_objects_by_name[extended_by]
|
|
|
|
source += obj.generate_dispatch(suffix, False)
|
2012-10-07 00:30:45 +08:00
|
|
|
|
|
|
|
return source
|
|
|
|
|
2011-04-10 19:26:47 +08:00
|
|
|
def generate_free_code(self, add_banner=False):
|
2010-03-07 00:56:28 +08:00
|
|
|
source = ""
|
|
|
|
|
|
|
|
if self.extends is not None:
|
2019-09-25 00:26:29 +08:00
|
|
|
obj = self.generic_objects_by_name[self.extends]
|
|
|
|
source += obj.generate_free_code(add_banner=True) + "\n"
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2011-04-10 19:26:47 +08:00
|
|
|
def generate_validate_code(self, add_banner=False):
|
2010-03-07 00:56:28 +08:00
|
|
|
source = ""
|
|
|
|
|
|
|
|
if self.extends is not None:
|
2019-09-25 00:26:29 +08:00
|
|
|
obj = self.generic_objects_by_name[self.extends]
|
|
|
|
source += obj.generate_validate_code(add_banner=True) + "\n"
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
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:
|
2013-05-01 21:54:30 +08:00
|
|
|
string += property.generate_validate_code(self.managed)
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
if len(string) < 1:
|
|
|
|
source += " /* no required properties */\n"
|
|
|
|
else:
|
|
|
|
source += string
|
|
|
|
|
|
|
|
return source
|
|
|
|
|
2010-04-13 20:25:52 +08:00
|
|
|
|
2013-05-01 21:54:30 +08:00
|
|
|
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()
|
|
|
|
|
2011-05-02 03:57:42 +08:00
|
|
|
def generate_dynamic_cast_code(self, is_first=True):
|
2010-03-07 00:56:28 +08:00
|
|
|
source = ""
|
|
|
|
|
|
|
|
if self.extended_by is not None:
|
2010-07-06 23:27:05 +08:00
|
|
|
if not is_first:
|
|
|
|
source += "\n"
|
|
|
|
|
2010-03-07 00:56:28 +08:00
|
|
|
source += " /* %s */\n" % self.name
|
|
|
|
|
|
|
|
for extended_by in self.extended_by:
|
2011-05-02 03:57:42 +08:00
|
|
|
source += " ESX_VI__TEMPLATE__DYNAMIC_CAST__ACCEPT(%s)\n" \
|
|
|
|
% extended_by
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
for extended_by in self.extended_by:
|
2019-09-25 00:26:29 +08:00
|
|
|
obj = objects_by_name[extended_by]
|
|
|
|
source += obj.generate_dynamic_cast_code(False)
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
return source
|
|
|
|
|
2018-03-20 14:48:54 +08:00
|
|
|
def generate_deep_copy_code(self, add_banner=False):
|
2010-03-07 00:56:28 +08:00
|
|
|
source = ""
|
|
|
|
|
|
|
|
if self.extends is not None:
|
2019-09-25 00:26:29 +08:00
|
|
|
obj = objects_by_name[self.extends]
|
|
|
|
source += obj.generate_deep_copy_code(add_banner=True) + "\n"
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2011-05-02 03:57:42 +08:00
|
|
|
def generate_serialize_code(self, add_banner=False):
|
2010-03-07 00:56:28 +08:00
|
|
|
source = ""
|
|
|
|
|
|
|
|
if self.extends is not None:
|
2019-09-25 00:26:29 +08:00
|
|
|
obj = objects_by_name[self.extends]
|
|
|
|
source += obj.generate_serialize_code(add_banner=True) + "\n"
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2011-05-02 03:57:42 +08:00
|
|
|
def generate_deserialize_code(self, add_banner=False):
|
2010-03-07 00:56:28 +08:00
|
|
|
source = ""
|
|
|
|
|
|
|
|
if self.extends is not None:
|
2019-09-25 00:26:29 +08:00
|
|
|
obj = objects_by_name[self.extends]
|
|
|
|
source += obj.generate_deserialize_code(add_banner=True) + "\n"
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
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):
|
2013-05-01 21:54:30 +08:00
|
|
|
header = self.generate_comment()
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
# struct
|
|
|
|
header += "struct _esxVI_%s {\n" % self.name
|
|
|
|
|
|
|
|
if self.features & Object.FEATURE__LIST:
|
2011-05-02 03:57:42 +08:00
|
|
|
header += aligned(" esxVI_%s *_next; " % self.name,
|
|
|
|
"/* optional */\n")
|
2010-03-07 00:56:28 +08:00
|
|
|
else:
|
2011-05-02 03:57:42 +08:00
|
|
|
header += aligned(" esxVI_%s *_unused; " % self.name,
|
|
|
|
"/* optional */\n")
|
2010-03-07 00:56:28 +08:00
|
|
|
|
2011-04-10 19:26:47 +08:00
|
|
|
header += aligned(" esxVI_Type _type; ", "/* required */\n")
|
|
|
|
header += self.generate_struct_members(struct_gap=True)
|
2010-03-07 00:56:28 +08:00
|
|
|
header += "};\n\n"
|
|
|
|
|
|
|
|
# functions
|
2011-05-02 03:57:42 +08:00
|
|
|
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)
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
if self.features & Object.FEATURE__DYNAMIC_CAST:
|
|
|
|
if self.extended_by is not None or self.extends is not None:
|
2011-05-02 03:57:42 +08:00
|
|
|
header += "esxVI_%s *esxVI_%s_DynamicCast(void *item);\n" \
|
|
|
|
% (self.name, self.name)
|
2010-03-07 00:56:28 +08:00
|
|
|
else:
|
|
|
|
report_error("cannot add dynamic cast support for an untyped object")
|
|
|
|
|
|
|
|
if self.features & Object.FEATURE__LIST:
|
2011-05-02 03:57:42 +08:00
|
|
|
header += "int esxVI_%s_AppendToList(esxVI_%s **list, esxVI_%s *item);\n" \
|
|
|
|
% (self.name, self.name, self.name)
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
if self.features & Object.FEATURE__DEEP_COPY:
|
2011-05-02 03:57:42 +08:00
|
|
|
header += "int esxVI_%s_DeepCopy(esxVI_%s **dst, esxVI_%s *src);\n" \
|
|
|
|
% (self.name, self.name, self.name)
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
if self.features & Object.FEATURE__LIST:
|
2019-09-25 00:26:29 +08:00
|
|
|
header += ((
|
|
|
|
"int esxVI_%s_DeepCopyList(esxVI_%s **dstList, "
|
|
|
|
" esxVI_%s *srcList);\n") %
|
|
|
|
(self.name, self.name, self.name))
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
if self.features & Object.FEATURE__ANY_TYPE:
|
2019-09-25 00:26:29 +08:00
|
|
|
header += ((
|
|
|
|
"int esxVI_%s_CastFromAnyType(esxVI_AnyType *anyType, "
|
|
|
|
" esxVI_%s **item);\n") %
|
|
|
|
(self.name, self.name))
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
if self.features & Object.FEATURE__LIST:
|
2019-09-25 00:26:29 +08:00
|
|
|
header += ((
|
|
|
|
"int esxVI_%s_CastListFromAnyType(esxVI_AnyType *anyType, "
|
|
|
|
" esxVI_%s **list);\n") %
|
|
|
|
(self.name, self.name))
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
if self.features & Object.FEATURE__SERIALIZE:
|
2019-09-25 00:26:29 +08:00
|
|
|
header += ((
|
|
|
|
"int esxVI_%s_Serialize(esxVI_%s *item, "
|
|
|
|
" const char *element, "
|
2021-03-11 15:16:13 +08:00
|
|
|
" virBuffer *output);\n") %
|
2019-09-25 00:26:29 +08:00
|
|
|
(self.name, self.name))
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
if self.features & Object.FEATURE__LIST:
|
2019-09-25 00:26:29 +08:00
|
|
|
header += ((
|
|
|
|
"int esxVI_%s_SerializeList(esxVI_%s *list, "
|
|
|
|
" const char *element, "
|
2021-03-11 15:16:13 +08:00
|
|
|
" virBuffer *output);\n") %
|
2019-09-25 00:26:29 +08:00
|
|
|
(self.name, self.name))
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
if self.features & Object.FEATURE__DESERIALIZE:
|
2011-05-02 03:57:42 +08:00
|
|
|
header += "int esxVI_%s_Deserialize(xmlNodePtr node, esxVI_%s **item);\n" \
|
|
|
|
% (self.name, self.name)
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
if self.features & Object.FEATURE__LIST:
|
2019-09-25 00:26:29 +08:00
|
|
|
header += ((
|
|
|
|
"int esxVI_%s_DeserializeList(xmlNodePtr node, "
|
|
|
|
" esxVI_%s **list);\n") %
|
|
|
|
(self.name, self.name))
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
header += "\n\n\n"
|
|
|
|
|
|
|
|
return header
|
|
|
|
|
|
|
|
def generate_source(self):
|
2011-05-02 03:57:42 +08:00
|
|
|
source = separator
|
2011-04-10 19:27:56 +08:00
|
|
|
source += " * VI Object: %s\n" % self.name
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
if self.extends is not None:
|
2011-04-10 19:27:56 +08:00
|
|
|
source += " * extends %s\n" % self.extends
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
first = True
|
|
|
|
|
|
|
|
if self.extended_by is not None:
|
|
|
|
for extended_by in self.extended_by:
|
|
|
|
if first:
|
2011-04-10 19:27:56 +08:00
|
|
|
source += " * extended by %s\n" % extended_by
|
2010-03-07 00:56:28 +08:00
|
|
|
first = False
|
|
|
|
else:
|
2011-04-10 19:27:56 +08:00
|
|
|
source += " * %s\n" % extended_by
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
source += " */\n\n"
|
|
|
|
|
|
|
|
# functions
|
|
|
|
source += "/* esxVI_%s_Alloc */\n" % self.name
|
|
|
|
source += "ESX_VI__TEMPLATE__ALLOC(%s)\n\n" % self.name
|
|
|
|
|
|
|
|
# free
|
2013-05-01 21:54:30 +08:00
|
|
|
source += "/* esxVI_%s_Free */\n" % self.name
|
|
|
|
|
2010-03-07 00:56:28 +08:00
|
|
|
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"
|
2013-01-02 14:22:28 +08:00
|
|
|
source += self.generate_dispatch('FREE')
|
2010-03-07 00:56:28 +08:00
|
|
|
source += "},\n"
|
|
|
|
|
2013-05-01 21:54:30 +08:00
|
|
|
source += "{\n"
|
2010-03-07 00:56:28 +08:00
|
|
|
|
2013-05-01 21:54:30 +08:00
|
|
|
if self.features & Object.FEATURE__LIST:
|
esx: generator: fix free of elements in lists
When a list is freed, we iterate through all the items, invoking the
free function for each; the actual free function called for each element
is the function of the actual type of each element, and thus the @_next
pointer in the element struct has the same type as the element itself.
Currently, the free function gets the parent of the current element
type, and invoke its free function to continue freeing the list.
However, in case the hierarchy of the classes has more than 1 level
(i.e. Class <- SubClass <- SubSubClass), the invoked free function is
only the parent class' one, and not the actual base class of the
hierarchy.
To fix that, change the generator to get the base class of a class, and
invoking that instead. Also, avoid to set the @_next back, as it is not
needed.
Fixes commits 5cff36e39ae691fbd7c40597df1732eecf294150 and
f76c6dde2e33233566e886d96e76b5fe0c102d9a.
Signed-off-by: Pino Toscano <ptoscano@redhat.com>
Reviewed-by: Martin Kletzander <mkletzan@redhat.com>
2020-09-10 21:08:24 +08:00
|
|
|
base_class = get_base_class(self)
|
|
|
|
if base_class:
|
2013-05-01 21:54:30 +08:00
|
|
|
# avoid "dereferencing type-punned pointer will break
|
|
|
|
# strict-aliasing rules" warnings
|
esx: generator: fix free of elements in lists
When a list is freed, we iterate through all the items, invoking the
free function for each; the actual free function called for each element
is the function of the actual type of each element, and thus the @_next
pointer in the element struct has the same type as the element itself.
Currently, the free function gets the parent of the current element
type, and invoke its free function to continue freeing the list.
However, in case the hierarchy of the classes has more than 1 level
(i.e. Class <- SubClass <- SubSubClass), the invoked free function is
only the parent class' one, and not the actual base class of the
hierarchy.
To fix that, change the generator to get the base class of a class, and
invoking that instead. Also, avoid to set the @_next back, as it is not
needed.
Fixes commits 5cff36e39ae691fbd7c40597df1732eecf294150 and
f76c6dde2e33233566e886d96e76b5fe0c102d9a.
Signed-off-by: Pino Toscano <ptoscano@redhat.com>
Reviewed-by: Martin Kletzander <mkletzan@redhat.com>
2020-09-10 21:08:24 +08:00
|
|
|
source += " esxVI_%s *baseNext = (esxVI_%s *)item->_next;\n" \
|
|
|
|
% (base_class, base_class)
|
|
|
|
source += " esxVI_%s_Free(&baseNext);\n\n" % base_class
|
2013-05-01 21:54:30 +08:00
|
|
|
else:
|
|
|
|
source += " esxVI_%s_Free(&item->_next);\n\n" % self.name
|
2010-03-07 00:56:28 +08:00
|
|
|
|
2013-05-01 21:54:30 +08:00
|
|
|
source += self.generate_free_code()
|
|
|
|
source += "})\n\n"
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
# 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
|
2013-05-01 21:54:30 +08:00
|
|
|
if self.features & Object.FEATURE__DEEP_COPY:
|
|
|
|
source += "/* esxVI_%s_DeepCopy */\n" % self.name
|
2010-03-07 00:56:28 +08:00
|
|
|
|
2013-05-01 21:54:30 +08:00
|
|
|
if self.extended_by is None:
|
|
|
|
source += "ESX_VI__TEMPLATE__DEEP_COPY(%s,\n" % self.name
|
|
|
|
else:
|
2012-07-19 14:14:18 +08:00
|
|
|
source += "ESX_VI__TEMPLATE__DYNAMIC_DEEP_COPY(%s,\n" % self.name
|
2010-03-07 00:56:28 +08:00
|
|
|
source += "{\n"
|
2012-10-07 00:30:45 +08:00
|
|
|
source += self.generate_dispatch('DEEP_COPY')
|
2010-03-07 00:56:28 +08:00
|
|
|
source += "},\n"
|
|
|
|
|
2013-05-01 21:54:30 +08:00
|
|
|
source += "{\n"
|
|
|
|
source += self.generate_deep_copy_code()
|
|
|
|
source += "})\n\n"
|
2010-03-07 00:56:28 +08:00
|
|
|
|
2013-05-01 21:54:30 +08:00
|
|
|
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
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
# cast from any type
|
|
|
|
if self.features & Object.FEATURE__ANY_TYPE:
|
|
|
|
source += "/* esxVI_%s_CastFromAnyType */\n" % self.name
|
2010-05-18 23:53:12 +08:00
|
|
|
|
|
|
|
if self.extended_by is None:
|
2011-05-02 03:57:42 +08:00
|
|
|
source += "ESX_VI__TEMPLATE__CAST_FROM_ANY_TYPE(%s)\n\n" \
|
|
|
|
% self.name
|
2010-05-18 23:53:12 +08:00
|
|
|
else:
|
2011-05-02 03:57:42 +08:00
|
|
|
source += "ESX_VI__TEMPLATE__DYNAMIC_CAST_FROM_ANY_TYPE(%s,\n" \
|
|
|
|
% self.name
|
2010-05-18 23:53:12 +08:00
|
|
|
source += "{\n"
|
2012-10-07 00:30:45 +08:00
|
|
|
source += self.generate_dispatch('CAST_FROM_ANY_TYPE')
|
2010-05-18 23:53:12 +08:00
|
|
|
source += "})\n\n"
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
if self.features & Object.FEATURE__LIST:
|
|
|
|
source += "/* esxVI_%s_CastListFromAnyType */\n" % self.name
|
2011-05-02 03:57:42 +08:00
|
|
|
source += "ESX_VI__TEMPLATE__LIST__CAST_FROM_ANY_TYPE(%s)\n\n" \
|
|
|
|
% self.name
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
# serialize
|
2013-05-01 21:54:30 +08:00
|
|
|
if self.features & Object.FEATURE__SERIALIZE:
|
|
|
|
source += "/* esxVI_%s_Serialize */\n" % self.name
|
2010-03-07 00:56:28 +08:00
|
|
|
|
2013-05-01 21:54:30 +08:00
|
|
|
if self.extended_by is None:
|
|
|
|
source += "ESX_VI__TEMPLATE__SERIALIZE(%s,\n" % self.name
|
|
|
|
else:
|
2010-03-07 00:56:28 +08:00
|
|
|
source += "ESX_VI__TEMPLATE__DYNAMIC_SERIALIZE(%s,\n" % self.name
|
|
|
|
source += "{\n"
|
2012-10-07 00:30:45 +08:00
|
|
|
source += self.generate_dispatch('SERIALIZE')
|
2010-03-07 00:56:28 +08:00
|
|
|
source += "},\n"
|
|
|
|
|
2013-05-01 21:54:30 +08:00
|
|
|
source += "{\n"
|
|
|
|
source += self.generate_serialize_code()
|
|
|
|
source += "})\n\n"
|
2010-03-07 00:56:28 +08:00
|
|
|
|
2013-05-01 21:54:30 +08:00
|
|
|
if self.features & Object.FEATURE__LIST:
|
|
|
|
source += "/* esxVI_%s_SerializeList */\n" % self.name
|
|
|
|
source += "ESX_VI__TEMPLATE__LIST__SERIALIZE(%s)\n\n" \
|
|
|
|
% self.name
|
2010-03-07 00:56:28 +08:00
|
|
|
|
2011-05-02 03:57:42 +08:00
|
|
|
# deserialize
|
2013-05-01 21:54:30 +08:00
|
|
|
if self.features & Object.FEATURE__DESERIALIZE:
|
|
|
|
source += "/* esxVI_%s_Deserialize */\n" % self.name
|
2010-03-07 00:56:28 +08:00
|
|
|
|
2013-05-01 21:54:30 +08:00
|
|
|
if self.extended_by is None:
|
|
|
|
source += "ESX_VI__TEMPLATE__DESERIALIZE(%s,\n" % self.name
|
|
|
|
else:
|
2011-05-02 03:57:42 +08:00
|
|
|
source += "ESX_VI__TEMPLATE__DYNAMIC_DESERIALIZE(%s,\n" \
|
|
|
|
% self.name
|
2010-07-06 23:27:05 +08:00
|
|
|
source += "{\n"
|
2012-10-07 00:30:45 +08:00
|
|
|
source += self.generate_dispatch('DESERIALIZE')
|
2010-07-06 23:27:05 +08:00
|
|
|
source += "},\n"
|
|
|
|
|
2013-05-01 21:54:30 +08:00
|
|
|
source += "{\n"
|
|
|
|
source += self.generate_deserialize_code()
|
|
|
|
source += "})\n\n"
|
2010-07-06 23:27:05 +08:00
|
|
|
|
2013-05-01 21:54:30 +08:00
|
|
|
if self.features & Object.FEATURE__LIST:
|
|
|
|
source += "/* esxVI_%s_DeserializeList */\n" % self.name
|
|
|
|
source += "ESX_VI__TEMPLATE__LIST__DESERIALIZE(%s)\n\n" \
|
|
|
|
% self.name
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
source += "\n\n"
|
|
|
|
|
|
|
|
return source
|
|
|
|
|
|
|
|
|
2013-05-01 21:54:30 +08:00
|
|
|
class ManagedObject(GenericObject):
|
2011-04-10 19:27:56 +08:00
|
|
|
def __init__(self, name, extends, properties, features=0, extended_by=None):
|
2013-05-01 21:54:30 +08:00
|
|
|
GenericObject.__init__(self, name, 'VI Managed Object', True,
|
|
|
|
managed_objects_by_name)
|
2011-04-10 19:27:56 +08:00
|
|
|
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:
|
2019-09-25 00:26:29 +08:00
|
|
|
obj = managed_objects_by_name[self.extends]
|
|
|
|
source += obj.generate_lookup_code1(add_banner=True) + "\n"
|
2011-04-10 19:27:56 +08:00
|
|
|
|
|
|
|
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:
|
2019-09-25 00:26:29 +08:00
|
|
|
obj = managed_objects_by_name[self.extends]
|
|
|
|
source += obj.generate_lookup_code2(add_banner=True) + "\n"
|
2011-04-10 19:27:56 +08:00
|
|
|
|
|
|
|
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:
|
2011-05-02 03:57:42 +08:00
|
|
|
header += aligned(" esxVI_%s *_next; " % self.name,
|
|
|
|
"/* optional */\n")
|
2011-04-10 19:27:56 +08:00
|
|
|
else:
|
2011-05-02 03:57:42 +08:00
|
|
|
header += aligned(" esxVI_%s *_unused; " % self.name,
|
|
|
|
"/* optional */\n")
|
2011-04-10 19:27:56 +08:00
|
|
|
|
|
|
|
header += aligned(" esxVI_Type _type; ", "/* required */\n")
|
2011-05-02 03:57:42 +08:00
|
|
|
header += aligned(" esxVI_ManagedObjectReference *_reference; ",
|
|
|
|
"/* required */\n")
|
2011-04-10 19:27:56 +08:00
|
|
|
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)
|
2011-05-02 03:57:42 +08:00
|
|
|
header += ("int esxVI_%s_Validate(esxVI_%s *item, "
|
2019-09-25 00:26:29 +08:00
|
|
|
" esxVI_String *selectedPropertyNameList);\n") \
|
|
|
|
% (self.name, self.name)
|
2011-04-10 19:27:56 +08:00
|
|
|
|
|
|
|
if self.features & Object.FEATURE__LIST:
|
2011-05-02 03:57:42 +08:00
|
|
|
header += "int esxVI_%s_AppendToList(esxVI_%s **list, esxVI_%s *item);\n" \
|
2019-09-25 00:26:29 +08:00
|
|
|
% (self.name, self.name, self.name)
|
2011-04-10 19:27:56 +08:00
|
|
|
|
|
|
|
header += "\n\n\n"
|
|
|
|
|
|
|
|
return header
|
|
|
|
|
|
|
|
def generate_helper_header(self):
|
|
|
|
# functions
|
2018-03-20 14:48:49 +08:00
|
|
|
return (
|
|
|
|
"int esxVI_Lookup%(name)s(esxVI_Context *ctx,"
|
2019-09-25 00:26:29 +08:00
|
|
|
" const char *name,"
|
|
|
|
" esxVI_ManagedObjectReference *root,"
|
|
|
|
" esxVI_String *selectedPropertyNameList,"
|
|
|
|
" esxVI_%(name)s **item,"
|
|
|
|
" esxVI_Occurrence occurrence);\n\n"
|
2018-03-20 14:48:49 +08:00
|
|
|
% {"name": self.name}
|
|
|
|
)
|
2011-04-10 19:27:56 +08:00
|
|
|
|
|
|
|
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
|
2013-05-01 21:54:30 +08:00
|
|
|
source += "/* esxVI_%s_Free */\n" % self.name
|
|
|
|
|
2011-04-10 19:27:56 +08:00
|
|
|
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"
|
2013-01-02 14:22:28 +08:00
|
|
|
source += self.generate_dispatch('FREE')
|
2011-04-10 19:27:56 +08:00
|
|
|
source += "},\n"
|
|
|
|
|
2013-05-01 21:54:30 +08:00
|
|
|
source += "{\n"
|
2011-04-10 19:27:56 +08:00
|
|
|
|
2013-05-01 21:54:30 +08:00
|
|
|
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
|
2011-04-10 19:27:56 +08:00
|
|
|
|
2013-05-01 21:54:30 +08:00
|
|
|
source += " esxVI_ManagedObjectReference_Free(&item->_reference);\n\n"
|
|
|
|
source += self.generate_free_code()
|
|
|
|
source += "})\n\n"
|
2011-04-10 19:27:56 +08:00
|
|
|
|
|
|
|
# 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
|
2018-03-20 14:48:48 +08:00
|
|
|
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()}
|
|
|
|
)
|
2010-04-13 20:25:52 +08:00
|
|
|
|
2010-03-07 00:56:28 +08:00
|
|
|
|
2011-05-01 17:29:40 +08:00
|
|
|
class Enum(Type):
|
2011-04-10 19:26:47 +08:00
|
|
|
FEATURE__ANY_TYPE = (1 << 1)
|
|
|
|
FEATURE__SERIALIZE = (1 << 2)
|
|
|
|
FEATURE__DESERIALIZE = (1 << 3)
|
|
|
|
|
|
|
|
def __init__(self, name, values, features=0):
|
2011-05-01 17:29:40 +08:00
|
|
|
Type.__init__(self, "enum", name)
|
2011-04-10 19:26:47 +08:00
|
|
|
self.values = values
|
2011-05-01 16:43:17 +08:00
|
|
|
self.features = features
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
def generate_header(self):
|
2011-05-02 03:57:42 +08:00
|
|
|
header = separator
|
2010-03-07 00:56:28 +08:00
|
|
|
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:
|
2011-05-02 03:57:42 +08:00
|
|
|
header += ("int esxVI_%s_CastFromAnyType(esxVI_AnyType *anyType, "
|
2019-09-25 00:26:29 +08:00
|
|
|
" esxVI_%s *item);\n") \
|
|
|
|
% (self.name, self.name)
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
if self.features & Enum.FEATURE__SERIALIZE:
|
2011-05-02 03:57:42 +08:00
|
|
|
header += ("int esxVI_%s_Serialize(esxVI_%s item, const char *element, "
|
2021-03-11 15:16:13 +08:00
|
|
|
" virBuffer *output);\n") \
|
2019-09-25 00:26:29 +08:00
|
|
|
% (self.name, self.name)
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
if self.features & Enum.FEATURE__DESERIALIZE:
|
2011-05-02 03:57:42 +08:00
|
|
|
header += ("int esxVI_%s_Deserialize(xmlNodePtr node, "
|
2019-09-25 00:26:29 +08:00
|
|
|
" esxVI_%s *item);\n") \
|
|
|
|
% (self.name, self.name)
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
header += "\n\n\n"
|
|
|
|
|
|
|
|
return header
|
|
|
|
|
|
|
|
def generate_source(self):
|
2011-05-02 03:57:42 +08:00
|
|
|
source = separator
|
2010-03-07 00:56:28 +08:00
|
|
|
source += " * VI Enum: %s\n" % self.name
|
|
|
|
source += " */\n\n"
|
2011-05-02 03:57:42 +08:00
|
|
|
source += "static const esxVI_Enumeration _esxVI_%s_Enumeration = {\n" \
|
2019-09-25 00:26:29 +08:00
|
|
|
% self.name
|
2010-03-07 00:56:28 +08:00
|
|
|
source += " esxVI_Type_%s, {\n" % self.name
|
|
|
|
|
|
|
|
for value in self.values:
|
2011-05-02 03:57:42 +08:00
|
|
|
source += " { \"%s\", esxVI_%s_%s },\n" \
|
2019-09-25 00:26:29 +08:00
|
|
|
% (value, self.name, capitalize_first(value))
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
source += " { NULL, -1 },\n"
|
|
|
|
source += " },\n"
|
|
|
|
source += "};\n\n"
|
|
|
|
|
|
|
|
# functions
|
|
|
|
if self.features & Enum.FEATURE__ANY_TYPE:
|
|
|
|
source += "/* esxVI_%s_CastFromAnyType */\n" % self.name
|
2011-05-02 03:57:42 +08:00
|
|
|
source += "ESX_VI__TEMPLATE__ENUMERATION__CAST_FROM_ANY_TYPE(%s)\n\n" \
|
|
|
|
% self.name
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
if self.features & Enum.FEATURE__SERIALIZE:
|
|
|
|
source += "/* esxVI_%s_Serialize */\n" % self.name
|
2011-05-02 03:57:42 +08:00
|
|
|
source += "ESX_VI__TEMPLATE__ENUMERATION__SERIALIZE(%s)\n\n" \
|
|
|
|
% self.name
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
if self.features & Enum.FEATURE__DESERIALIZE:
|
|
|
|
source += "/* esxVI_%s_Deserialize */\n" % self.name
|
2011-05-02 03:57:42 +08:00
|
|
|
source += "ESX_VI__TEMPLATE__ENUMERATION__DESERIALIZE(%s)\n\n" \
|
|
|
|
% self.name
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
source += "\n\n"
|
|
|
|
|
|
|
|
return source
|
|
|
|
|
|
|
|
|
|
|
|
def report_error(message):
|
2018-03-15 17:30:03 +08:00
|
|
|
print("error: " + message)
|
2010-03-07 00:56:28 +08:00
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
def capitalize_first(string):
|
|
|
|
return string[:1].upper() + string[1:]
|
|
|
|
|
|
|
|
|
|
|
|
def parse_object(block):
|
2011-04-10 19:27:56 +08:00
|
|
|
# expected format: [managed] object <name> [extends <name>]
|
2010-03-07 00:56:28 +08:00
|
|
|
header_items = block[0][1].split()
|
2011-04-10 19:27:56 +08:00
|
|
|
managed = False
|
|
|
|
|
|
|
|
if header_items[0] == "managed":
|
|
|
|
managed = True
|
|
|
|
del header_items[0]
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
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])
|
|
|
|
|
2010-04-13 20:25:52 +08:00
|
|
|
if items[2] not in valid_occurrences:
|
2010-03-07 00:56:28 +08:00
|
|
|
report_error("line %d: invalid occurrence" % line[0])
|
|
|
|
|
2011-04-10 19:26:47 +08:00
|
|
|
properties.append(Property(type=items[0], name=items[1],
|
|
|
|
occurrence=items[2]))
|
2010-03-07 00:56:28 +08:00
|
|
|
|
2011-04-10 19:27:56 +08:00
|
|
|
if managed:
|
|
|
|
return ManagedObject(name=name, extends=extends, properties=properties)
|
|
|
|
else:
|
|
|
|
return Object(name=name, extends=extends, properties=properties)
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
|
|
|
|
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])
|
|
|
|
|
2011-04-10 19:26:47 +08:00
|
|
|
return Enum(name=name, values=values)
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
|
2010-04-13 20:25:52 +08:00
|
|
|
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:
|
2011-04-10 19:26:47 +08:00
|
|
|
returns = Parameter(type=header_items[3], name="output",
|
|
|
|
occurrence=header_items[4])
|
2010-04-13 20:25:52 +08:00
|
|
|
|
|
|
|
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])
|
|
|
|
|
2011-04-10 19:26:47 +08:00
|
|
|
parameters.append(Parameter(type=items[0], name=items[1],
|
|
|
|
occurrence=items[2]))
|
2010-04-13 20:25:52 +08:00
|
|
|
|
2011-04-10 19:26:47 +08:00
|
|
|
return Method(name=name, parameters=parameters, returns=returns)
|
2010-04-13 20:25:52 +08:00
|
|
|
|
|
|
|
|
2010-03-07 00:56:28 +08:00
|
|
|
def is_known_type(type):
|
2019-09-25 00:26:29 +08:00
|
|
|
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)
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
|
esx: generator: fix free of elements in lists
When a list is freed, we iterate through all the items, invoking the
free function for each; the actual free function called for each element
is the function of the actual type of each element, and thus the @_next
pointer in the element struct has the same type as the element itself.
Currently, the free function gets the parent of the current element
type, and invoke its free function to continue freeing the list.
However, in case the hierarchy of the classes has more than 1 level
(i.e. Class <- SubClass <- SubSubClass), the invoked free function is
only the parent class' one, and not the actual base class of the
hierarchy.
To fix that, change the generator to get the base class of a class, and
invoking that instead. Also, avoid to set the @_next back, as it is not
needed.
Fixes commits 5cff36e39ae691fbd7c40597df1732eecf294150 and
f76c6dde2e33233566e886d96e76b5fe0c102d9a.
Signed-off-by: Pino Toscano <ptoscano@redhat.com>
Reviewed-by: Martin Kletzander <mkletzan@redhat.com>
2020-09-10 21:08:24 +08:00
|
|
|
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
|
|
|
|
|
|
|
|
|
2020-07-27 14:23:40 +08:00
|
|
|
def open_file(filename):
|
2018-03-15 17:56:42 +08:00
|
|
|
return open(filename, "wt")
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
|
|
|
|
predefined_enums = ["Boolean"]
|
|
|
|
|
|
|
|
predefined_objects = ["AnyType",
|
2012-08-02 06:15:11 +08:00
|
|
|
"Byte",
|
2010-03-07 00:56:28 +08:00
|
|
|
"Int",
|
|
|
|
"Long",
|
|
|
|
"String",
|
|
|
|
"DateTime",
|
2010-12-06 20:53:36 +08:00
|
|
|
"MethodFault",
|
2010-03-07 00:56:28 +08:00
|
|
|
"ManagedObjectReference"]
|
|
|
|
|
2018-03-20 14:48:46 +08:00
|
|
|
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,
|
2020-09-14 17:10:58 +08:00
|
|
|
"GuestNicInfo": Object.FEATURE__LIST | Object.FEATURE__ANY_TYPE,
|
2018-03-20 14:48:46 +08:00
|
|
|
"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
|
|
|
|
}
|
2010-03-07 00:56:28 +08:00
|
|
|
|
2011-05-01 16:43:17 +08:00
|
|
|
removed_object_features = {}
|
2010-03-07 00:56:28 +08:00
|
|
|
|
2020-09-23 14:37:20 +08:00
|
|
|
if len(sys.argv) != 4:
|
|
|
|
report_error("usage: %s srcdir builddir header" % sys.argv[0])
|
2010-03-07 00:56:28 +08:00
|
|
|
|
2019-10-16 20:45:15 +08:00
|
|
|
input_filename = os.path.join(sys.argv[1], "esx/esx_vi_generator.input")
|
|
|
|
output_dirname = os.path.join(sys.argv[2], "esx")
|
2020-09-23 14:37:20 +08:00
|
|
|
header = sys.argv[3] == "header"
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
|
2020-09-23 14:37:20 +08:00
|
|
|
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"))
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
|
|
|
|
number = 0
|
|
|
|
objects_by_name = {}
|
2011-04-10 19:27:56 +08:00
|
|
|
managed_objects_by_name = {}
|
2010-03-07 00:56:28 +08:00
|
|
|
enums_by_name = {}
|
2010-04-13 20:25:52 +08:00
|
|
|
methods_by_name = {}
|
2010-03-07 00:56:28 +08:00
|
|
|
block = None
|
esx: generator: fix free of elements in lists
When a list is freed, we iterate through all the items, invoking the
free function for each; the actual free function called for each element
is the function of the actual type of each element, and thus the @_next
pointer in the element struct has the same type as the element itself.
Currently, the free function gets the parent of the current element
type, and invoke its free function to continue freeing the list.
However, in case the hierarchy of the classes has more than 1 level
(i.e. Class <- SubClass <- SubSubClass), the invoked free function is
only the parent class' one, and not the actual base class of the
hierarchy.
To fix that, change the generator to get the base class of a class, and
invoking that instead. Also, avoid to set the @_next back, as it is not
needed.
Fixes commits 5cff36e39ae691fbd7c40597df1732eecf294150 and
f76c6dde2e33233566e886d96e76b5fe0c102d9a.
Signed-off-by: Pino Toscano <ptoscano@redhat.com>
Reviewed-by: Martin Kletzander <mkletzan@redhat.com>
2020-09-10 21:08:24 +08:00
|
|
|
base_class_by_name = {}
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
|
2011-05-01 16:43:17 +08:00
|
|
|
# parse input file
|
2018-03-15 17:56:42 +08:00
|
|
|
for line in open(input_filename, "rt").readlines():
|
2010-03-07 00:56:28 +08:00
|
|
|
number += 1
|
|
|
|
|
|
|
|
if "#" in line:
|
|
|
|
line = line[:line.index("#")]
|
|
|
|
|
|
|
|
line = line.lstrip().rstrip()
|
|
|
|
|
|
|
|
if len(line) < 1:
|
|
|
|
continue
|
|
|
|
|
2011-04-10 19:27:56 +08:00
|
|
|
if line.startswith("object") or line.startswith("managed object") or \
|
|
|
|
line.startswith("enum") or line.startswith("method"):
|
2010-03-07 00:56:28 +08:00
|
|
|
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
|
2011-04-10 19:27:56 +08:00
|
|
|
elif block[0][1].startswith("managed object"):
|
|
|
|
obj = parse_object(block)
|
|
|
|
managed_objects_by_name[obj.name] = obj
|
2010-04-13 20:25:52 +08:00
|
|
|
elif block[0][1].startswith("enum"):
|
2010-03-07 00:56:28 +08:00
|
|
|
enum = parse_enum(block)
|
|
|
|
enums_by_name[enum.name] = enum
|
2010-04-13 20:25:52 +08:00
|
|
|
else:
|
|
|
|
method = parse_method(block)
|
|
|
|
methods_by_name[method.name] = method
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
block = None
|
|
|
|
else:
|
|
|
|
block.append((number, line))
|
|
|
|
|
|
|
|
|
2011-05-01 16:43:17 +08:00
|
|
|
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
|
2011-05-01 17:08:21 +08:00
|
|
|
objects_by_name[parameter.type].candidate_for_dynamic_cast = True
|
2011-05-01 16:43:17 +08:00
|
|
|
|
2011-05-01 17:31:55 +08:00
|
|
|
# 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
|
|
|
|
|
2011-05-01 16:43:17 +08:00
|
|
|
# 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
|
2011-05-01 17:08:21 +08:00
|
|
|
objects_by_name[method.returns.type].candidate_for_dynamic_cast = True
|
2011-05-01 16:43:17 +08:00
|
|
|
|
2011-05-01 17:31:55 +08:00
|
|
|
# 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
|
|
|
|
|
2011-05-01 16:43:17 +08:00
|
|
|
|
2010-03-07 00:56:28 +08:00
|
|
|
for enum in enums_by_name.values():
|
|
|
|
# apply additional features
|
|
|
|
if enum.name in additional_enum_features:
|
|
|
|
enum.features |= additional_enum_features[enum.name]
|
|
|
|
|
2011-05-01 16:43:17 +08:00
|
|
|
if additional_enum_features[enum.name] & Enum.FEATURE__ANY_TYPE:
|
|
|
|
enum.features |= Enum.FEATURE__DESERIALIZE
|
|
|
|
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
for obj in objects_by_name.values():
|
|
|
|
for property in obj.properties:
|
2010-04-13 20:25:52 +08:00
|
|
|
if property.occurrence != OCCURRENCE__IGNORED and \
|
2010-03-07 00:56:28 +08:00
|
|
|
not is_known_type(property.type):
|
2011-05-02 03:57:42 +08:00
|
|
|
report_error("object '%s' contains unknown property type '%s'"
|
|
|
|
% (obj.name, property.type))
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
if obj.extends is not None:
|
|
|
|
if not is_known_type(obj.extends):
|
2011-05-02 03:57:42 +08:00
|
|
|
report_error("object '%s' extends unknown object '%s'"
|
|
|
|
% (obj.name, obj.extends))
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
for property in obj.properties:
|
2011-05-01 17:31:55 +08:00
|
|
|
if not property.is_type_generated():
|
|
|
|
continue
|
|
|
|
|
2011-05-01 17:08:21 +08:00
|
|
|
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
|
2011-05-01 17:31:55 +08:00
|
|
|
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
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
# apply/remove additional features
|
|
|
|
if obj.name in additional_object_features:
|
|
|
|
obj.features |= additional_object_features[obj.name]
|
|
|
|
|
2011-05-01 16:43:17 +08:00
|
|
|
if additional_object_features[obj.name] & Object.FEATURE__ANY_TYPE:
|
|
|
|
obj.features |= Object.FEATURE__DESERIALIZE
|
|
|
|
|
2010-03-07 00:56:28 +08:00
|
|
|
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)
|
2010-05-19 00:11:59 +08:00
|
|
|
extended_obj.extended_by.sort()
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
|
2011-05-01 17:08:21 +08:00
|
|
|
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
|
|
|
|
|
|
|
|
|
2011-05-01 16:43:17 +08:00
|
|
|
def propagate_feature(obj, feature):
|
|
|
|
global features_have_changed
|
|
|
|
|
|
|
|
if not (obj.features & feature):
|
|
|
|
return
|
|
|
|
|
|
|
|
for property in obj.properties:
|
2019-09-25 00:26:29 +08:00
|
|
|
if (property.occurrence == OCCURRENCE__IGNORED or
|
|
|
|
not property.is_type_generated()):
|
2011-05-01 16:43:17 +08:00
|
|
|
continue
|
|
|
|
|
|
|
|
if property.is_enum():
|
2019-09-25 00:26:29 +08:00
|
|
|
if (feature == Object.FEATURE__SERIALIZE and
|
|
|
|
not (enums_by_name[property.type].features &
|
|
|
|
Enum.FEATURE__SERIALIZE)):
|
2011-05-01 16:43:17 +08:00
|
|
|
enums_by_name[property.type].features |= Enum.FEATURE__SERIALIZE
|
|
|
|
features_have_changed = True
|
2019-09-25 00:26:29 +08:00
|
|
|
elif (feature == Object.FEATURE__DESERIALIZE and
|
|
|
|
not (enums_by_name[property.type].features &
|
|
|
|
Enum.FEATURE__DESERIALIZE)):
|
2011-05-01 16:43:17 +08:00
|
|
|
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)
|
|
|
|
|
|
|
|
|
2011-04-10 19:27:56 +08:00
|
|
|
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):
|
2011-05-02 03:57:42 +08:00
|
|
|
report_error("object '%s' contains unknown property type '%s'"
|
|
|
|
% (obj.name, property.type))
|
2011-04-10 19:27:56 +08:00
|
|
|
|
|
|
|
if obj.extends is not None:
|
|
|
|
if not is_known_type(obj.extends):
|
2011-05-02 03:57:42 +08:00
|
|
|
report_error("object '%s' extends unknown object '%s'"
|
|
|
|
% (obj.name, obj.extends))
|
2011-04-10 19:27:56 +08:00
|
|
|
|
|
|
|
# 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()
|
|
|
|
|
|
|
|
|
2011-08-24 05:15:21 +08:00
|
|
|
notice = "/* Generated by esx_vi_generator.py */\n\n\n\n"
|
|
|
|
|
2020-09-23 14:37:20 +08:00
|
|
|
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)
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
|
2010-04-13 20:25:52 +08:00
|
|
|
# output enums
|
2020-09-23 14:37:20 +08:00
|
|
|
if header:
|
|
|
|
types_typedef.write(separator +
|
|
|
|
" * VI Enums\n" +
|
|
|
|
" */\n\n")
|
2010-03-07 00:56:28 +08:00
|
|
|
|
2018-03-15 17:51:57 +08:00
|
|
|
names = sorted(enums_by_name.keys())
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
for name in names:
|
2020-09-23 14:37:20 +08:00
|
|
|
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())
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
|
2010-04-13 20:25:52 +08:00
|
|
|
# output objects
|
2020-09-23 14:37:20 +08:00
|
|
|
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")
|
2010-03-07 00:56:28 +08:00
|
|
|
|
2018-03-15 17:51:57 +08:00
|
|
|
names = sorted(objects_by_name.keys())
|
2010-03-07 00:56:28 +08:00
|
|
|
|
2010-04-13 20:25:52 +08:00
|
|
|
for name in names:
|
2020-09-23 14:37:20 +08:00
|
|
|
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())
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
|
2011-04-10 19:27:56 +08:00
|
|
|
# output managed objects
|
2020-09-23 14:37:20 +08:00
|
|
|
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")
|
2011-04-10 19:27:56 +08:00
|
|
|
|
2018-03-15 17:51:57 +08:00
|
|
|
names = sorted(managed_objects_by_name.keys())
|
2011-04-10 19:27:56 +08:00
|
|
|
|
|
|
|
for name in names:
|
2020-09-23 14:37:20 +08:00
|
|
|
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())
|
2011-04-10 19:27:56 +08:00
|
|
|
|
|
|
|
|
2010-04-13 20:25:52 +08:00
|
|
|
# output methods
|
2018-03-15 17:51:57 +08:00
|
|
|
names = sorted(methods_by_name.keys())
|
2010-03-07 00:56:28 +08:00
|
|
|
|
|
|
|
for name in names:
|
2020-09-23 14:37:20 +08:00
|
|
|
if header:
|
|
|
|
methods_header.write(methods_by_name[name].generate_header())
|
|
|
|
else:
|
|
|
|
methods_source.write(methods_by_name[name].generate_source())
|
2011-04-10 19:27:56 +08:00
|
|
|
|
2020-09-23 14:37:20 +08:00
|
|
|
if not header:
|
|
|
|
names = list(autobind_names)
|
|
|
|
names.sort()
|
2011-05-01 14:05:58 +08:00
|
|
|
|
2020-09-23 14:37:20 +08:00
|
|
|
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)
|
2011-05-01 14:05:58 +08:00
|
|
|
|
2020-09-23 14:37:20 +08:00
|
|
|
methods_macro.write(string)
|
2011-05-01 14:05:58 +08:00
|
|
|
|
2011-04-10 19:27:56 +08:00
|
|
|
|
|
|
|
# output helpers
|
2018-03-15 17:51:57 +08:00
|
|
|
names = sorted(managed_objects_by_name.keys())
|
2011-04-10 19:27:56 +08:00
|
|
|
|
|
|
|
for name in names:
|
2020-09-23 14:37:20 +08:00
|
|
|
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())
|