esx_vi_generator.py 68.0 KB
Newer Older
1
#!/usr/bin/env python
2 3 4 5

#
# esx_vi_generator.py: generates most of the SOAP type mapping code
#
M
Matthias Bolte 已提交
6
# Copyright (C) 2010-2012 Matthias Bolte <matthias.bolte@googlemail.com>
7
# Copyright (C) 2013 Ata E Husain Bohra <ata.husain@hotmail.com>
8 9 10 11 12 13 14 15 16 17 18 19
#
# 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
20
# License along with this library.  If not, see
21
# <http://www.gnu.org/licenses/>.
22 23 24 25 26 27 28 29
#

import sys
import os
import os.path



30 31 32 33 34
OCCURRENCE__REQUIRED_ITEM = "r"
OCCURRENCE__REQUIRED_LIST = "rl"
OCCURRENCE__OPTIONAL_ITEM = "o"
OCCURRENCE__OPTIONAL_LIST = "ol"
OCCURRENCE__IGNORED = "i"
35

36 37 38 39 40
valid_occurrences = [OCCURRENCE__REQUIRED_ITEM,
                     OCCURRENCE__REQUIRED_LIST,
                     OCCURRENCE__OPTIONAL_ITEM,
                     OCCURRENCE__OPTIONAL_LIST,
                     OCCURRENCE__IGNORED]
41

42
autobind_names = set()
43

44 45
separator = "/* " + ("* " * 37) + "*\n"

46 47


48 49
def aligned(left, right, length=59):
    while len(left) < length:
M
Matthias Bolte 已提交
50 51 52
        left += " "

    return left + right
53 54 55



56 57
class Member:
    def __init__(self, type, occurrence):
58 59 60 61 62 63 64 65
        self.type = type
        self.occurrence = occurrence


    def is_enum(self):
        return self.type in predefined_enums or self.type in enums_by_name


66 67 68 69 70 71 72 73
    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


74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
    def get_occurrence_comment(self):
        if self.occurrence == OCCURRENCE__REQUIRED_ITEM:
            return "/* required */"
        elif self.occurrence == OCCURRENCE__REQUIRED_LIST:
            return "/* required, list */"
        elif self.occurrence == OCCURRENCE__OPTIONAL_ITEM:
            return "/* optional */"
        elif self.occurrence == OCCURRENCE__OPTIONAL_LIST:
            return "/* optional, list */"

        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"):
93
            self.name, self.autobind_name = name.split(":")
94 95
        else:
            self.name = name
96
            self.autobind_name = None
97 98


99
    def generate_parameter(self, is_last=False, is_header=True, offset=0):
100
        if self.occurrence == OCCURRENCE__IGNORED:
101 102
            raise ValueError("invalid function parameter occurrence value '%s'"
                             % self.occurrence)
103
        elif self.autobind_name is not None:
104 105 106 107 108 109 110 111 112 113 114 115 116 117
            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 += ", "

M
Matthias Bolte 已提交
118
            return aligned(string, self.get_occurrence_comment() + "\n")
119 120 121 122


    def generate_return(self, offset = 0, end_of_line = ";"):
        if self.occurrence == OCCURRENCE__IGNORED:
123 124
            raise ValueError("invalid function parameter occurrence value '%s'"
                             % self.occurrence)
125 126 127
        else:
            string = "       "
            string += " " * offset
128 129
            string += "%s%s)%s" \
                      % (self.get_type_string(True), self.name, end_of_line)
130

M
Matthias Bolte 已提交
131
            return aligned(string, self.get_occurrence_comment() + "\n")
132 133 134 135 136 137 138 139 140 141 142 143 144


    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]:
145 146
            return "    ESX_VI__METHOD__PARAMETER__SERIALIZE_LIST(%s, %s)\n" \
                   % (self.type, self.name)
147
        elif self.type == "String":
148 149
            return "    ESX_VI__METHOD__PARAMETER__SERIALIZE_VALUE(String, %s)\n" \
                   % self.name
150
        else:
151 152
            return "    ESX_VI__METHOD__PARAMETER__SERIALIZE(%s, %s)\n" \
                   % (self.type, self.name)
153 154


155
    def get_type_string(self, as_return_value=False):
156 157
        string = ""

158 159 160
        if self.type == "String" and \
           self.occurrence not in [OCCURRENCE__REQUIRED_LIST,
                                   OCCURRENCE__OPTIONAL_LIST]:
161 162 163 164
            if as_return_value:
                string += "char *"
            else:
                string += "const char *"
165
        elif self.is_enum():
166
            string += "esxVI_%s " % self.type
167
        else:
168 169 170 171 172 173
            string += "esxVI_%s *" % self.type

        if as_return_value:
            string += "*"

        return string
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197


    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:
198
            if parameter.autobind_name is None:
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
                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:
215
                header += self.parameters[-1].generate_parameter(is_last=True)
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
            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:
232 233
            autobind_names.add(self.autobind_parameter.autobind_name)
            source += " %s,\n" % self.autobind_parameter.autobind_name
234 235 236 237 238 239 240 241 242
        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]:
243 244
                source += parameter.generate_parameter(is_header=False,
                                                       offset=9)
245 246

            if self.returns is None:
247 248 249
                source += self.parameters[-1].generate_parameter(is_last=True,
                                                                 is_header=False,
                                                                 offset=9)
250
            else:
251 252 253 254
                source += self.parameters[-1].generate_parameter(is_header=False,
                                                                 offset=9)
                source += self.returns.generate_return(offset=9,
                                                       end_of_line=",")
255 256 257 258
        else:
            source += "),\n"

        if self.returns is None:
259 260
            source += "               void, /* nothing */, None,\n"
        elif self.returns.type == "String":
261 262
            source += "               String, Value, %s,\n" \
                      % self.returns.get_occurrence_short_enum()
263
        else:
