class ModuleGenerator: # Class initializer def __init__(self, model, baseName, noid, friendlyName, actionLocation, bGenerateDOMSchemas, bGenerateMethods, bClient, bADIReport): self._model = model # Options self._baseName = baseName self._noid = noid self._friendlyName = friendlyName self._bGenerateMethods = bGenerateMethods self._bADIReport = bADIReport # Generator state self._out = None # Module self._module = HDKModule(model, baseName, actionLocation, bGenerateDOMSchemas) # Generation options self._bGenerateActions = not bClient and self._module.actions self._bGenerateServices = not bClient and self._module.services self._bGenerateModule = self._module.actions or self._module.events self._bGenerateModuleDynamic = not bClient and self._bGenerateModule # # Generate code # def generate(self, dir, fhReport): for file, fn, bGenerate in \ [(os.path.join(dir, self._module.filename('.h')), self._generate_h, not self._bGenerateMethods), (os.path.join(dir, self._module.filename('.c')), self._generate_c, not self._bGenerateMethods), (os.path.join(dir, self._module.filename('_methods.c')), self._generate_methods_c, self._bGenerateMethods), (os.path.join(dir, self._module.filename('_adi.txt')), self._generate_adi_txt, self._bADIReport)]: if bGenerate: if fhReport is not None: print >> fhReport, 'Generating "%s" ...' % file self._out = open(file, "w") try: fn() except: raise finally: self._out.close() # # Output helper methods # # Output def _write(self, s): self._out.write(s) # Write .c file header def _write_header_c(self): self._write('''\ /* * Copyright (c) 2008-2010 Cisco Systems, Inc. All rights reserved. * * Cisco Systems, Inc. retains all right, title and interest (including all * intellectual property rights) in and to this computer program, which is * protected by applicable intellectual property laws. Unless you have obtained * a separate written license from Cisco Systems, Inc., you are not authorized * to utilize all or a part of this computer program for any purpose (including * reproduction, distribution, modification, and compilation into object code), * and you must immediately destroy or return to Cisco Systems, Inc. all copies * of this computer program. If you are licensed by Cisco Systems, Inc., your * rights to utilize this computer program are limited by the terms of that * license. To obtain a license, please contact Cisco Systems, Inc. * * This computer program contains trade secrets owned by Cisco Systems, Inc. * and, unless unauthorized by Cisco Systems, Inc. in writing, you agree to * maintain the confidentiality of this computer program and related information * and to not disclose this computer program and related information to any * other person or entity. * * THIS COMPUTER PROGRAM IS PROVIDED AS IS WITHOUT ANY WARRANTIES, AND CISCO * SYSTEMS, INC. EXPRESSLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, * INCLUDING THE WARRANTIES OF MERCHANTIBILITY, FITNESS FOR A PARTICULAR * PURPOSE, TITLE, AND NONINFRINGEMENT. */ ''') # Write .h file header def _write_header_h(self): self._write_header_c() self._write('''\ #ifndef %s #define %s ''' % (self._module.header_sentinel('.h'), self._module.header_sentinel('.h'))) # Write .h file footer def _write_footer_h(self): self._write('''\ #endif /* %s */ ''' % (self._module.header_sentinel('.h'))) # Write a section comment def _write_section(self, comment): self._write('''\ /* * %s */ ''' % (comment)) # Write enumeration definition def _write_enumeration(self, name, values, ix_start=0, ix_delta=1, value_symbols={}): # Enum header self._write('''\ typedef enum _%s { ''' % (name)) # Write enum values ix_value = ix_start ix_value_last = ix_start + ix_delta * (len(values) - 1) sep = "," for value in values: # Does the value have a symbol? if value_symbols.has_key(value): str_value = value_symbols[value] else: str_value = str(ix_value) # Don't separate the last value if ix_value == ix_value_last: sep = "" # Write the enum value self._write('''\ %s = %s%s ''' % (value, str_value, sep)) ix_value += ix_delta # Enum footer self._write('''\ } %s; ''' % (name)) # Write schema definition def _write_schema(self, schema_nodes_static, schema_static, nodes, element_path_static=None, element_path=None): # Schema nodes header self._write('''\ static const HDK_XML_SchemaNode %s[] = { ''' % (schema_nodes_static)) # Write the schema nodes ix = 0 for node in nodes: # Compute the parent index if node.parent: ix_parent = nodes.index(node.parent) else: ix_parent = 0 # Compute the options options = [] if node.is_optional: options.append("HDK_XML_SchemaNodeProperty_Optional") if node.is_unbounded: options.append("HDK_XML_SchemaNodeProperty_Unbounded") if node.is_any_element: options.append("HDK_XML_SchemaNodeProperty_AnyElement") if node.is_error: options.append("HDK_XML_SchemaNodeProperty_ErrorOutput") if node.is_csv: options.append("HDK_XML_SchemaNodeProperty_CSV") if options: options = " | ".join(options) else: options = "0" # Write the schema node self._write('''\ /* %d */ { %d, %s, %s, %s }, ''' % (ix, ix_parent, self._module.element_value( node.element()), self._module.type_value(node.type), options)) ix += 1 # Schema nodes footer self._write('''\ HDK_XML_Schema_SchemaNodesEnd }; ''') # Schema struct element path if element_path_static and element_path: self._write('''\ static const HDK_XML_Element %s[] = { ''' % (element_path_static)) for element in element_path: self._write('''\ %s, ''' % (self._module.element_value(element))) self._write('''\ HDK_MOD_ElementPathEnd }; ''') # Schema self._write('''\ static const HDK_XML_Schema %s = { s_namespaces, s_elements, %s, %s }; ''' % (schema_static, schema_nodes_static, "s_enumTypes" if self._module.schema.enums else "0")) # Write action definition def _write_action(self, action_loc): http_method, http_location, action, noauth = \ (action_loc.http_method, action_loc.http_location, action_loc.action, action_loc.noauth) # Compute the SOAP action is_get = (http_method.lower() == "get") if is_get: soap_action = "0" else: soap_action = '"' + action.uri + '"' # Compute the action function name if self._bGenerateActions: action_fn = self._module.action_fn(action) else: action_fn = "0" # Compute the schema struct element path symbols if not is_get and self._module.schema.struct_nodes_envelope( action.inputMember, soap=True): input_element_path = self._module.schema_element_path_static( action, "_Input") else: input_element_path = "0" if self._module.schema.struct_nodes_envelope(action.outputMember, soap=True): output_element_path = self._module.schema_element_path_static( action, "_Output") else: output_element_path = "0" # Compute the method options options = [] if noauth: options.append("HDK_MOD_MethodOption_NoBasicAuth") if is_get: options.append("HDK_MOD_MethodOption_NoInputStruct") if options: options = " | ".join(options) else: options = "0" # Compute the OK and REBOOT values result_member = action.outputMember.type.members[0] if "REBOOT" in action.resultEnum.enumValues: result_reboot = "REBOOT" else: result_reboot = "OK" # Write the method struct self._write('''\ { "%s", "%s", %s, %s, &%s, &%s, %s, %s, %s, %s, %s, %s, %s }, ''' % (http_method, http_location, soap_action, action_fn, self._module.schema_static(action, suffix="_Input"), self._module.schema_static(action, suffix="_Output"), input_element_path, output_element_path, options, self._module.element_value( (result_member.namespace, result_member.name)), self._module.type_value(result_member.type), self._module.enum_value(result_member.type, "OK"), self._module.enum_value(result_member.type, result_reboot))) # Write event definition def _write_event(self, event): # Write the method struct self._write('''\ { "%s", &%s }, ''' % (event.uri, self._module.schema_static(event))) # # *.h code generator # def _generate_h(self): # File header self._write_header_h() # Includes self._write('''\ #include "hdk_mod.h" /* * Macro to control public exports */ #ifdef __cplusplus # define %s_PREFIX extern "C" #else # define %s_PREFIX extern #endif #ifdef HDK_MOD_STATIC # define %s %s_PREFIX #else /* ndef HDK_MOD_STATIC */ # ifdef _MSC_VER # ifdef %s # define %s %s_PREFIX __declspec(dllexport) # else # define %s %s_PREFIX __declspec(dllimport) # endif # else /* ndef _MSC_VER */ # ifdef %s # define %s %s_PREFIX __attribute__ ((visibility("default"))) # else # define %s %s_PREFIX # endif # endif /*def _MSC_VER */ #endif /* def HDK_MOD_STATIC */ ''' % (self._module.export_macro(), self._module.export_macro(), self._module.export_macro(), self._module.export_macro(), self._module.build_macro(), self._module.export_macro(), self._module.export_macro(), self._module.export_macro(), self._module.export_macro(), self._module.build_macro(), self._module.export_macro(), self._module.export_macro(), self._module.export_macro(), self._module.export_macro())) # Element enumeration self._write_section("Elements") self._write_enumeration(self._module.element_enum(), [ self._module.element_value(element) for element in self._module.schema.elements ]) # Enumeration type definition if self._module.schema.enums: self._write_section("Enum types enumeration") self._write_enumeration(self._module.enum_type_enum(), [ self._module.enum_type_value(enum) for enum in self._module.schema.enums ], ix_start=-1, ix_delta=-1) # Enumeration declarations for enum in self._module.schema.enums: # Enumeration type definition self._write_section("Enumeration %s" % (enum.uri)) value_unknown = self._module.enum_value(enum, None, is_unknown=True) values = [value_unknown] values.extend([ self._module.enum_value(enum, value) for value in enum.enumValues ]) self._write_enumeration( self._module.enum_enum(enum), values, ix_start=-1, value_symbols={value_unknown: "HDK_XML_Enum_Unknown"}) # Enumeration accessor declarations self._write('''\ #define %s(pStruct, element, value) HDK_XML_Set_Enum(pStruct, element, %s, 0 ? %s : (value)) #define %s(pStruct, element, value) HDK_XML_Append_Enum(pStruct, element, %s, 0 ? %s : (value)) #define %s(pStruct, element) (%s*)HDK_XML_Get_Enum(pStruct, element, %s) #define %s(pStruct, element, value) (%s)HDK_XML_GetEx_Enum(pStruct, element, %s, 0 ? %s : (value)) #define %s(pMember) (%s*)HDK_XML_GetMember_Enum(pMember, %s) ''' % (self._module.enum_accessor(enum, "Set"), self._module.enum_type_value(enum), self._module.enum_value( enum, enum.enumValues[0]), self._module.enum_accessor( enum, "Append"), self._module.enum_type_value(enum), self._module.enum_value( enum, enum.enumValues[0]), self._module.enum_accessor(enum, "Get"), self._module.enum_enum(enum), self._module.enum_type_value(enum), self._module.enum_accessor(enum, "GetEx"), self._module.enum_enum(enum), self._module.enum_type_value(enum), self._module.enum_value(enum, enum.enumValues[0]), self._module.enum_accessor(enum, "GetMember"), self._module.enum_enum(enum), self._module.enum_type_value(enum))) # Action enumeration if self._module.actions: self._write_section("Method enumeration") self._write_enumeration(self._module.action_enum(), [ self._module.action_value(action_loc) for action_loc in self._module.action_locations() ]) # Action sentinels if self._bGenerateActions: self._write_section("Method sentinels") for action in self._module.actions: self._write('''\ #define %s ''' % (self._module.action_sentinel(action))) # Action declarations if self._bGenerateActions: self._write_section("Methods") for action in self._module.actions: self._write('''\ extern void %s(HDK_MOD_MethodContext* pMethodCtx, HDK_XML_Struct* pInput, HDK_XML_Struct* pOutput); ''' % (self._module.action_fn(action))) # Event enumeration if self._module.events: self._write_section("Event enumeration") self._write_enumeration(self._module.event_enum(), [ self._module.event_value(event) for event in self._module.events ]) # DOM (struct) schema accessor declarations if self._module.schema.structs: self._write_section("DOM Schemas") for struct in self._module.schema.structs: self._write('''\ %s const HDK_XML_Schema* %s(); ''' % (self._module.export_macro(), self._module.dom_schema_fn(struct))) # State declarations if self._module.states: self._write_section("ADI") self._write_enumeration(self._module.state_enum(), [ self._module.state_value(state) for state in self._module.states ], ix_start=1) self._write_section("ADI sentinels") for state in self._module.states: # Determine get/set usages = {} for actionState in self._model.actionStates: if state.uri in actionState.stateMembers: stateMember = actionState.stateMembers[state.uri] if stateMember.isGet: usages["get"] = None if stateMember.isSet: usages["set"] = None for usage in sorted(usages.iterkeys()): self._write('''\ #define %s ''' % (self._module.state_value_sentinel(state, usage))) # Module declaration if self._bGenerateModule: self._write_section("Module") self._write('''\ %s const HDK_MOD_Module* %s(void); ''' % (self._module.export_macro(), self._module.module_fn())) if self._bGenerateModuleDynamic: self._write('''\ /* Dynamic server module export */ %s const HDK_MOD_Module* HDK_SRV_Module(void); ''' % (self._module.export_macro())) # File footer self._write_footer_h() # # *.c code generator # def _generate_c(self): # File header self._write_header_c() self._write('''\ #include "%s" #include <string.h> ''' % (self._module.filename('.h'))) # Namespace table self._write_section("Namespaces") self._write('''\ static const HDK_XML_Namespace s_namespaces[] = { ''') for namespace in self._module.schema.namespaces: self._write('''\ /* %d */ "%s", ''' % (self._module.schema.namespace_index(namespace), namespace)) self._write('''\ HDK_XML_Schema_NamespacesEnd }; ''') # Elements table self._write_section("Elements") self._write('''\ static const HDK_XML_ElementNode s_elements[] = { ''') for element in self._module.schema.elements: self._write('''\ /* %s = %d */ { %d, "%s" }, ''' % (self._module.element_value(element), self._module.schema.element_index(element), self._module.schema.namespace_index(element[0]), element[1])) self._write('''\ HDK_XML_Schema_ElementsEnd }; ''') # Enumerations definitions for enum in self._module.schema.enums: # Enumeration string table self._write_section("Enumeration %s" % (enum.uri)) self._write('''\ static const HDK_XML_EnumValue %s[] = { ''' % (self._module.enum_type_strings_static(enum))) for value in enum.enumValues: self._write('''\ "%s", ''' % (value)) self._write('''\ HDK_XML_Schema_EnumTypeValuesEnd }; ''') # Enum types array if self._module.schema.enums: self._write_section("Enumeration types array") self._write('''\ static const HDK_XML_EnumType s_enumTypes[] = { ''') sep = ',' for enum in self._module.schema.enums: if enum is self._module.schema.enums[-1]: sep = "" self._write('''\ %s%s ''' % (self._module.enum_type_strings_static(enum), sep)) self._write('''\ }; ''') # Action definitions for action in self._module.actions: self._write_section("Method %s" % (action.uri)) # Input schema self._write_schema( self._module.schema_nodes_static(action, suffix="_Input"), self._module.schema_static(action, suffix="_Input"), self._module.schema.struct_nodes(action.inputMember, soap=True), element_path_static=self._module.schema_element_path_static( action, suffix="_Input"), element_path=self._module.schema.struct_nodes_envelope( action.inputMember, soap=True)) # Output schema self._write('''\ ''') self._write_schema( self._module.schema_nodes_static(action, suffix="_Output"), self._module.schema_static(action, suffix="_Output"), self._module.schema.struct_nodes(action.outputMember, soap=True), element_path_static=self._module.schema_element_path_static( action, suffix="_Output"), element_path=self._module.schema.struct_nodes_envelope( action.outputMember, soap=True)) # Actions table if self._module.actions: self._write_section("Methods") # Actions table header self._write('''\ static const HDK_MOD_Method s_methods[] = { ''') # Write each action node for action_loc in self._module.action_locations(): self._write_action(action_loc) # Actions table footer self._write('''\ HDK_MOD_MethodsEnd }; ''') # Event definitions for event in self._module.events: self._write_section("Event %s" % (event.uri)) self._write_schema(self._module.schema_nodes_static(event), self._module.schema_static(event), self._module.schema.struct_nodes(event.member)) # Events table if self._module.events: self._write_section("Events") # Events table header self._write('''\ static const HDK_MOD_Event s_events[] = { ''') # Write each event node for event in self._module.events: self._write_event(event) # Events table footer self._write('''\ HDK_MOD_EventsEnd }; ''') if self._bGenerateServices: # Services action tables self._write_section("Service Methods") for service in self._module.services: # Service actions header self._write('''\ static const HDK_MOD_Method* %s[] = { ''' % (self._module.service_actions_name(service))) # Service actions for action_uri in service.actions: action_loc = [ a for a in self._module.action_locations() if a.action.uri == action_uri ][0] self._write('''\ &s_methods[%s], ''' % (self._module.action_value(action_loc))) # Service actions footer self._write('''\ 0 }; ''') # Services event tables self._write_section("Service Events") for service in self._module.services: # Service events header self._write('''\ static const HDK_MOD_Event* %s[] = { ''' % (self._module.service_events_name(service))) # Service events for eventURI in service.events: event = [ e for e in self._module.events if e.uri == eventURI ][0] self._write('''\ &s_events[%s], ''' % (self._module.event_value(event))) # Service events footer self._write('''\ 0 }; ''') # Services table self._write_section("Services") # Services table header self._write('''\ static const HDK_MOD_Service s_services[] = { ''') # Write each service node for service in self._module.services: self._write('''\ { "%s", %s, %s }, ''' % (service.uri, self._module.service_actions_name(service), self._module.service_events_name(service))) # Services table footer self._write('''\ HDK_MOD_ServicesEnd }; ''') # State definitions if self._module.states: self._write_section("ADI") self._write_schema("s_schemaNodes_ADI", "s_schema_ADI", self._module.schema.state_nodes()) # Struct schema definitions for struct in self._module.schema.structs: self._write_section("Struct %s" % (struct.uri)) self._write_schema(self._module.schema_nodes_static(struct), self._module.schema_static(struct), self._module.schema.struct_nodes(struct)) self._write('''\ /* extern */ const HDK_XML_Schema* %s() { return &%s; } ''' % (self._module.dom_schema_fn(struct), self._module.schema_static(struct))) # Module definition if self._bGenerateModule: self._write_section("Module") # Network Object ID definition if self._noid is not None: self._write('''\ /* %s */ static const HDK_XML_UUID s_uuid_NOID = { { %s } }; ''' % (self._noid, ", ".join( ["0x%02x" % ord(byte) for byte in self._noid.bytes]))) # Module definition and accessors self._write('''\ static const HDK_MOD_Module s_module = { %s, %s, %s, %s, %s, %s }; const HDK_MOD_Module* %s(void) { return &s_module; } ''' % ("&s_uuid_NOID" if self._noid else "0", '"' + self._friendlyName + '"' if self._friendlyName else "0", "s_services" if self._bGenerateServices else "0", "s_methods" if self._module.actions else "0", "s_events" if self._module.events else "0", "&s_schema_ADI" if self._module.states else "0", self._module.module_fn())) if self._bGenerateModuleDynamic: self._write('''\ const HDK_MOD_Module* HDK_SRV_Module(void) { return &s_module; } ''') # # *_methods.c code generator # def _generate_methods_c(self): # File header self._write_header_c() self._write('''\ #include "%s" #include "hdk_srv.h" /* Helper method for HNAP results */ #define SetHNAPResult(pStruct, prefix, method, result) \\ prefix##_Set_##method##Result(pStruct, prefix##_Element_##method##Result, prefix##_Enum_##method##Result_##result) ''' % (self._module.filename('.h'))) # Action declarations for action in self._module.actions: self._write_section("Method %s" % (action.uri)) self._write('''\ #ifdef %s void %s(HDK_MOD_MethodContext* pMethodCtx, HDK_XML_Struct* pInput, HDK_XML_Struct* pOutput) { /* Unused parameters */ (void)pMethodCtx; (void)pInput; (void)pOutput; } #endif /* %s */ ''' % (self._module.action_sentinel(action), self._module.action_fn(action), self._module.action_sentinel(action))) # # *_adi.txt report generator # def _generate_adi_txt(self): # ADI report title self._write('''\ ====================================================================== ADI Report for the %s Module ====================================================================== ''' % (self._baseName.upper())) # Output the ADI values used (show get/set) self._write('''\ ====================================================================== ADI values ====================================================================== ''') for state in self._model.referenced_states(): # Determine get/set usages = {} for actionState in self._model.actionStates: if state.uri in actionState.stateMembers: stateMember = actionState.stateMembers[state.uri] if stateMember.isGet: usages["get"] = None if stateMember.isSet: usages["set"] = None sUsages = ', '.join(sorted(usages.iterkeys())) # Get the base type type = state.type nArray = 0 while type.isArray: nArray += 1 type = type.arrayType sArray = "[]" * nArray # Get the type description sDesc = "" if type.isEnum: sDesc = "enum" elif type.isStruct: sDesc = "struct" # Get the type string if sDesc: sType = '%s%s (%s, "%s")' % (type.name, sArray, sDesc, type.namespace) else: sType = '%s%s' % (type.name, sArray) self._write('''\ %s Namespace: "%s" Name: "%s" Type: %s Usage: %s ''' % (self._module.state_value(state), state.namespace, state.name, sType, sUsages)) # Output the ADI values used by action self._write('''\ ====================================================================== ADI values by action ====================================================================== ''') for actionState in self._model.actionStates: self._write('''\ %s ''' % (actionState.uri)) for stateMember in sorted(actionState.stateMembers.itervalues()): # Determine usage usages = {} if stateMember.isGet: usages["get"] = None if stateMember.isSet: usages["set"] = None sUsages = ', '.join(sorted(usages.iterkeys())) self._write('''\ [%s] %s ''' % (sUsages, self._module.state_value(stateMember.state)))
class CppClientGenerator: # Class initializer def __init__(self, model, baseName, moduleName, actionLocation, fDOM, fInline): self._baseName = baseName self._fDOM = fDOM self._fInline = fInline # Generator state self._out = None self._namespaceStack = [] # The underlying module. self._module = HDKModule(model, moduleName, actionLocation, fDOM) # Type information structTypes = {} arrayTypes = {} enumTypes = {} for type in model.all_types(user_types = fDOM, state_types = False): if type.isArray: arrayTypes[type.uri] = type elif type.isStruct: structTypes[type.uri] = type elif type.isEnum: enumTypes[type.uri] = type self._structTypes = sorted(structTypes.values(), key = lambda x:x.uri) self._arrayTypes = sorted(arrayTypes.values(), key = lambda x:x.uri) self._enumTypes = sorted(enumTypes.values(), key = lambda x:x.uri) # # Generate code # def generate(self, dir, fhReport): # Generate c++ client code for file, fn in [(os.path.join(dir, self._filename('.h')), self._generate_h), (os.path.join(dir, self._filename('.cpp')), self._generate_cpp)]: if fhReport is not None: print >>fhReport, 'Generating "%s" ...' % file self._out = open(file, "w") try: fn() except: raise finally: self._out.close() # # Helpers # # Is the given type a "blob" @staticmethod def is_blob_type(type): return type.name == "blob" @staticmethod def is_bool_type(type): return type.name == "bool" @staticmethod def is_int_type(type): return type.name == "int" @staticmethod def is_long_type(type): return type.name == "long" @staticmethod def is_datetime_type(type): return type.name == "datetime" @staticmethod def is_ipaddress_type(type): return type.name == "IPAddress" @staticmethod def is_macaddress_type(type): return type.name == "MACAddress" @staticmethod def is_string_type(type): return type.name == "string" @staticmethod def is_uuid_type(type): return type.name == "UUID" @staticmethod def is_hnap_result_type(type): return type.name == "Result" # Does the given type support the "blank" value @staticmethod def supports_blank(type): return CppClientGenerator.is_ipaddress_type(type) or CppClientGenerator.is_macaddress_type(type) # Retrieve the HDK_XML_ function to use for the given type and access def _hdk_struct_accessor(self, type, access): if CppClientGenerator.is_datetime_type(type): method = "HDK_XML_" + access + "_DateTime" elif CppClientGenerator.is_macaddress_type(type) or \ CppClientGenerator.is_ipaddress_type(type): method = "HDK_XML_" + access + "_" + type.name elif CppClientGenerator.is_uuid_type(type): method = "HDK_XML_" + access + "_UUID" elif type.isEnum: method = self._module.enum_accessor(type, access) elif type.isStruct: method = "HDK_XML_" + access + "_Struct" else: method = "HDK_XML_" + access + "_" + type.name.capitalize() return method # Retrieve the HDK type cast for the given type def _hdk_type_cast(self, type): if type.isEnum: return "(" + self._module.enum_enum(type) + ")" elif CppClientGenerator.is_bool_type(type): return "(int)" else: return "" # # Symbol helper methods # # Generated code filename def _filename(self, suffix): return self._baseName + suffix # c++ namespace def _namespace(self, uri): ns = re.sub("^\w+:/+(www\.)?", "", uri) ns = re.sub("\.com", "", ns) ns = re.sub("/+HNAPExt", "", ns) ns = re.sub("/+$", "", ns) if ns: ns = ns[0].upper() + ns[1:] return re.sub("[^\w]", "_", ns) # c++ class name def _class_class(self, type): assert(type.isStruct) if type.isArray: match = re.match("ArrayOf(.*)", type.name); return makeGlobalSymbol("", "", match.group(1) + "Array") else: return makeGlobalSymbol("", "", type.name + "Struct") def _class_class_iter(self, type): return self._class_class(type) + "Iter" # c++ class constructor def _class_constructor(self, type): assert(type.isStruct) return self._class_class(type) # c++ class set property method def _class_set_property_method(self, member): return "set_" + member.name # c++ class get property method def _class_get_property_method(self, member): return "get_" + member.name # c++ class from file method def _class_from_file_method(self): return "FromFile" # c++ class to file method def _class_to_file_method(self): return "ToFile" def _type_type(self, type, withNS = False): typeName = None if type.isBuiltin: if CppClientGenerator.is_bool_type(type): typeName = "bool" elif CppClientGenerator.is_int_type(type): typeName = "HDK_XML_Int" elif CppClientGenerator.is_long_type(type): typeName = "HDK_XML_Long" elif CppClientGenerator.is_string_type(type): typeName = "const char*" elif CppClientGenerator.is_datetime_type(type): typeName = "time_t" elif CppClientGenerator.is_ipaddress_type(type): typeName = "IPv4Address" elif CppClientGenerator.is_macaddress_type(type): typeName = "MACAddress" elif CppClientGenerator.is_blob_type(type): typeName = "Blob" elif CppClientGenerator.is_uuid_type(type): typeName = "UUID" elif CppClientGenerator.is_hnap_result_type(type): typeName = type.name if fWithNamespace and self._current_open_namespace() != type.namespace: typeName = self._namespace(type.namespace) + "::" + typeName else: print>>sys.stderr, "Unhandled builtin type %s" % (type.name) typeName = type.name elif type.isStruct: typeName = self._class_class(type) namespace = self._namespace(type.namespace) if namespace and withNS and self._current_open_namespace() != type.namespace: typeName = namespace + "::" + typeName elif type.isEnum: typeName = self._enum_enum(type) if withNS and self._current_open_namespace() != type.namespace: typeName = self._namespace(type.namespace) + "::" + typeName typeName = "enum " + typeName return typeName # c++ type cast def _type_cast(self, type): if type.isEnum: return "(" + self._type_type(type, withNS = True) + ")" elif CppClientGenerator.is_bool_type(type): return "(bool)" else: return "" # c++ enum type def _enum_enum(self, type): return makeGlobalSymbol("", "", type.name) # c++ enum value def _enum_value(self, type, value, bIsUnknown = False): if bIsUnknown: return makeGlobalSymbol(type.name, "", "Unknown") else: return makeGlobalSymbol(type.name, "", value) # c++ action def _action_fn(self, action_loc, withNS = False): (http_method, action) = (action_loc.http_method, action_loc.action) fn = action.name if withNS: fn = self._namespace(action.namespace) + "::" + fn # Non-post action? if http_method != "POST": suffix = "_" + http_method else: suffix = "" return fn + suffix # # Output helper methods # # Output def _write(self, s): self._out.write(s) def _write_newline(self): self._out.write(''' ''') def _write_with_indent(self, s, cIndent, bIndentCPreprocessor = False): indent = cIndent * ' ' for line in s.splitlines(True): if line[0] == '#' and not bIndentCPreprocessor: self._write(line) elif re.search("^\s*$", line): # Don't write unnecessary whitespace self._write(line) else: self._write(indent + line) def _write_with_ns_indent(self, s, extraIndent = 0): self._write_with_indent(s, self._namespace_indent() + extraIndent) def _write_copyright(self): self._write('''\ /* * Copyright (c) 2008-2010 Cisco Systems, Inc. All rights reserved. * * Cisco Systems, Inc. retains all right, title and interest (including all * intellectual property rights) in and to this computer program, which is * protected by applicable intellectual property laws. Unless you have obtained * a separate written license from Cisco Systems, Inc., you are not authorized * to utilize all or a part of this computer program for any purpose (including * reproduction, distribution, modification, and compilation into object code), * and you must immediately destroy or return to Cisco Systems, Inc. all copies * of this computer program. If you are licensed by Cisco Systems, Inc., your * rights to utilize this computer program are limited by the terms of that * license. To obtain a license, please contact Cisco Systems, Inc. * * This computer program contains trade secrets owned by Cisco Systems, Inc. * and, unless unauthorized by Cisco Systems, Inc. in writing, you agree to * maintain the confidentiality of this computer program and related information * and to not disclose this computer program and related information to any * other person or entity. * * THIS COMPUTER PROGRAM IS PROVIDED AS IS WITHOUT ANY WARRANTIES, AND CISCO * SYSTEMS, INC. EXPRESSLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, * INCLUDING THE WARRANTIES OF MERCHANTIBILITY, FITNESS FOR A PARTICULAR * PURPOSE, TITLE, AND NONINFRINGEMENT. */ ''') # Write .cpp file header def _write_header_cpp(self, fileName = ""): self._write_copyright() self._write('''\ // %s - [Generated by hdkcli_cpp] ''' % (fileName)) # Write .h file header def _write_header_h(self, fileName = ""): self._write_copyright() self._write('''\ #pragma once // %s - [Generated by hdkcli_cpp] ''' % (fileName)) # Write .h file footer def _write_footer_h(self): # Namespace stack should be empty now. assert(not self._namespaceStack) # Write the opening of a namespace def _write_open_namespace(self, uri, cIndent): indent = ' ' * cIndent namespace = self._namespace(uri) self._write('''\ %snamespace %s %s{ ''' % (indent, namespace, indent)) # Write the closing of a namespace def _write_close_namespace(self, uri, cIndent): indent = ' ' * cIndent namespace = self._namespace(uri) self._write('''\ %s} // namespace %s ''' % (indent, namespace)) # Generate a class forward declaration def _write_class_forward_declaration(self, type): self._write_with_ns_indent('''\ class %s; ''' % (self._class_class(type))) # Generate an enum definition def _write_enum(self, type, extraIndent = 0): assert(type.isEnum) indent = self._namespace_indent() + extraIndent self._write_doxygen_section_with_ns_indent_begin(extraIndent) self._write_doxygen_string_with_ns_indent('''\ \\enum %s <a>%s</a> ''' % (self._enum_enum(type), type.uri), extraIndent) self._write_doxygen_lines_with_ns_indent(type.doctext, extraIndent) self._write_doxygen_section_with_ns_indent_end(extraIndent) self._write_with_indent('''\ enum %s { %s = %s /*<! Unknown value */, ''' % (self._enum_enum(type), self._enum_value(type, None, True), self._module.enum_value(type, None, True)), indent) for value in type.enumValues[0:-1]: self._write_with_indent('''\ %s = %s /*!< %s */, ''' % (self._enum_value(type, value), self._module.enum_value(type, value), value), indent) if type.enumValues: value = type.enumValues[-1] self._write_with_indent('''\ %s = %s /*!< %s */ ''' % (self._enum_value(type, value), self._module.enum_value(type, value), value), indent) self._write_with_indent('''\ }; // enum %s ''' % (self._enum_enum(type)), indent) # # Doxygen-formatted output helpers # # Doxygen comment prefix. _doxygenPrefix = "///" def _write_doxygen_line_with_ns_indent(self, line, extraIndent = 0): doxygenFormattedLine = CppClientGenerator._doxygenPrefix if line and not re.search("^\s$", line): doxygenFormattedLine += " " + line if not doxygenFormattedLine.endswith("\n"): doxygenFormattedLine += "\n" self._write_with_indent(doxygenFormattedLine, extraIndent + self._namespace_indent()) def _write_doxygen_lines_with_ns_indent(self, lines, extraIndent = 0): for line in lines: self._write_doxygen_line_with_ns_indent(line, extraIndent) def _write_doxygen_string_with_ns_indent(self, s, extraIndent = 0): for line in s.splitlines(True): self._write_doxygen_line_with_ns_indent(line, extraIndent) def _write_doxygen_section_with_ns_indent_begin(self, extraIndent = 0): self._write_doxygen_line_with_ns_indent(None, extraIndent) def _write_doxygen_section_with_ns_indent_end(self, extraIndent = 0): self._write_doxygen_line_with_ns_indent(None, extraIndent) def _write_doxygen_section_with_ns_indent(self, s, extraIndent = 0): self._write_doxygen_section_with_ns_indent_begin(extraIndent) self._write_doxygen_string_with_ns_indent(s, extraIndent) self._write_doxygen_section_with_ns_indent_end(extraIndent) # # Namespace scoping # # Update the current namespace (closing the previous one, if needed) def _push_namespace(self, ns): if self._namespaceStack: if self._namespaceStack[-1].namespace == ns: if self._namespaceStack[-1].needs_closing: self._namespaceStack[-1].increment() return #else: ns::ns. strange... else: if self._namespaceStack[-1].needs_closing: self._write_close_namespace(self._namespaceStack[-1].namespace, (len(self._namespaceStack) - 1) * 4) self._namespaceStack.pop() self._namespaceStack.append(CppNamespaceScope(ns)) self._write_open_namespace(ns, (len(self._namespaceStack) - 1) * 4) def _pop_namespace(self, bAlwaysClose = False): if self._namespaceStack[-1].needs_closing: self._write_close_namespace(self._namespaceStack[-1].namespace, (len(self._namespaceStack) - 1) * 4) self._namespaceStack.pop() if self._namespaceStack: self._namespaceStack[-1].decrement() if bAlwaysClose and self._namespaceStack[-1].needs_closing: self._write_close_namespace(self._namespaceStack[-1].namespace, (len(self._namespaceStack) - 1) * 4) self._namespaceStack.pop() # Namespace indentation def _namespace_indent(self): return len(self._namespaceStack) * 4 # Current open namespace def _current_open_namespace(self): if self._namespaceStack: return self._namespaceStack[-1].namespace else: return None # # Helpers for c++ class wrappers of HDK_XML_Structs # # Generate a default constructor def _write_class_default_constructor(self, struct, element = None, fImpl = False, classScope = None, extraIndent = 0): if element is None: element = "HDK_XML_BuiltinElement_Unknown" method = self._class_constructor(struct) if classScope is not None: method = self._type_type(classScope, withNS = True) + "::" + method self._write_with_ns_indent('''\ %s() throw()''' % (method), extraIndent) if fImpl: self._write(''' :''') self._write_with_ns_indent(''' Struct(%s) { } ''' % (element), extraIndent) else: # not fImpl self._write('''; ''') # Generate a constructor with HDK_XML_Struct def _write_class_hdk_constructor(self, struct, fImpl = False, classScope = None, extraIndent = 0): method = self._class_constructor(struct) if classScope is not None: method = self._type_type(classScope, withNS = True) + "::" + method self._write_with_ns_indent('''\ %s(HDK_XML_Struct* phdkstruct) throw()''' % (method), extraIndent) if fImpl: self._write(''' :''') self._write_with_ns_indent(''' Struct(phdkstruct) { } ''', extraIndent) else: # not fImpl self._write('''; ''') # Generate a get_ accessor implementation. def _write_class_get_accessor(self, member, fImpl = False, classScope = None, extraIndent = 0): element = self._module.element_value((member.namespace, member.name)) method = self._class_get_property_method(member) if classScope is not None: method = self._type_type(classScope, withNS = True) + "::" + method self._write_with_ns_indent('''\ %s %s() const throw()''' % (self._type_type(member.type, withNS = True), method), extraIndent) if fImpl: self._write_with_ns_indent('''\ { ''', extraIndent) if member.type.isStruct: self._write_with_ns_indent('''\ return %s(GetStruct(), %s); ''' % (self._hdk_struct_accessor(member.type, "Get"), element), extraIndent) else: # Blob type is special-cased. if CppClientGenerator.is_blob_type(member.type): self._write_with_ns_indent('''\ unsigned int cbBlob = 0; char* pbBlob = %s(GetStruct(), %s, &cbBlob); return Blob(pbBlob, cbBlob); ''' % (self._hdk_struct_accessor(member.type, "Get"), element), extraIndent) else: # Determine the default value if member.type.isEnum: defaultValue = self._module.enum_value(member.type, None, is_unknown = True) elif CppClientGenerator.is_ipaddress_type(member.type): defaultValue = "HDK::IPv4Address::Blank()" elif CppClientGenerator.is_macaddress_type(member.type): defaultValue = "HDK::MACAddress::Blank()" else: defaultValue = "0" # Determine the cast for the type. cast = self._type_cast(member.type) if CppClientGenerator.is_bool_type(member.type): # Avoid Microsoft compiler warning C4800 cast = "0 != " self._write_with_ns_indent('''\ return %s%s(GetStruct(), %s, %s); ''' % (cast, self._hdk_struct_accessor(member.type, "GetEx"), element, defaultValue), extraIndent) self._write_with_ns_indent('''\ } ''', extraIndent) else: # not fImpl self._write('''; ''') # Generate a set_ accessor implementation. If classScope is present, the method will be scoped in the class. def _write_class_set_accessor(self, member, fImpl = False, classScope = None, extraIndent = 0): element = self._module.element_value((member.namespace, member.name)) if member.type.isStruct or \ CppClientGenerator.is_blob_type(member.type) or \ CppClientGenerator.is_ipaddress_type(member.type) or \ CppClientGenerator.is_macaddress_type(member.type): argType = "const " + self._type_type(member.type, withNS = True) + "&" else: argType = self._type_type(member.type, withNS = True) method = self._class_set_property_method(member) if classScope is not None: method = self._type_type(classScope, withNS = True) + "::" + method self._write_with_ns_indent('''\ void %s(%s value) throw()''' % (method, argType), extraIndent) if fImpl: self._write_with_ns_indent('''\ { ''', extraIndent) if CppClientGenerator.supports_blank(member.type): self._write_with_ns_indent('''\ if (value.IsBlank()) { (void)HDK_XML_Set_Blank(GetStruct(), %s); return; } ''' % (element), extraIndent) # Handle non-standard value sets (struct and blob types) if member.type.isStruct: self._write_with_ns_indent('''\ (void)%s(GetStruct(), %s, value); ''' % (self._hdk_struct_accessor(member.type, "SetEx"), element), extraIndent) elif CppClientGenerator.is_blob_type(member.type): self._write_with_ns_indent('''\ (void)%s(GetStruct(), %s, value.get_Data(), value.get_Size()); ''' % (self._hdk_struct_accessor(member.type, "Set"), element), extraIndent) else: self._write_with_ns_indent('''\ (void)%s(GetStruct(), %s, %svalue); ''' % (self._hdk_struct_accessor(member.type, "Set"), element, self._hdk_type_cast(member.type)), extraIndent) self._write_with_ns_indent('''\ } ''', extraIndent) else: # not fImpl self._write('''; ''') # Generate a FromFile method implementation. def _write_class_method_from_file(self, type, fImpl = False, classScope = None, extraIndent = 0): method = self._class_from_file_method() if classScope is not None: method = self._type_type(classScope, withNS = True) + "::" + method self._write_with_ns_indent('''\ bool %s(const char* pszFile) throw()''' % (method), extraIndent) if fImpl: self._write_with_ns_indent('''\ { return HDK::Struct::DeserializeFromFile(%s(), pszFile); } ''' % (self._module.dom_schema_fn(type)), extraIndent) else: # not fImpl self._write('''; ''') # Generate a ToFile method implementation. def _write_class_method_to_file(self, type, fImpl = False, classScope = None, extraIndent = 0): method = self._class_to_file_method() if classScope is not None: method = self._type_type(classScope, withNS = True) + "::" + method self._write_with_ns_indent('''\ bool %s(const char* pszFile) const throw()''' % (method), extraIndent) if fImpl: self._write_with_ns_indent('''\ { return HDK::Struct::SerializeToFile(%s(), pszFile, 0); } ''' % (self._module.dom_schema_fn(type)), extraIndent) else: # not fImpl self._write('''; ''') # Generate a c++ class declaration from an HDK_XML_Struct def _write_class_declaration(self, struct, fGenerateSets = True, fConstructFromStruct = True, fInline = False, rootElement = None, fDOM = False): self._write_doxygen_section_with_ns_indent_begin() self._write_doxygen_string_with_ns_indent('''\ \\brief %s <a>%s</a> ''' % (struct.name, struct.uri)) self._write_doxygen_lines_with_ns_indent(struct.doctext) self._write_doxygen_section_with_ns_indent_end() self._write_with_ns_indent('''\ class %s : public Struct { ''' % (self._class_class(struct))) # Generate the class constructors and destructor. self._write_with_ns_indent('''\ public: // // Constructors/Destructor. // ''') self._write_class_default_constructor(struct, element = rootElement, fImpl = fInline, extraIndent = 4) self._write_newline() if fConstructFromStruct: self._write_class_hdk_constructor(struct, fImpl = fInline, extraIndent = 4) self._write_newline() # Write the accessor methods. for member in struct.members: self._write_doxygen_section_with_ns_indent_begin(4) self._write_doxygen_string_with_ns_indent('''\ \\brief Get the %s value. ''' % (member.name), 4) if member.doctext: self._write_doxygen_line_with_ns_indent('''\ \\retval %s ''' % (member.doctext[0]), 4) self._write_doxygen_lines_with_ns_indent(member.doctext[1:], 4) self._write_doxygen_section_with_ns_indent_end(4) self._write_class_get_accessor(member, fImpl = fInline, extraIndent = 4) self._write_newline() if fGenerateSets: self._write_doxygen_section_with_ns_indent_begin(4) self._write_doxygen_string_with_ns_indent('''\ \\brief Set the %s value. ''' % (member.name), 4) if member.doctext: self._write_doxygen_string_with_ns_indent('''\ \\arg %s ''' % (member.doctext[0]), 4) self._write_doxygen_lines_with_ns_indent(member.doctext[1:], 4) self._write_doxygen_section_with_ns_indent_end(4) self._write_class_set_accessor(member, fImpl = fInline, extraIndent = 4) self._write_newline() if fDOM: self._write_doxygen_section_with_ns_indent_begin(4) self._write_doxygen_string_with_ns_indent('''\ \\brief Serialize to/from an XML file. ''', 4) self._write_doxygen_section_with_ns_indent_end(4) self._write_class_method_from_file(struct, fImpl = fInline, extraIndent = 4) self._write_class_method_to_file(struct, fImpl = fInline, extraIndent = 4) self._write_newline() self._write_with_ns_indent('''\ }; // class %s : public Struct ''' % self._class_class(struct)) # Generate a wrapper for an array class using the array template def _write_array_template_typedef(self, type, includeClassDeclaration = True): assert(type.isArray) self._write_doxygen_section_with_ns_indent('''\ \\class %s Wrapper class for accessing arrays of %s values. ''' % (self._class_class(type), type.arrayType.name)) # element represents the XML element of each array item element = self._module.element_value((type.members[0].namespace, type.members[0].name)) if type.arrayType.isStruct: if includeClassDeclaration: self._write_with_ns_indent('''\ class %s; // forward declaration ''' % (self._class_class(type.arrayType))) self._write_with_ns_indent('''\ typedef HDK::StructArray<%s, %s> %s; typedef HDK::StructArray<%s, %s>::StructArrayIter %sIter; ''' % (self._type_type(type.arrayType, withNS = True), element, self._class_class(type), self._type_type(type.arrayType, withNS = True), element, self._class_class(type))) elif type.arrayType.isEnum: self._write_with_ns_indent('''\ typedef HDK::EnumArray<%s, %s, %s> %s; typedef HDK::EnumArray<%s, %s, %s>::EnumArrayIter %sIter; ''' % (self._type_type(type.arrayType, withNS = True), self._module.enum_type_value(type.arrayType), element, self._class_class(type), self._type_type(type.arrayType, withNS = True), self._module.enum_type_value(type.arrayType), element, self._class_class(type))) elif type.arrayType.name == "datetime": self._write_with_ns_indent('''\ typedef HDK::DateTimeArray<%s> %s; typedef HDK::DateTimeArray<%s>::DateTimeArrayIter %sIter; ''' % (element, self._class_class(type), element, self._class_class(type))) else: templateClass = type.arrayType.name.capitalize() + "Array" self._write_with_ns_indent('''\ typedef HDK::%s<%s> %s; typedef HDK::%s<%s>::%sIter %sIter; ''' % (templateClass, element, self._class_class(type), templateClass, element, self._class_class(type), templateClass)) # # Generate a c++ class definition from an HDK_XML_Struct # def _write_class_definition(self, struct, fGenerateSets = True, fConstructFromStruct = True, rootElement = None, fDOM = False): assert(struct.isStruct) # Constructors. self._write_class_default_constructor(struct, element = rootElement, fImpl = True, classScope = struct) if fConstructFromStruct: self._write_newline() self._write_class_hdk_constructor(struct, fImpl = True, classScope = struct) for member in struct.members: element = self._module.element_value((member.namespace, member.name)) # Get accessor self._write_newline() self._write_class_get_accessor(member, fImpl = True, classScope = struct) # Set accessor if fGenerateSets: self._write_newline() self._write_class_set_accessor(member, fImpl = True, classScope = struct) if fDOM: self._write_newline() self._write_class_method_from_file(struct, fImpl = True, classScope = struct) self._write_newline() self._write_class_method_to_file(struct, fImpl = True, classScope = struct) # Helper to generate the action method documentation def _write_action_method_documentation(self, action_loc, extraIndent = 0): (http_method, http_location, action, noauth) = \ (action_loc.http_method, action_loc.http_location, action_loc.action, action_loc.noauth) bInput = (len(action.inputMember.type.members) > 0) bOutput = (len(action.outputMember.type.members) > 1) self._write_doxygen_section_with_ns_indent_begin(extraIndent) self._write_doxygen_string_with_ns_indent('''\ \\brief Call the %s method on a given device. <a>%s</a> This method uses HTTP method %s and location '%s' ''' % (action.name, action.uri, http_method, http_location), extraIndent) if noauth: self._write_doxygen_string_with_ns_indent('''\ \\note This method does NOT require HTTP Basic Authorization. ''', extraIndent) self._write_doxygen_lines_with_ns_indent(action.doctext) self._write_doxygen_line_with_ns_indent("\n") # Write out the potential result values. if action.resultEnum.enumValues: self._write_doxygen_line_with_ns_indent('''\ Possible result values: ''', extraIndent) for enumValue in action.resultEnum.enumValues: self._write_doxygen_line_with_ns_indent('''\ - #%s ''' % (self._enum_value(action.resultEnum, enumValue)), extraIndent) self._write_doxygen_string_with_ns_indent('''\ \\arg pTarget The target on which to call this method. ''', extraIndent) if bInput: self._write_doxygen_string_with_ns_indent('''\ \\arg input The input argument data to the %s HNAP method. ''' % (action.name), extraIndent) if bOutput: self._write_doxygen_line_with_ns_indent('''\ \\arg output The output argument data from the %s HNAP method. ''' % (action.name), extraIndent) self._write_doxygen_string_with_ns_indent('''\ \\arg[optional] result The HNAP result of the %s HNAP method. \\arg timeoutSecs An optional timeout, in seconds, to use for the HNAP call. \\retval The result of the HNAP method call. ''' % (action.name), extraIndent) self._write_doxygen_section_with_ns_indent_end(extraIndent) # Helper to generate the action method declarations def _write_action_method(self, action_loc, fImpl = False, withNS = False, fNoDefaultArgs = False, extraIndent = 0): action = action_loc.action bInput = (len(action.inputMember.type.members) > 0) bOutput = (len(action.outputMember.type.members) > 1) self._write_with_ns_indent('''\ HDK::ClientError %s ( HDK::ITarget* pTarget, ''' % (self._action_fn(action_loc, withNS = withNS)), extraIndent) if bInput: self._write_with_ns_indent('''\ const %s & input, ''' % (self._type_type(action.inputMember.type, withNS = True)), extraIndent) if bOutput: self._write_with_ns_indent('''\ %s & output, ''' % (self._type_type(action.outputMember.type, withNS = True)), extraIndent) if fNoDefaultArgs: presultDefault = "/* = NULL */" timeoutSecsDefault = "/* = 0 */" else: presultDefault = "= NULL" timeoutSecsDefault = "= 0" self._write_with_ns_indent('''\ %s* presult %s, unsigned int timeoutSecs %s ) throw()''' % (self._type_type(action.outputMember.type.members[0].type, withNS = True), presultDefault, timeoutSecsDefault), extraIndent) if fImpl: self._write_with_ns_indent('''\ { if (!pTarget) { return ClientError_InvalidArg; } ''', extraIndent) if not bInput: self._write_with_ns_indent('''\ %s input; ''' % (self._type_type(action.inputMember.type, withNS = True)), extraIndent) if not bOutput: self._write_with_ns_indent('''\ %s output; ''' % (self._type_type(action.outputMember.type, withNS = True)), extraIndent) self._write_with_ns_indent('''\ ClientError error = pTarget->Request(timeoutSecs, %s(), %s, input, &output); ''' % (self._module.module_fn(), self._module.action_value(action_loc)), extraIndent) self._write_with_ns_indent('''\ const HDK_MOD_Method* pMethod = HDK_MOD_GetMethod(%s(), %s); ''' % (self._module.module_fn(), self._module.action_value(action_loc)), extraIndent) self._write_with_ns_indent('''\ // Get the result value. %s result = output.%s(); if (NULL != presult) { *presult = result; } // Determine if there was an HNAP-result, and whether it was an error or not. if ((ClientError_OK == error) && (HDK_XML_BuiltinElement_Unknown != pMethod->hnapResultElement)) { if ((pMethod->hnapResultOK != (int)result) && (pMethod->hnapResultREBOOT != (int)result)) { // An HNAP error response. error = HDK::ClientError_HnapMethod; } } return error; } ''' % (self._type_type(action.outputMember.type.members[0].type, withNS = True), \ self._class_get_property_method(action.outputMember.type.members[0])), extraIndent) else: # not fImpl self._write('''; ''') # Helper to write HDK Init documentation def _write_init_function_documentation(self, extraIndent = 0): self._write_doxygen_section_with_ns_indent('''\ \\fn InitializeClient Initialize the HDK client library. This should be called once per application instance. Each call to InitializeClient should be matched by a call to UninitializeClient. \\retval true if initialization was successful, false if not. ''', extraIndent) # Helper to write HDK Init method def _write_init_function(self, fImpl = False, withNS = False, extraIndent = 0): method = "InitializeClient" if withNS: method = "HDK::" + method self._write_with_ns_indent('''\ bool %s() throw()''' % (method), extraIndent) if fImpl: self._write_with_ns_indent('''\ { return !!HDK_CLI_Init(); } ''', extraIndent) else: # not fImpl self._write('''; ''') # Helper to write HDK uninit documentation def _write_uninit_function_documentation(self, extraIndent = 0): self._write_doxygen_section_with_ns_indent('''\ \\fn UninitializeClient Cleanup the HDK client library. This should be called if true was returned from InitializeClient When the caller is done using the HDK client library. ''', extraIndent) # Helper to write HDK uninit method def _write_uninit_function(self, fImpl = False, withNS = False, extraIndent = 0): method = "UninitializeClient" if withNS: method = "HDK::" + method self._write_with_ns_indent('''\ void %s() throw()''' % (method), extraIndent) if fImpl: self._write_with_ns_indent('''\ { HDK_CLI_Cleanup(); } ''', extraIndent) else: # not fImpl self._write('''; ''') # Helper to write URI accessor macro documentation def _write_uri_accessor_macro_documentation(self, action_loc, extraIndent = 0): self._write_doxygen_section_with_ns_indent('''\ \\brief SOAP method URI for action %s ''' % (action_loc.action.name), extraIndent) # Helper to write URI accessor macro def _write_uri_accessor_macro(self, action_loc, extraIndent = 0): self._write_with_ns_indent('''\ #define %s (HDK_MOD_GetMethod(%s(), %s)->pszSOAPAction) ''' % (makeGlobalSymbol("", action_loc.action.namespace, action_loc.action.name, nameSuffix = "_URI"), self._module.module_fn(), self._module.action_value(action_loc)), extraIndent) # # .h code generator # def _generate_h(self): self._write_header_h(self._filename('.h')) self._write('''\ // Non-generated client code. #include "hdk_cli_cpp.h" // Underlying schema module. #include "%s" ''' % (self._module.filename('.h'))) self._push_namespace("HDK") # Write HDK global functions. if self._module.action_locations(): self._write_init_function_documentation() self._write_init_function() self._write_newline() self._write_uninit_function_documentation() self._write_uninit_function() self._write_newline() # Generate c++-style enums for typeEnum in self._enumTypes: self._push_namespace(typeEnum.namespace) self._write_enum(typeEnum) self._pop_namespace() # Declare array types. for typeArray in self._arrayTypes: self._push_namespace(typeArray.namespace) self._write_array_template_typedef(typeArray) self._pop_namespace() # Generate c++ wrapper classes for each struct for typeStruct in self._structTypes: # Generate any required forward declarations. for member in typeStruct.members: # The types are sorted alphabetically, so anything greater than this one has yet to be defined. forwDeclType = member.type if forwDeclType.isArray: forwDeclType = forwDeclType.arrayType if forwDeclType.isStruct and not forwDeclType.isArray: if forwDeclType.name > typeStruct.name: self._push_namespace(forwDeclType.namespace) self._write_class_forward_declaration(forwDeclType) self._pop_namespace() self._push_namespace(typeStruct.namespace) element = None if self._fDOM: element = self._module.element_value((typeStruct.namespace, typeStruct.name)) self._write_class_declaration(typeStruct, fDOM = self._fDOM, fInline = self._fInline, rootElement = element) self._pop_namespace() # Generate class implementations for each action input and output structure. for action in self._module.actions: for (fGenerateSets, struct) in \ [(True, action.inputMember.type), (False, action.outputMember.type)]: self._push_namespace(struct.namespace) self._write_class_declaration(struct, fGenerateSets, fConstructFromStruct = False, fInline = self._fInline, rootElement = self._module.element_value((action.namespace, action.name))) self._pop_namespace() # Generate the action method declarations. for action_loc in self._module.action_locations(): self._push_namespace(action_loc.action.namespace) # Generate accessors for macros URIs. if action_loc.http_method == "POST": self._write_uri_accessor_macro_documentation(action_loc) self._write_uri_accessor_macro(action_loc) self._write_newline() self._write_action_method_documentation(action_loc) self._write_action_method(action_loc) self._write_newline() self._pop_namespace() # Make sure the previous namespace is closed. self._pop_namespace() # Should be in the HDK namespace scope assert(self._namespaceStack[-1].namespace == "HDK") # Close HDK namespace self._pop_namespace(True) # # .cpp code generator # def _generate_cpp(self): self._write_header_cpp(self._filename('.cpp')) self._write('''\ // Local header. #include "%s" using namespace HDK; ''' % (self._filename('.h'))) if not self._fInline: # Generate class implementations for each structure type. for type in self._structTypes: element = None if self._fDOM: element = self._module.element_value((type.namespace, type.name)) self._write_newline() self._write_class_definition(type, fDOM = self._fDOM, rootElement = element) # Generate class implementations for each action input and output structure. for action in self._module.actions: for (fGenerateSets, member) in \ [(True, action.inputMember), (False, action.outputMember)]: self._write_newline() self._write_class_definition(member.type, fGenerateSets, fConstructFromStruct = False, rootElement = self._module.element_value((action.namespace, action.name))) # Write the action method definitions. if self._module.action_locations(): # Write HDK global init/cleanup function definitions. self._write_newline() self._write_init_function(fImpl = True, withNS = True) self._write_newline() self._write_uninit_function(fImpl = True, withNS = True) for action_loc in self._module.action_locations(): self._write_newline() self._write_action_method(action_loc, fImpl = True, withNS = True, fNoDefaultArgs = True)
class ModuleGenerator: # Class initializer def __init__(self, model, baseName, noid, friendlyName, actionLocation, bGenerateDOMSchemas, bGenerateMethods, bClient, bADIReport): self._model = model # Options self._baseName = baseName self._noid = noid self._friendlyName = friendlyName self._bGenerateMethods = bGenerateMethods self._bADIReport = bADIReport # Generator state self._out = None # Module self._module = HDKModule(model, baseName, actionLocation, bGenerateDOMSchemas) # Generation options self._bGenerateActions = not bClient and self._module.actions self._bGenerateServices = not bClient and self._module.services self._bGenerateModule = self._module.actions or self._module.events self._bGenerateModuleDynamic = not bClient and self._bGenerateModule # # Generate code # def generate(self, dir, fhReport): for file, fn, bGenerate in \ [(os.path.join(dir, self._module.filename('.h')), self._generate_h, not self._bGenerateMethods), (os.path.join(dir, self._module.filename('.c')), self._generate_c, not self._bGenerateMethods), (os.path.join(dir, self._module.filename('_methods.c')), self._generate_methods_c, self._bGenerateMethods), (os.path.join(dir, self._module.filename('_adi.txt')), self._generate_adi_txt, self._bADIReport)]: if bGenerate: if fhReport is not None: print >>fhReport, 'Generating "%s" ...' % file self._out = open(file, "w") try: fn() except: raise finally: self._out.close() # # Output helper methods # # Output def _write(self, s): self._out.write(s) # Write .c file header def _write_header_c(self): self._write('''\ /* * Copyright (c) 2008-2010 Cisco Systems, Inc. All rights reserved. * * Cisco Systems, Inc. retains all right, title and interest (including all * intellectual property rights) in and to this computer program, which is * protected by applicable intellectual property laws. Unless you have obtained * a separate written license from Cisco Systems, Inc., you are not authorized * to utilize all or a part of this computer program for any purpose (including * reproduction, distribution, modification, and compilation into object code), * and you must immediately destroy or return to Cisco Systems, Inc. all copies * of this computer program. If you are licensed by Cisco Systems, Inc., your * rights to utilize this computer program are limited by the terms of that * license. To obtain a license, please contact Cisco Systems, Inc. * * This computer program contains trade secrets owned by Cisco Systems, Inc. * and, unless unauthorized by Cisco Systems, Inc. in writing, you agree to * maintain the confidentiality of this computer program and related information * and to not disclose this computer program and related information to any * other person or entity. * * THIS COMPUTER PROGRAM IS PROVIDED AS IS WITHOUT ANY WARRANTIES, AND CISCO * SYSTEMS, INC. EXPRESSLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, * INCLUDING THE WARRANTIES OF MERCHANTIBILITY, FITNESS FOR A PARTICULAR * PURPOSE, TITLE, AND NONINFRINGEMENT. */ ''') # Write .h file header def _write_header_h(self): self._write_header_c(); self._write('''\ #ifndef %s #define %s ''' % (self._module.header_sentinel('.h'), self._module.header_sentinel('.h'))) # Write .h file footer def _write_footer_h(self): self._write('''\ #endif /* %s */ ''' % (self._module.header_sentinel('.h'))) # Write a section comment def _write_section(self, comment): self._write('''\ /* * %s */ ''' % (comment)) # Write enumeration definition def _write_enumeration(self, name, values, ix_start = 0, ix_delta = 1, value_symbols = {}): # Enum header self._write('''\ typedef enum _%s { ''' % (name)) # Write enum values ix_value = ix_start ix_value_last = ix_start + ix_delta * (len(values) - 1) sep = "," for value in values: # Does the value have a symbol? if value_symbols.has_key(value): str_value = value_symbols[value] else: str_value = str(ix_value) # Don't separate the last value if ix_value == ix_value_last: sep = "" # Write the enum value self._write('''\ %s = %s%s ''' % (value, str_value, sep)) ix_value += ix_delta # Enum footer self._write('''\ } %s; ''' % (name)) # Write schema definition def _write_schema(self, schema_nodes_static, schema_static, nodes, element_path_static = None, element_path = None): # Schema nodes header self._write('''\ static const HDK_XML_SchemaNode %s[] = { ''' % (schema_nodes_static)) # Write the schema nodes ix = 0 for node in nodes: # Compute the parent index if node.parent: ix_parent = nodes.index(node.parent) else: ix_parent = 0 # Compute the options options = [] if node.is_optional: options.append("HDK_XML_SchemaNodeProperty_Optional") if node.is_unbounded: options.append("HDK_XML_SchemaNodeProperty_Unbounded") if node.is_any_element: options.append("HDK_XML_SchemaNodeProperty_AnyElement") if node.is_error: options.append("HDK_XML_SchemaNodeProperty_ErrorOutput") if node.is_csv: options.append("HDK_XML_SchemaNodeProperty_CSV") if options: options = " | ".join(options) else: options = "0" # Write the schema node self._write('''\ /* %d */ { %d, %s, %s, %s }, ''' % (ix, ix_parent, self._module.element_value(node.element()), self._module.type_value(node.type), options)) ix += 1 # Schema nodes footer self._write('''\ HDK_XML_Schema_SchemaNodesEnd }; ''') # Schema struct element path if element_path_static and element_path: self._write('''\ static const HDK_XML_Element %s[] = { ''' % (element_path_static)) for element in element_path: self._write('''\ %s, ''' % (self._module.element_value(element))) self._write('''\ HDK_MOD_ElementPathEnd }; ''') # Schema self._write('''\ static const HDK_XML_Schema %s = { s_namespaces, s_elements, %s, %s }; ''' % (schema_static, schema_nodes_static, "s_enumTypes" if self._module.schema.enums else "0")) # Write action definition def _write_action(self, action_loc): http_method, http_location, action, noauth = \ (action_loc.http_method, action_loc.http_location, action_loc.action, action_loc.noauth) # Compute the SOAP action is_get = (http_method.lower() == "get") if is_get: soap_action = "0" else: soap_action = '"' + action.uri + '"' # Compute the action function name if self._bGenerateActions: action_fn = self._module.action_fn(action) else: action_fn = "0" # Compute the schema struct element path symbols if not is_get and self._module.schema.struct_nodes_envelope(action.inputMember, soap = True): input_element_path = self._module.schema_element_path_static(action, "_Input") else: input_element_path = "0" if self._module.schema.struct_nodes_envelope(action.outputMember, soap = True): output_element_path = self._module.schema_element_path_static(action, "_Output") else: output_element_path = "0" # Compute the method options options = [] if noauth: options.append("HDK_MOD_MethodOption_NoBasicAuth") if is_get: options.append("HDK_MOD_MethodOption_NoInputStruct") if options: options = " | ".join(options) else: options = "0" # Compute the OK and REBOOT values result_member = action.outputMember.type.members[0] if "REBOOT" in action.resultEnum.enumValues: result_reboot = "REBOOT" else: result_reboot = "OK" # Write the method struct self._write('''\ { "%s", "%s", %s, %s, &%s, &%s, %s, %s, %s, %s, %s, %s, %s }, ''' % (http_method, http_location, soap_action, action_fn, self._module.schema_static(action, suffix = "_Input"), self._module.schema_static(action, suffix = "_Output"), input_element_path, output_element_path, options, self._module.element_value((result_member.namespace, result_member.name)), self._module.type_value(result_member.type), self._module.enum_value(result_member.type, "OK"), self._module.enum_value(result_member.type, result_reboot))) # Write event definition def _write_event(self, event): # Write the method struct self._write('''\ { "%s", &%s }, ''' % (event.uri, self._module.schema_static(event))) # # *.h code generator # def _generate_h(self): # File header self._write_header_h() # Includes self._write('''\ #include "hdk_mod.h" /* * Macro to control public exports */ #ifdef __cplusplus # define %s_PREFIX extern "C" #else # define %s_PREFIX extern #endif #ifdef HDK_MOD_STATIC # define %s %s_PREFIX #else /* ndef HDK_MOD_STATIC */ # ifdef _MSC_VER # ifdef %s # define %s %s_PREFIX __declspec(dllexport) # else # define %s %s_PREFIX __declspec(dllimport) # endif # else /* ndef _MSC_VER */ # ifdef %s # define %s %s_PREFIX __attribute__ ((visibility("default"))) # else # define %s %s_PREFIX # endif # endif /*def _MSC_VER */ #endif /* def HDK_MOD_STATIC */ ''' % (self._module.export_macro(), self._module.export_macro(), self._module.export_macro(), self._module.export_macro(), self._module.build_macro(), self._module.export_macro(), self._module.export_macro(), self._module.export_macro(), self._module.export_macro(), self._module.build_macro(), self._module.export_macro(), self._module.export_macro(), self._module.export_macro(), self._module.export_macro())) # Element enumeration self._write_section("Elements") self._write_enumeration(self._module.element_enum(), [ self._module.element_value(element) for element in self._module.schema.elements ]) # Enumeration type definition if self._module.schema.enums: self._write_section("Enum types enumeration") self._write_enumeration(self._module.enum_type_enum(), [ self._module.enum_type_value(enum) for enum in self._module.schema.enums ], ix_start = -1, ix_delta = -1) # Enumeration declarations for enum in self._module.schema.enums: # Enumeration type definition self._write_section("Enumeration %s" % (enum.uri)) value_unknown = self._module.enum_value(enum, None, is_unknown = True) values = [ value_unknown ] values.extend([ self._module.enum_value(enum, value) for value in enum.enumValues ]) self._write_enumeration(self._module.enum_enum(enum), values, ix_start = -1, value_symbols = { value_unknown: "HDK_XML_Enum_Unknown" }) # Enumeration accessor declarations self._write('''\ #define %s(pStruct, element, value) HDK_XML_Set_Enum(pStruct, element, %s, 0 ? %s : (value)) #define %s(pStruct, element, value) HDK_XML_Append_Enum(pStruct, element, %s, 0 ? %s : (value)) #define %s(pStruct, element) (%s*)HDK_XML_Get_Enum(pStruct, element, %s) #define %s(pStruct, element, value) (%s)HDK_XML_GetEx_Enum(pStruct, element, %s, 0 ? %s : (value)) #define %s(pMember) (%s*)HDK_XML_GetMember_Enum(pMember, %s) ''' % (self._module.enum_accessor(enum, "Set"), self._module.enum_type_value(enum), self._module.enum_value(enum, enum.enumValues[0]), self._module.enum_accessor(enum, "Append"), self._module.enum_type_value(enum), self._module.enum_value(enum, enum.enumValues[0]), self._module.enum_accessor(enum, "Get"), self._module.enum_enum(enum), self._module.enum_type_value(enum), self._module.enum_accessor(enum, "GetEx"), self._module.enum_enum(enum), self._module.enum_type_value(enum), self._module.enum_value(enum, enum.enumValues[0]), self._module.enum_accessor(enum, "GetMember"), self._module.enum_enum(enum), self._module.enum_type_value(enum))) # Action enumeration if self._module.actions: self._write_section("Method enumeration") self._write_enumeration(self._module.action_enum(), [ self._module.action_value(action_loc) for action_loc in self._module.action_locations() ]) # Action sentinels if self._bGenerateActions: self._write_section("Method sentinels") for action in self._module.actions: self._write('''\ #define %s ''' % (self._module.action_sentinel(action))) # Action declarations if self._bGenerateActions: self._write_section("Methods") for action in self._module.actions: self._write('''\ extern void %s(HDK_MOD_MethodContext* pMethodCtx, HDK_XML_Struct* pInput, HDK_XML_Struct* pOutput); ''' % (self._module.action_fn(action))) # Event enumeration if self._module.events: self._write_section("Event enumeration") self._write_enumeration(self._module.event_enum(), [ self._module.event_value(event) for event in self._module.events ]) # DOM (struct) schema accessor declarations if self._module.schema.structs: self._write_section("DOM Schemas") for struct in self._module.schema.structs: self._write('''\ %s const HDK_XML_Schema* %s(); ''' % (self._module.export_macro(), self._module.dom_schema_fn(struct))) # State declarations if self._module.states: self._write_section("ADI") self._write_enumeration(self._module.state_enum(), [ self._module.state_value(state) for state in self._module.states ], ix_start = 1) self._write_section("ADI sentinels") for state in self._module.states: # Determine get/set usages = {} for actionState in self._model.actionStates: if state.uri in actionState.stateMembers: stateMember = actionState.stateMembers[state.uri] if stateMember.isGet: usages["get"] = None if stateMember.isSet: usages["set"] = None for usage in sorted(usages.iterkeys()): self._write('''\ #define %s ''' % (self._module.state_value_sentinel(state, usage))) # Module declaration if self._bGenerateModule: self._write_section("Module") self._write('''\ %s const HDK_MOD_Module* %s(void); ''' % (self._module.export_macro(), self._module.module_fn())) if self._bGenerateModuleDynamic: self._write('''\ /* Dynamic server module export */ %s const HDK_MOD_Module* HDK_SRV_Module(void); ''' % (self._module.export_macro())) # File footer self._write_footer_h() # # *.c code generator # def _generate_c(self): # File header self._write_header_c() self._write('''\ #include "%s" #include <string.h> ''' % (self._module.filename('.h'))) # Namespace table self._write_section("Namespaces") self._write('''\ static const HDK_XML_Namespace s_namespaces[] = { ''') for namespace in self._module.schema.namespaces: self._write('''\ /* %d */ "%s", ''' % (self._module.schema.namespace_index(namespace), namespace)) self._write('''\ HDK_XML_Schema_NamespacesEnd }; ''') # Elements table self._write_section("Elements") self._write('''\ static const HDK_XML_ElementNode s_elements[] = { ''') for element in self._module.schema.elements: self._write('''\ /* %s = %d */ { %d, "%s" }, ''' % (self._module.element_value(element), self._module.schema.element_index(element), self._module.schema.namespace_index(element[0]), element[1])) self._write('''\ HDK_XML_Schema_ElementsEnd }; ''') # Enumerations definitions for enum in self._module.schema.enums: # Enumeration string table self._write_section("Enumeration %s" % (enum.uri)) self._write('''\ static const HDK_XML_EnumValue %s[] = { ''' % (self._module.enum_type_strings_static(enum))) for value in enum.enumValues: self._write('''\ "%s", ''' % (value)) self._write('''\ HDK_XML_Schema_EnumTypeValuesEnd }; ''') # Enum types array if self._module.schema.enums: self._write_section("Enumeration types array") self._write('''\ static const HDK_XML_EnumType s_enumTypes[] = { ''') sep = ',' for enum in self._module.schema.enums: if enum is self._module.schema.enums[-1]: sep = "" self._write('''\ %s%s ''' % (self._module.enum_type_strings_static(enum), sep)) self._write('''\ }; ''') # Action definitions for action in self._module.actions: self._write_section("Method %s" % (action.uri)) # Input schema self._write_schema(self._module.schema_nodes_static(action, suffix = "_Input"), self._module.schema_static(action, suffix = "_Input"), self._module.schema.struct_nodes(action.inputMember, soap = True), element_path_static = self._module.schema_element_path_static(action, suffix = "_Input"), element_path = self._module.schema.struct_nodes_envelope(action.inputMember, soap = True)) # Output schema self._write('''\ ''') self._write_schema(self._module.schema_nodes_static(action, suffix = "_Output"), self._module.schema_static(action, suffix = "_Output"), self._module.schema.struct_nodes(action.outputMember, soap = True), element_path_static = self._module.schema_element_path_static(action, suffix = "_Output"), element_path = self._module.schema.struct_nodes_envelope(action.outputMember, soap = True)) # Actions table if self._module.actions: self._write_section("Methods") # Actions table header self._write('''\ static const HDK_MOD_Method s_methods[] = { ''') # Write each action node for action_loc in self._module.action_locations(): self._write_action(action_loc) # Actions table footer self._write('''\ HDK_MOD_MethodsEnd }; ''') # Event definitions for event in self._module.events: self._write_section("Event %s" % (event.uri)) self._write_schema(self._module.schema_nodes_static(event), self._module.schema_static(event), self._module.schema.struct_nodes(event.member)) # Events table if self._module.events: self._write_section("Events") # Events table header self._write('''\ static const HDK_MOD_Event s_events[] = { ''') # Write each event node for event in self._module.events: self._write_event(event) # Events table footer self._write('''\ HDK_MOD_EventsEnd }; ''') if self._bGenerateServices: # Services action tables self._write_section("Service Methods") for service in self._module.services: # Service actions header self._write('''\ static const HDK_MOD_Method* %s[] = { ''' % (self._module.service_actions_name(service))) # Service actions for action_uri in service.actions: action_loc = [a for a in self._module.action_locations() if a.action.uri == action_uri][0] self._write('''\ &s_methods[%s], ''' % (self._module.action_value(action_loc))) # Service actions footer self._write('''\ 0 }; ''') # Services event tables self._write_section("Service Events") for service in self._module.services: # Service events header self._write('''\ static const HDK_MOD_Event* %s[] = { ''' % (self._module.service_events_name(service))) # Service events for eventURI in service.events: event = [e for e in self._module.events if e.uri == eventURI][0] self._write('''\ &s_events[%s], ''' % (self._module.event_value(event))) # Service events footer self._write('''\ 0 }; ''') # Services table self._write_section("Services") # Services table header self._write('''\ static const HDK_MOD_Service s_services[] = { ''') # Write each service node for service in self._module.services: self._write('''\ { "%s", %s, %s }, ''' % (service.uri, self._module.service_actions_name(service), self._module.service_events_name(service))) # Services table footer self._write('''\ HDK_MOD_ServicesEnd }; ''') # State definitions if self._module.states: self._write_section("ADI") self._write_schema("s_schemaNodes_ADI", "s_schema_ADI", self._module.schema.state_nodes()) # Struct schema definitions for struct in self._module.schema.structs: self._write_section("Struct %s" % (struct.uri)) self._write_schema(self._module.schema_nodes_static(struct), self._module.schema_static(struct), self._module.schema.struct_nodes(struct)) self._write('''\ /* extern */ const HDK_XML_Schema* %s() { return &%s; } ''' % (self._module.dom_schema_fn(struct), self._module.schema_static(struct))) # Module definition if self._bGenerateModule: self._write_section("Module"); # Network Object ID definition if self._noid is not None: self._write('''\ /* %s */ static const HDK_XML_UUID s_uuid_NOID = { { %s } }; ''' % (self._noid, ", ".join(["0x%02x" % ord(byte) for byte in self._noid.bytes]))) # Module definition and accessors self._write('''\ static const HDK_MOD_Module s_module = { %s, %s, %s, %s, %s, %s }; const HDK_MOD_Module* %s(void) { return &s_module; } ''' % ( "&s_uuid_NOID" if self._noid else "0", '"' + self._friendlyName + '"' if self._friendlyName else "0", "s_services" if self._bGenerateServices else "0", "s_methods" if self._module.actions else "0", "s_events" if self._module.events else "0", "&s_schema_ADI" if self._module.states else "0", self._module.module_fn() )) if self._bGenerateModuleDynamic: self._write('''\ const HDK_MOD_Module* HDK_SRV_Module(void) { return &s_module; } ''') # # *_methods.c code generator # def _generate_methods_c(self): # File header self._write_header_c() self._write('''\ #include "%s" #include "hdk_srv.h" /* Helper method for HNAP results */ #define SetHNAPResult(pStruct, prefix, method, result) \\ prefix##_Set_##method##Result(pStruct, prefix##_Element_##method##Result, prefix##_Enum_##method##Result_##result) ''' % (self._module.filename('.h'))) # Action declarations for action in self._module.actions: self._write_section("Method %s" % (action.uri)) self._write('''\ #ifdef %s void %s(HDK_MOD_MethodContext* pMethodCtx, HDK_XML_Struct* pInput, HDK_XML_Struct* pOutput) { /* Unused parameters */ (void)pMethodCtx; (void)pInput; (void)pOutput; } #endif /* %s */ ''' % (self._module.action_sentinel(action), self._module.action_fn(action), self._module.action_sentinel(action))) # # *_adi.txt report generator # def _generate_adi_txt(self): # ADI report title self._write('''\ ====================================================================== ADI Report for the %s Module ====================================================================== ''' % (self._baseName.upper())) # Output the ADI values used (show get/set) self._write('''\ ====================================================================== ADI values ====================================================================== ''') for state in self._model.referenced_states(): # Determine get/set usages = {} for actionState in self._model.actionStates: if state.uri in actionState.stateMembers: stateMember = actionState.stateMembers[state.uri] if stateMember.isGet: usages["get"] = None if stateMember.isSet: usages["set"] = None sUsages = ', '.join(sorted(usages.iterkeys())) # Get the base type type = state.type nArray = 0 while type.isArray: nArray += 1 type = type.arrayType sArray = "[]" * nArray # Get the type description sDesc = "" if type.isEnum: sDesc = "enum" elif type.isStruct: sDesc = "struct" # Get the type string if sDesc: sType = '%s%s (%s, "%s")' % (type.name, sArray, sDesc, type.namespace) else: sType = '%s%s' % (type.name, sArray) self._write('''\ %s Namespace: "%s" Name: "%s" Type: %s Usage: %s ''' % (self._module.state_value(state), state.namespace, state.name, sType, sUsages)) # Output the ADI values used by action self._write('''\ ====================================================================== ADI values by action ====================================================================== ''') for actionState in self._model.actionStates: self._write('''\ %s ''' % (actionState.uri)) for stateMember in sorted(actionState.stateMembers.itervalues()): # Determine usage usages = {} if stateMember.isGet: usages["get"] = None if stateMember.isSet: usages["set"] = None sUsages = ', '.join(sorted(usages.iterkeys())) self._write('''\ [%s] %s ''' % (sUsages, self._module.state_value(stateMember.state)))