264 265 266
            source += "               %s, /* nothing */, %s,\n" \
                      % (self.returns.type,
                         self.returns.get_occurrence_short_enum())
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290

        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



291
class Property(Member):
292
    def __init__(self, type, name, occurrence):
293
        Member.__init__(self, type, occurrence)
294

295
        self.name = name
296 297


298
    def generate_struct_member(self):
299
        if self.occurrence == OCCURRENCE__IGNORED:
300 301 302 303
            return "    /* FIXME: %s is currently ignored */\n" % self.name
        else:
            string = "    %s%s; " % (self.get_type_string(), self.name)

M
Matthias Bolte 已提交
304
            return aligned(string, self.get_occurrence_comment() + "\n")
305

306 307 308

    def generate_free_code(self):
        if self.type == "String" and \
309 310 311
           self.occurrence not in [OCCURRENCE__REQUIRED_LIST,
                                   OCCURRENCE__OPTIONAL_LIST,
                                   OCCURRENCE__IGNORED]:
312 313 314 315
            return "    VIR_FREE(item->%s);\n" % self.name
        elif self.is_enum():
            return ""
        else:
316
            if self.occurrence == OCCURRENCE__IGNORED:
317 318 319 320
                return "    /* FIXME: %s is currently ignored */\n" % self.name
            else:
                return "    esxVI_%s_Free(&item->%s);\n" % (self.type, self.name)

321

322 323 324 325 326 327
    def generate_validate_code(self, managed=False):
        if managed:
            macro = "ESX_VI__TEMPLATE__PROPERTY__MANAGED_REQUIRE"
        else:
            macro = "ESX_VI__TEMPLATE__PROPERTY__REQUIRE"

328 329
        if self.occurrence in [OCCURRENCE__REQUIRED_ITEM,
                               OCCURRENCE__REQUIRED_LIST]:
330
            return "    %s(%s)\n" % (macro, self.name)
331
        elif self.occurrence == OCCURRENCE__IGNORED:
332 333 334 335
            return "    /* FIXME: %s is currently ignored */\n" % self.name
        else:
            return ""

336

337
    def generate_deep_copy_code(self):
338
        if self.occurrence == OCCURRENCE__IGNORED:
339
            return "    /* FIXME: %s is currently ignored */\n" % self.name
340 341
        elif self.occurrence in [OCCURRENCE__REQUIRED_LIST,
                                 OCCURRENCE__OPTIONAL_LIST]:
342 343
            return "    ESX_VI__TEMPLATE__PROPERTY__DEEP_COPY_LIST(%s, %s)\n" \
                   % (self.type, self.name)
344
        elif self.type == "String":
345 346
            return "    ESX_VI__TEMPLATE__PROPERTY__DEEP_COPY_VALUE(String, %s)\n" \
                   % self.name
347 348
        elif self.is_enum():
            return "    (*dest)->%s = src->%s;\n" % (self.name, self.name)
349
        else:
350 351
            return "    ESX_VI__TEMPLATE__PROPERTY__DEEP_COPY(%s, %s)\n" \
                   % (self.type, self.name)
352

353

354
    def generate_serialize_code(self):
355
        if self.occurrence == OCCURRENCE__IGNORED:
356
            return "    /* FIXME: %s is currently ignored */\n" % self.name
357 358
        elif self.occurrence in [OCCURRENCE__REQUIRED_LIST,
                                 OCCURRENCE__OPTIONAL_LIST]:
359 360
            return "    ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_LIST(%s, %s)\n" \
                   % (self.type, self.name)
361
        elif self.type == "String":
362 363
            return "    ESX_VI__TEMPLATE__PROPERTY__SERIALIZE_VALUE(String, %s)\n" \
                   % self.name
364
        else:
365 366
            return "    ESX_VI__TEMPLATE__PROPERTY__SERIALIZE(%s, %s)\n" \
                   % (self.type, self.name)
367

368

369
    def generate_deserialize_code(self):
370
        if self.occurrence == OCCURRENCE__IGNORED:
371 372
            return "    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_IGNORE(%s) /* FIXME */\n" \
                   % self.name
373 374
        elif self.occurrence in [OCCURRENCE__REQUIRED_LIST,
                                 OCCURRENCE__OPTIONAL_LIST]:
375 376
            return "    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_LIST(%s, %s)\n" \
                   % (self.type, self.name)
377
        elif self.type == "String":
378 379
            return "    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE_VALUE(String, %s)\n" \
                   % self.name
380
        else:
381 382
            return "    ESX_VI__TEMPLATE__PROPERTY__DESERIALIZE(%s, %s)\n" \
                   % (self.type, self.name)
383

384

385 386
    def generate_lookup_code(self):
        if self.occurrence == OCCURRENCE__IGNORED:
387 388
            return "    ESX_VI__TEMPLATE__PROPERTY__CAST_FROM_ANY_TYPE_IGNORE(%s) /* FIXME */\n" \
                   % self.name
389 390
        elif self.occurrence in [OCCURRENCE__REQUIRED_LIST,
                                 OCCURRENCE__OPTIONAL_LIST]:
391 392
            return "    ESX_VI__TEMPLATE__PROPERTY__CAST_LIST_FROM_ANY_TYPE(%s, %s)\n" \
                   % (self.type, self.name)
393
        elif self.type == "String":
394 395
            return "    ESX_VI__TEMPLATE__PROPERTY__CAST_VALUE_FROM_ANY_TYPE(String, %s)\n" \
                   % self.name
396
        else:
397 398
            return "    ESX_VI__TEMPLATE__PROPERTY__CAST_FROM_ANY_TYPE(%s, %s)\n" \
                   % (self.type, self.name)
399 400


401 402
    def get_type_string(self):
        if self.type == "String" and \
403 404
           self.occurrence not in [OCCURRENCE__REQUIRED_LIST,
                                   OCCURRENCE__OPTIONAL_LIST]:
405 406 407 408 409 410 411 412
            return "char *"
        elif self.is_enum():
            return "esxVI_%s " % self.type
        else:
            return "esxVI_%s *" % self.type



413
class Type:
M
Matthias Bolte 已提交
414 415 416 417 418 419
    def __init__(self, kind, name):
        self.kind = kind
        self.name = name


    def generate_typedef(self):
420 421
        return "typedef %s _esxVI_%s esxVI_%s;\n" \
               % (self.kind, self.name, self.name)
M
Matthias Bolte 已提交
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443


    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 =  "           else if (STREQ(type, \"%s\")) {\n" % self.name
        string += "               return esxVI_Type_%s;\n" % self.name
        string += "           }\n"

        return string



444
class Object(Type):
445 446 447 448 449 450 451
    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)

452 453

    def __init__(self, name, extends, properties, features=0, extended_by=None):
454
        Type.__init__(self, "struct", name)
455
        self.extends = extends
456
        self.features = features
457 458
        self.properties = properties
        self.extended_by = extended_by
459
        self.candidate_for_dynamic_cast = False
460

461
        if self.extended_by is not None:
M
Matthias Bolte 已提交
462
            self.extended_by.sort()
463

464

M
Matthias Bolte 已提交
465
    def generate_struct_members(self, add_banner=False, struct_gap=False):
466 467
        members = ""

M
Matthias Bolte 已提交
468
        if struct_gap:
469 470 471
            members += "\n"

        if self.extends is not None:
472 473 474
            members += objects_by_name[self.extends] \
                       .generate_struct_members(add_banner=True,
                                                struct_gap=False) + "\n"
475 476 477 478 479 480 481 482 483 484 485 486

        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

487

488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
    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:
                source += objects_by_name[extended_by] \
                          .generate_dispatch(suffix, False)

        return source


M
Matthias Bolte 已提交
508
    def generate_free_code(self, add_banner=False):
509 510 511
        source = ""

        if self.extends is not None:
512 513
            source += objects_by_name[self.extends] \
                      .generate_free_code(add_banner=True) + "\n"
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532

        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

533

M
Matthias Bolte 已提交
534
    def generate_validate_code(self, add_banner=False):
535 536 537
        source = ""

        if self.extends is not None:
538 539
            source += objects_by_name[self.extends] \
                      .generate_validate_code(add_banner=True) + "\n"
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558

        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()

            if len(string) < 1:
                source += "    /* no required properties */\n"
            else:
                source += string

        return source

559

560
    def generate_dynamic_cast_code(self, is_first=True):
561 562 563
        source = ""

        if self.extended_by is not None:
564 565 566
            if not is_first:
                source += "\n"

567 568 569
            source += "    /* %s */\n" % self.name

            for extended_by in self.extended_by:
570 571
                source += "    ESX_VI__TEMPLATE__DYNAMIC_CAST__ACCEPT(%s)\n" \
                          % extended_by
572 573

            for extended_by in self.extended_by:
574 575
                source += objects_by_name[extended_by] \
                          .generate_dynamic_cast_code(False)
576 577 578

        return source

579

580 581 582 583
    def generate_deep_copy_code(self, add_banner = False):
        source = ""

        if self.extends is not None:
584 585
            source += objects_by_name[self.extends] \
                      .generate_deep_copy_code(add_banner=True) + "\n"
586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604

        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

605

606
    def generate_serialize_code(self, add_banner=False):
607 608 609
        source = ""

        if self.extends is not None:
610 611
            source += objects_by_name[self.extends] \
                      .generate_serialize_code(add_banner=True) + "\n"
612 613 614 615 616 617 618 619 620 621 622 623

        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

624

625
    def generate_deserialize_code(self, add_banner=False):
626 627 628
        source = ""

        if self.extends is not None:
629 630
            source += objects_by_name[self.extends] \
                      .generate_deserialize_code(add_banner=True) + "\n"
631 632 633 634 635 636 637 638 639 640 641 642

        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

643

644
    def generate_header(self):
645
        header = separator
646
        header += " * VI Object: %s\n" % self.name
647 648

        if self.extends is not None:
649
            header += " *            extends %s\n" % self.extends
650 651 652 653 654 655

        first = True

        if self.extended_by is not None:
            for extended_by in self.extended_by:
                if first:
656
                    header += " *            extended by %s\n" % extended_by
657 658
                    first = False
                else:
659
                    header += " *                        %s\n" % extended_by
660 661 662 663 664 665 666

        header += " */\n\n"

        # struct
        header += "struct _esxVI_%s {\n" % self.name

        if self.features & Object.FEATURE__LIST:
667 668
            header += aligned("    esxVI_%s *_next; " % self.name,
                              "/* optional */\n")
669
        else:
670 671
            header += aligned("    esxVI_%s *_unused; " % self.name,
                              "/* optional */\n")
672

M
Matthias Bolte 已提交
673 674
        header += aligned("    esxVI_Type _type; ", "/* required */\n")
        header += self.generate_struct_members(struct_gap=True)
675 676 677
        header += "};\n\n"

        # functions
678 679 680 681 682 683
        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)
684 685 686

        if self.features & Object.FEATURE__DYNAMIC_CAST:
            if self.extended_by is not None or self.extends is not None:
687 688
                header += "esxVI_%s *esxVI_%s_DynamicCast(void *item);\n" \
                          % (self.name, self.name)
689 690 691 692
            else:
                report_error("cannot add dynamic cast support for an untyped object")

        if self.features & Object.FEATURE__LIST:
693 694
            header += "int esxVI_%s_AppendToList(esxVI_%s **list, esxVI_%s *item);\n" \
                      % (self.name, self.name, self.name)
695 696

        if self.features & Object.FEATURE__DEEP_COPY:
697 698
            header += "int esxVI_%s_DeepCopy(esxVI_%s **dst, esxVI_%s *src);\n" \
                      % (self.name, self.name, self.name)
699 700

            if self.features & Object.FEATURE__LIST:
701 702 703
                header += ("int esxVI_%s_DeepCopyList(esxVI_%s **dstList, "
                                                     "esxVI_%s *srcList);\n") \
                          % (self.name, self.name, self.name)
704 705

        if self.features & Object.FEATURE__ANY_TYPE:
706 707 708
            header += ("int esxVI_%s_CastFromAnyType(esxVI_AnyType *anyType, "
                                                    "esxVI_%s **item);\n") \
                      % (self.name, self.name)
709 710

            if self.features & Object.FEATURE__LIST:
711 712 713
                header += ("int esxVI_%s_CastListFromAnyType(esxVI_AnyType *anyType, "
                                                            "esxVI_%s **list);\n") \
                          % (self.name, self.name)
714 715

        if self.features & Object.FEATURE__SERIALIZE:
716 717 718 719
            header += ("int esxVI_%s_Serialize(esxVI_%s *item, "
                                              "const char *element, "
                                              "virBufferPtr output);\n") \
                      % (self.name, self.name)
720 721

            if self.features & Object.FEATURE__LIST:
722 723 724 725
                header += ("int esxVI_%s_SerializeList(esxVI_%s *list, "
                                                      "const char *element, "
                                                      "virBufferPtr output);\n") \
                          % (self.name, self.name)
726 727

        if self.features & Object.FEATURE__DESERIALIZE:
728 729
            header += "int esxVI_%s_Deserialize(xmlNodePtr node, esxVI_%s **item);\n" \
                      % (self.name, self.name)
730 731

            if self.features & Object.FEATURE__LIST:
732 733 734
                header += ("int esxVI_%s_DeserializeList(xmlNodePtr node, "
                                                        "esxVI_%s **list);\n") \
                          % (self.name, self.name)
735 736 737 738 739

        header += "\n\n\n"

        return header

740

741
    def generate_source(self):
742
        source = separator
743
        source += " * VI Object: %s\n" % self.name
744 745

        if self.extends is not None:
746
            source += " *            extends %s\n" % self.extends
747 748 749 750 751 752

        first = True

        if self.extended_by is not None:
            for extended_by in self.extended_by:
                if first:
753
                    source += " *            extended by %s\n" % extended_by
754 755
                    first = False
                else:
756
                    source += " *                        %s\n" % extended_by
757 758 759 760 761 762 763 764 765 766 767 768 769 770

        source += " */\n\n"

        # functions
        source += "/* esxVI_%s_Alloc */\n" % self.name
        source += "ESX_VI__TEMPLATE__ALLOC(%s)\n\n" % self.name

        # free
        if self.extended_by is None:
            source += "/* esxVI_%s_Free */\n" % self.name
            source += "ESX_VI__TEMPLATE__FREE(%s,\n" % self.name
            source += "{\n"

            if self.features & Object.FEATURE__LIST:
771
                if self.extends is not None:
772 773 774 775
                    # 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)
776 777
                    source += "    esxVI_%s_Free(&next);\n" % self.extends
                    source += "    item->_next = (esxVI_%s *)next;\n\n" % self.name
778 779
                else:
                    source += "    esxVI_%s_Free(&item->_next);\n\n" % self.name
780 781 782 783 784 785 786 787 788

            source += self.generate_free_code()

            source += "})\n\n"
        else:
            source += "/* esxVI_%s_Free */\n" % self.name
            source += "ESX_VI__TEMPLATE__DYNAMIC_FREE(%s,\n" % self.name
            source += "{\n"

789
            source += self.generate_dispatch('FREE')
790 791 792 793 794

            source += "},\n"
            source += "{\n"

            if self.features & Object.FEATURE__LIST:
795
                if self.extends is not None:
796
                    # avoid "dereferencing type-punned pointer will break
797 798 799
                    # strict-aliasing rules" warnings
                    source += "    esxVI_%s *next = (esxVI_%s *)item->_next;\n\n" \
                              % (self.extends, self.extends)
800 801
                    source += "    esxVI_%s_Free(&next);\n" % self.extends
                    source += "    item->_next = (esxVI_%s *)next;\n\n" % self.name
802 803
                else:
                    source += "    esxVI_%s_Free(&item->_next);\n\n" % self.name
804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848

            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.extended_by is None:
            if self.features & Object.FEATURE__DEEP_COPY:
                source += "/* esxVI_%s_DeepCopy */\n" % self.name
                source += "ESX_VI__TEMPLATE__DEEP_COPY(%s,\n" % self.name
                source += "{\n"

                source += self.generate_deep_copy_code()

                source += "})\n\n"

                if self.features & Object.FEATURE__LIST:
                    source += "/* esxVI_%s_DeepCopyList */\n" % self.name
849 850
                    source += "ESX_VI__TEMPLATE__LIST__DEEP_COPY(%s)\n\n" \
                              % self.name
851 852 853
        else:
            if self.features & Object.FEATURE__DEEP_COPY:
                source += "/* esxVI_%s_DeepCopy */\n" % self.name
854
                source += "ESX_VI__TEMPLATE__DYNAMIC_DEEP_COPY(%s,\n" % self.name
855 856
                source += "{\n"

857
                source += self.generate_dispatch('DEEP_COPY')
858 859 860 861 862 863 864 865 866 867

                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
868 869
                    source += "ESX_VI__TEMPLATE__LIST__DEEP_COPY(%s)\n\n" \
                              % self.name
870 871 872 873

        # cast from any type
        if self.features & Object.FEATURE__ANY_TYPE:
            source += "/* esxVI_%s_CastFromAnyType */\n" % self.name
874 875

            if self.extended_by is None:
876 877
                source += "ESX_VI__TEMPLATE__CAST_FROM_ANY_TYPE(%s)\n\n" \
                          % self.name
878
            else:
879 880
                source += "ESX_VI__TEMPLATE__DYNAMIC_CAST_FROM_ANY_TYPE(%s,\n" \
                          % self.name
881 882
                source += "{\n"

883
                source += self.generate_dispatch('CAST_FROM_ANY_TYPE')
884 885

                source += "})\n\n"
886 887 888

            if self.features & Object.FEATURE__LIST:
                source += "/* esxVI_%s_CastListFromAnyType */\n" % self.name
889 890
                source += "ESX_VI__TEMPLATE__LIST__CAST_FROM_ANY_TYPE(%s)\n\n" \
                          % self.name
891 892 893 894 895 896 897 898 899 900 901 902 903 904

        # serialize
        if self.extended_by is None:
            if self.features & Object.FEATURE__SERIALIZE:
                source += "/* esxVI_%s_Serialize */\n" % self.name
                source += "ESX_VI__TEMPLATE__SERIALIZE(%s,\n" % self.name
                source += "{\n"

                source += self.generate_serialize_code()

                source += "})\n\n"

                if self.features & Object.FEATURE__LIST:
                    source += "/* esxVI_%s_SerializeList */\n" % self.name
905 906
                    source += "ESX_VI__TEMPLATE__LIST__SERIALIZE(%s)\n\n" \
                              % self.name
907 908 909 910 911 912
        else:
            if self.features & Object.FEATURE__SERIALIZE:
                source += "/* esxVI_%s_Serialize */\n" % self.name
                source += "ESX_VI__TEMPLATE__DYNAMIC_SERIALIZE(%s,\n" % self.name
                source += "{\n"

913
                source += self.generate_dispatch('SERIALIZE')
914 915 916 917 918 919 920 921 922 923

                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
924 925
                    source += "ESX_VI__TEMPLATE__LIST__SERIALIZE(%s)\n\n" \
                              % self.name
926

927
        # deserialize
928 929 930 931 932
        if self.extended_by is None:
            if self.features & Object.FEATURE__DESERIALIZE:
                source += "/* esxVI_%s_Deserialize */\n" % self.name
                source += "ESX_VI__TEMPLATE__DESERIALIZE(%s,\n" % self.name
                source += "{\n"
933

934
                source += self.generate_deserialize_code()
935

936
                source += "})\n\n"
937

938 939
                if self.features & Object.FEATURE__LIST:
                    source += "/* esxVI_%s_DeserializeList */\n" % self.name
940 941
                    source += "ESX_VI__TEMPLATE__LIST__DESERIALIZE(%s)\n\n" \
                              % self.name
942 943 944
        else:
            if self.features & Object.FEATURE__DESERIALIZE:
                source += "/* esxVI_%s_Deserialize */\n" % self.name
945 946
                source += "ESX_VI__TEMPLATE__DYNAMIC_DESERIALIZE(%s,\n" \
                          % self.name
947 948
                source += "{\n"

949
                source += self.generate_dispatch('DESERIALIZE')
950 951 952 953 954 955 956 957 958 959

                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
960 961
                    source += "ESX_VI__TEMPLATE__LIST__DESERIALIZE(%s)\n\n" \
                              % self.name
962 963 964 965 966 967 968

        source += "\n\n"

        return source



969
class ManagedObject(Type):
970 971 972 973
    FEATURE__LIST = (1 << 2)


    def __init__(self, name, extends, properties, features=0, extended_by=None):
974
        Type.__init__(self, "struct", name)
975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990
        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_struct_members(self, add_banner=False, struct_gap=False):
        members = ""

        if struct_gap:
            members += "\n"

        if self.extends is not None:
991 992
            members += managed_objects_by_name[self.extends] \
                       .generate_struct_members(add_banner=True) + "\n"
993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005

        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


1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025
    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:
                source += managed_objects_by_name[extended_by] \
                          .generate_dispatch(suffix, False)

        return source


1026 1027
    def generate_free_code(self, add_banner=False):
        source = ""
1028

1029
        if self.extends is not None:
1030 1031
            source += managed_objects_by_name[self.extends] \
                      .generate_free_code(add_banner=True) + "\n"
1032

1033 1034
        if self.extends is not None or add_banner:
            source += "    /* %s */\n" % self.name
1035

1036 1037 1038 1039
        if len(self.properties) < 1:
            source += "    /* no properties */\n"
        else:
            string = ""
1040

1041 1042
            for property in self.properties:
                string += property.generate_free_code()
1043

1044 1045 1046 1047
            if len(string) < 1:
                source += "    /* no properties to be freed */\n"
            else:
                source += string
1048

1049
        return source
1050

1051

1052 1053 1054 1055
    def generate_validate_code(self, add_banner=False):
        source = ""

        if self.extends is not None:
1056 1057
            source += managed_objects_by_name[self.extends] \
                      .generate_validate_code(add_banner=True) + "\n"
1058 1059 1060 1061 1062 1063 1064 1065

        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 = ""
1066

1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081
            for property in self.properties:
                string += property.generate_validate_code(managed=True)

            if len(string) < 1:
                source += "    /* no required properties */\n"
            else:
                source += string

        return source


    def generate_lookup_code1(self, add_banner=False):
        source = ""

        if self.extends is not None:
1082 1083
            source += managed_objects_by_name[self.extends] \
                      .generate_lookup_code1(add_banner=True) + "\n"
1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107

        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:
1108 1109
            source += managed_objects_by_name[self.extends] \
                      .generate_lookup_code2(add_banner=True) + "\n"
1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130

        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_comment(self):
1131
        comment = separator
1132 1133 1134 1135 1136 1137 1138 1139 1140 1141
        comment += " * VI Managed Object: %s\n" % self.name

        if self.extends is not None:
            comment += " *                    extends %s\n" % self.extends

        first = True

        if self.extended_by is not None:
            for extended_by in self.extended_by:
                if first:
1142 1143
                    comment += " *                    extended by %s\n" \
                               % extended_by
1144 1145
                    first = False
                else:
1146 1147
                    comment += " *                                %s\n" \
                               % extended_by
1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160

        comment += " */\n\n"

        return comment


    def generate_header(self):
        header = self.generate_comment()

        # struct
        header += "struct _esxVI_%s {\n" % self.name

        if self.features & Object.FEATURE__LIST:
1161 1162
            header += aligned("    esxVI_%s *_next; " % self.name,
                              "/* optional */\n")
1163
        else:
1164 1165
            header += aligned("    esxVI_%s *_unused; " % self.name,
                              "/* optional */\n")
1166 1167

        header += aligned("    esxVI_Type _type; ", "/* required */\n")
1168 1169
        header += aligned("    esxVI_ManagedObjectReference *_reference; ",
                          "/* required */\n")
1170 1171 1172 1173 1174 1175 1176 1177
        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)
1178 1179 1180
        header += ("int esxVI_%s_Validate(esxVI_%s *item, "
                                         "esxVI_String *selectedPropertyNameList);\n") \
                  % (self.name, self.name)
1181 1182

        if self.features & Object.FEATURE__LIST:
1183 1184
            header += "int esxVI_%s_AppendToList(esxVI_%s **list, esxVI_%s *item);\n" \
                      % (self.name, self.name, self.name)
1185 1186 1187 1188 1189 1190 1191 1192 1193 1194

        header += "\n\n\n"

        return header


    def generate_helper_header(self):
        header = ""

        # functions
1195 1196 1197 1198 1199 1200 1201
        header += ("int esxVI_Lookup%s(esxVI_Context *ctx, "
                                      "const char *name, "
                                      "esxVI_ManagedObjectReference *root, "
                                      "esxVI_String *selectedPropertyNameList, "
                                      "esxVI_%s **item, "
                                      "esxVI_Occurrence occurrence);\n") \
                  % (self.name, self.name)
1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222

        header += "\n"

        return header


    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
        if self.extended_by is None:
            source += "/* esxVI_%s_Free */\n" % self.name
            source += "ESX_VI__TEMPLATE__FREE(%s,\n" % self.name
            source += "{\n"

            if self.features & ManagedObject.FEATURE__LIST:
                if self.extends is not None:
1223 1224 1225 1226
                    # 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)
1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241
                    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"
        else:
            source += "/* esxVI_%s_Free */\n" % self.name
            source += "ESX_VI__TEMPLATE__DYNAMIC_FREE(%s,\n" % self.name
            source += "{\n"

1242
            source += self.generate_dispatch('FREE')
1243 1244 1245 1246

            source += "},\n"
            source += "{\n"

1247
            if self.features & ManagedObject.FEATURE__LIST:
1248
                if self.extends is not None:
1249 1250 1251 1252
                    # 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)
1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302
                    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):
        source = ""

        # lookup
        source += "/* esxVI_Lookup%s */\n" % self.name
        source += "ESX_VI__TEMPLATE__LOOKUP(%s,\n" % self.name
        source += "{\n"

        source += self.generate_lookup_code1()

        source += "},\n"
        source += "{\n"

        source += self.generate_lookup_code2()

        source += "})\n\n"

        source += "\n\n"

        return source
1303

1304

1305

1306
class Enum(Type):
M
Matthias Bolte 已提交
1307 1308 1309 1310 1311 1312
    FEATURE__ANY_TYPE = (1 << 1)
    FEATURE__SERIALIZE = (1 << 2)
    FEATURE__DESERIALIZE = (1 << 3)


    def __init__(self, name, values, features=0):
1313
        Type.__init__(self, "enum", name)
M
Matthias Bolte 已提交
1314
        self.values = values
1315
        self.features = features
1316

1317

1318
    def generate_header(self):
1319
        header = separator
1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333
        header += " * VI Enum: %s\n" % self.name
        header += " */\n\n"

        # enum
        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:
1334 1335 1336
            header += ("int esxVI_%s_CastFromAnyType(esxVI_AnyType *anyType, "
                                                    "esxVI_%s *item);\n") \
                      % (self.name, self.name)
1337 1338

        if self.features & Enum.FEATURE__SERIALIZE:
1339 1340 1341
            header += ("int esxVI_%s_Serialize(esxVI_%s item, const char *element, "
                                              "virBufferPtr output);\n") \
                      % (self.name, self.name)
1342 1343

        if self.features & Enum.FEATURE__DESERIALIZE:
1344 1345 1346
            header += ("int esxVI_%s_Deserialize(xmlNodePtr node, "
                                                "esxVI_%s *item);\n") \
                      % (self.name, self.name)
1347 1348 1349 1350 1351

        header += "\n\n\n"

        return header

1352

1353
    def generate_source(self):
1354
        source = separator
1355 1356 1357
        source += " * VI Enum: %s\n" % self.name
        source += " */\n\n"

1358 1359
        source += "static const esxVI_Enumeration _esxVI_%s_Enumeration = {\n" \
                  % self.name
1360 1361 1362
        source += "    esxVI_Type_%s, {\n" % self.name

        for value in self.values:
1363 1364
            source += "        { \"%s\", esxVI_%s_%s },\n" \
                      % (value, self.name, capitalize_first(value))
1365 1366 1367 1368 1369 1370 1371 1372

        source += "        { NULL, -1 },\n"
        source += "    },\n"
        source += "};\n\n"

        # functions
        if self.features & Enum.FEATURE__ANY_TYPE:
            source += "/* esxVI_%s_CastFromAnyType */\n" % self.name
1373 1374
            source += "ESX_VI__TEMPLATE__ENUMERATION__CAST_FROM_ANY_TYPE(%s)\n\n" \
                      % self.name
1375 1376 1377

        if self.features & Enum.FEATURE__SERIALIZE:
            source += "/* esxVI_%s_Serialize */\n" % self.name
1378 1379
            source += "ESX_VI__TEMPLATE__ENUMERATION__SERIALIZE(%s)\n\n" \
                      % self.name
1380 1381 1382

        if self.features & Enum.FEATURE__DESERIALIZE:
            source += "/* esxVI_%s_Deserialize */\n" % self.name
1383 1384
            source += "ESX_VI__TEMPLATE__ENUMERATION__DESERIALIZE(%s)\n\n" \
                      % self.name
1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403

        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):
1404
    # expected format: [managed] object <name> [extends <name>]
1405
    header_items = block[0][1].split()
1406 1407 1408 1409 1410
    managed = False

    if header_items[0] == "managed":
        managed = True
        del header_items[0]
1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434

    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])

1435
        if items[2] not in valid_occurrences:
1436 1437
            report_error("line %d: invalid occurrence" % line[0])

M
Matthias Bolte 已提交
1438 1439
        properties.append(Property(type=items[0], name=items[1],
                                   occurrence=items[2]))
1440

1441 1442 1443 1444
    if managed:
        return ManagedObject(name=name, extends=extends, properties=properties)
    else:
        return Object(name=name, extends=extends, properties=properties)
1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464



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])

M
Matthias Bolte 已提交
1465
    return Enum(name=name, values=values)
1466 1467 1468



1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484
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:
M
Matthias Bolte 已提交
1485 1486
            returns = Parameter(type=header_items[3], name="output",
                                occurrence=header_items[4])
1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499

    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])

M
Matthias Bolte 已提交
1500 1501
        parameters.append(Parameter(type=items[0], name=items[1],
                                    occurrence=items[2]))
1502

M
Matthias Bolte 已提交
1503
    return Method(name=name, parameters=parameters, returns=returns)
1504 1505 1506



1507 1508 1509 1510
def is_known_type(type):
    return type in predefined_objects or \
           type in predefined_enums or \
           type in objects_by_name or \
1511
           type in managed_objects_by_name or \
1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528
           type in enums_by_name



def open_and_print(filename):
    if filename.startswith("./"):
        print "  GEN    " + filename[2:]
    else:
        print "  GEN    " + filename

    return open(filename, "wb")



predefined_enums = ["Boolean"]

predefined_objects = ["AnyType",
A
Ata E Husain Bohra 已提交
1529
                      "Byte",
1530 1531 1532 1533
                      "Int",
                      "Long",
                      "String",
                      "DateTime",
1534
                      "MethodFault",
1535 1536 1537 1538 1539 1540
                      "ManagedObjectReference"]

additional_enum_features = { "ManagedEntityStatus"      : Enum.FEATURE__ANY_TYPE,
                             "TaskInfoState"            : Enum.FEATURE__ANY_TYPE,
                             "VirtualMachinePowerState" : Enum.FEATURE__ANY_TYPE }

1541
additional_object_features = { "AutoStartDefaults"          : Object.FEATURE__ANY_TYPE,
1542
                               "AutoStartPowerInfo"         : Object.FEATURE__ANY_TYPE,
1543 1544 1545 1546 1547
                               "DatastoreHostMount"         : Object.FEATURE__DEEP_COPY |
                                                              Object.FEATURE__LIST |
                                                              Object.FEATURE__ANY_TYPE,
                               "DatastoreInfo"              : Object.FEATURE__ANY_TYPE |
                                                              Object.FEATURE__DYNAMIC_CAST,
1548
                               "HostConfigManager"          : Object.FEATURE__ANY_TYPE,
1549 1550 1551 1552
                               "HostCpuIdInfo"              : Object.FEATURE__LIST |
                                                              Object.FEATURE__ANY_TYPE,
                               "HostDatastoreBrowserSearchResults" : Object.FEATURE__LIST |
                                                              Object.FEATURE__ANY_TYPE,
1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567
                               "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,
M
Matthias Bolte 已提交
1568 1569 1570 1571 1572
                               "HostPortGroup"              : Object.FEATURE__LIST |
                                                              Object.FEATURE__ANY_TYPE,
                               "HostVirtualSwitch"          : Object.FEATURE__DEEP_COPY |
                                                              Object.FEATURE__LIST |
                                                              Object.FEATURE__ANY_TYPE,
1573
                               "ManagedObjectReference"     : Object.FEATURE__ANY_TYPE,
1574
                               "ObjectContent"              : Object.FEATURE__DEEP_COPY,
M
Matthias Bolte 已提交
1575 1576 1577
                               "PhysicalNic"                : Object.FEATURE__DEEP_COPY |
                                                              Object.FEATURE__LIST |
                                                              Object.FEATURE__ANY_TYPE,
1578
                               "ResourcePoolResourceUsage"  : Object.FEATURE__ANY_TYPE,
1579 1580 1581 1582
                               "ScsiLun"                    : Object.FEATURE__LIST |
                                                              Object.FEATURE__ANY_TYPE |
                                                              Object.FEATURE__DEEP_COPY,
                               "ScsiLunDurableName"         : Object.FEATURE__LIST,
1583
                               "ServiceContent"             : Object.FEATURE__DESERIALIZE,
1584
                               "SharesInfo"                 : Object.FEATURE__ANY_TYPE,
1585 1586
                               "TaskInfo"                   : Object.FEATURE__LIST |
                                                              Object.FEATURE__ANY_TYPE,
1587
                               "UserSession"                : Object.FEATURE__ANY_TYPE,
1588
                               "VirtualMachineQuestionInfo" : Object.FEATURE__ANY_TYPE,
1589 1590
                               "VirtualMachineSnapshotTree" : Object.FEATURE__DEEP_COPY |
                                                              Object.FEATURE__ANY_TYPE,
1591
                               "VmEventArgument"            : Object.FEATURE__DESERIALIZE }
1592

1593
removed_object_features = {}
1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605



if "srcdir" in os.environ:
    input_filename = os.path.join(os.environ["srcdir"], "esx/esx_vi_generator.input")
    output_dirname = os.path.join(os.environ["srcdir"], "esx")
else:
    input_filename = os.path.join(os.getcwd(), "esx_vi_generator.input")
    output_dirname = os.getcwd()



1606 1607 1608 1609 1610 1611 1612 1613
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"))
1614
methods_macro = open_and_print(os.path.join(output_dirname, "esx_vi_methods.generated.macro"))
1615 1616
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"))
1617 1618 1619 1620 1621



number = 0
objects_by_name = {}
1622
managed_objects_by_name = {}
1623
enums_by_name = {}
1624
methods_by_name = {}
1625 1626 1627 1628
block = None



1629
# parse input file
1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640
for line in file(input_filename, "rb").readlines():
    number += 1

    if "#" in line:
        line = line[:line.index("#")]

    line = line.lstrip().rstrip()

    if len(line) < 1:
        continue

1641 1642
    if line.startswith("object") or line.startswith("managed object") or \
       line.startswith("enum") or line.startswith("method"):
1643 1644 1645 1646 1647 1648 1649 1650 1651 1652
        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
1653 1654 1655
            elif block[0][1].startswith("managed object"):
                obj = parse_object(block)
                managed_objects_by_name[obj.name] = obj
1656
            elif block[0][1].startswith("enum"):
1657 1658
                enum = parse_enum(block)
                enums_by_name[enum.name] = enum
1659 1660 1661
            else:
                method = parse_method(block)
                methods_by_name[method.name] = method
1662 1663 1664 1665 1666 1667 1668

            block = None
        else:
            block.append((number, line))



1669 1670 1671 1672 1673 1674 1675 1676 1677 1678
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
1679
            objects_by_name[parameter.type].candidate_for_dynamic_cast = True
1680

1681 1682 1683 1684 1685 1686 1687 1688 1689
        # 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

1690 1691 1692 1693 1694 1695
    # 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
1696
            objects_by_name[method.returns.type].candidate_for_dynamic_cast = True
1697

1698 1699 1700 1701 1702 1703 1704 1705 1706
        # 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

1707 1708


1709 1710 1711 1712 1713
for enum in enums_by_name.values():
    # apply additional features
    if enum.name in additional_enum_features:
        enum.features |= additional_enum_features[enum.name]

1714 1715 1716
        if additional_enum_features[enum.name] & Enum.FEATURE__ANY_TYPE:
            enum.features |= Enum.FEATURE__DESERIALIZE

1717 1718 1719 1720


for obj in objects_by_name.values():
    for property in obj.properties:
1721
        if property.occurrence != OCCURRENCE__IGNORED and \
1722
           not is_known_type(property.type):
1723 1724
            report_error("object '%s' contains unknown property type '%s'"
                         % (obj.name, property.type))
1725 1726 1727

    if obj.extends is not None:
        if not is_known_type(obj.extends):
1728 1729
            report_error("object '%s' extends unknown object '%s'"
                         % (obj.name, obj.extends))
1730 1731

    for property in obj.properties:
1732 1733 1734
        if not property.is_type_generated():
            continue

1735 1736 1737 1738 1739 1740
        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
1741 1742 1743 1744 1745 1746 1747
        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
1748 1749 1750 1751 1752

    # apply/remove additional features
    if obj.name in additional_object_features:
        obj.features |= additional_object_features[obj.name]

1753 1754 1755
        if additional_object_features[obj.name] & Object.FEATURE__ANY_TYPE:
            obj.features |= Object.FEATURE__DESERIALIZE

1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766
    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)
1767
            extended_obj.extended_by.sort()
1768 1769 1770



1771 1772 1773 1774 1775 1776 1777 1778 1779
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



1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853
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)



1854 1855 1856 1857
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):
1858 1859
            report_error("object '%s' contains unknown property type '%s'"
                         % (obj.name, property.type))
1860 1861 1862

    if obj.extends is not None:
        if not is_known_type(obj.extends):
1863 1864
            report_error("object '%s' extends unknown object '%s'"
                         % (obj.name, obj.extends))
1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877

    # 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()



1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890
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)
1891 1892


1893

1894
# output enums
1895
types_typedef.write(separator +
1896 1897
                    " * VI Enums\n" +
                    " */\n\n")
1898 1899 1900 1901 1902

names = enums_by_name.keys()
names.sort()

for name in names:
1903 1904 1905 1906 1907 1908
    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())
1909 1910 1911



1912 1913
# output objects
types_typedef.write("\n\n\n" +
1914
                    separator +
1915
                    " * VI Objects\n" +
1916 1917 1918 1919
                    " */\n\n")
types_typeenum.write("\n")
types_typetostring.write("\n")
types_typefromstring.write("\n")
1920

1921 1922
names = objects_by_name.keys()
names.sort()
1923

1924 1925 1926 1927 1928 1929 1930
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())
1931 1932 1933



1934 1935
# output managed objects
types_typedef.write("\n\n\n" +
1936
                    separator +
1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955
                    " * VI Managed Objects\n" +
                    " */\n\n")
types_typeenum.write("\n")
types_typetostring.write("\n")
types_typefromstring.write("\n")

names = managed_objects_by_name.keys()
names.sort()

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())



1956 1957 1958
# output methods
names = methods_by_name.keys()
names.sort()
1959 1960

for name in names:
1961 1962
    methods_header.write(methods_by_name[name].generate_header())
    methods_source.write(methods_by_name[name].generate_source())
1963

1964 1965
names = list(autobind_names)
names.sort()
1966

1967
for name in names:
1968 1969 1970 1971 1972 1973
    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)

1974 1975 1976 1977 1978 1979 1980 1981 1982


# output helpers
names = managed_objects_by_name.keys()
names.sort()

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())