#!/usr/bin/python # -*- coding: utf-8 -*- # # $Id$ # $HeadURL$ # $Author$ # from __future__ import print_function import xml.etree.ElementTree as ET import os import re import string import sys import time class FtData(object): def __init__( self ): self.name = '' self.namespace = '' self.requestTopicType = '' self.requestTopicName = '' self.replyTopicType = '' self.replyTopicName = '' def fqnVar( self, name ): if name.find('::') < 0: name = self.namespace + '::' + name return name def stripNamespace( self, str ): return str.split('::')[-1] def getReplyTopicName( self ): return 'LTS_' + self.stripNamespace( self.replyTopicName ).replace( '::', '_' ) def getReplyTopicNameType( self, withNamespace = True ): var = self.replyTopicName return self.fqnVar( var ) if withNamespace else self.stripNamespace( var ) def getRequestTopicName( self ): return 'LTS_' + self.stripNamespace( self.requestTopicName ).replace( '::', '_' ) def getRequestTopicNameType( self, withNamespace = True ): var = self.requestTopicName return self.fqnVar( var ) if withNamespace else self.stripNamespace( var ) def getReplyTopicType( self ): return self.fqnVar( self.replyTopicType ) def getRequestTopicType( self ): return self.fqnVar( self.requestTopicType ) def needReplyTopicTypedef( self ): return self.getReplyTopicNameType() != self.getReplyTopicType() def needRequestTopicTypedef( self ): return self.getRequestTopicNameType() != self.getRequestTopicType() class GuiPluginRights(object): def __init__( self ): self.name = '' self.offset = 0 self.groups = [] class GuiPluginRightsGroup(object): def __init__( self ): self.name = '' self.desc = '' self.values = [] class FileParser(object): def __init__( self ): self.filename = '' self.service_abbr = '' self.module_name = '' self.struct_names = [] self.ft_enums = [] self.ft_replies = [] self.ft_data = dict() self.op_right_offset = 0 self.op_rights = [] def build(self, path): """ Parse the whole stuff ... """ self.filename = path self.read_file_xml(self.filename) def read_file_xml(self, filename): """ Read the given xml service file""" """print >> sys.stdout, 'Reading xml file %s' % filename""" xmlTree = ET.parse(filename) root = xmlTree.getroot() self.module_name = root.attrib['namespace'] self.service_abbr = root.attrib['abbreviation'].lower() for child in root.iter('topicType'): struct_name = child.attrib['name'] if 'isDataObject' in child.attrib and int(child.attrib['isDataObject']) != 0: self.struct_names.append(struct_name) for child in root.iter('functionTopic'): ft_name = child.attrib['name'] self.ft_enums.append(ft_name) # solange es noch entityModel.idl gibt ... ft_data = FtData() ft_data.name = ft_name ft_data.namespace = self.module_name ft_data.requestTopicType = child.attrib['requestTopicType'] ft_data.requestTopicName = child.attrib['requestTopicName'] ft_data.replyTopicType = child.attrib['replyTopicType'] ft_data.replyTopicName = child.attrib['replyTopicName'] self.ft_data[ft_name] = ft_data for child in root.iter('operatorRights'): self.op_right_offset = int(child.attrib['offset']) for pluginChild in child.iter('guiPlugin'): r = GuiPluginRights() r.name = pluginChild.attrib['name'] r.offset = int(pluginChild.attrib['offset']) r.groups = []; for groups in pluginChild.iter('operatorRightGroup'): g = GuiPluginRightsGroup(); g.name = groups.attrib['name'] g.desc = groups.attrib['description'] if 'description' in groups.attrib else '' for right in groups.iter('operatorRight'): desc = right.attrib['description'] if 'description' in right.attrib else '' g.values.append((right.attrib['right'], int(right.attrib['value']), desc)) r.groups.append(g) self.op_rights.append(r) def outputHeader( outfile, parser, description, with_dds_include = True, with_pragma = True ): outfile.write('\n') outfile.write('/**\n') outfile.write('* %s definitions\n' % description) outfile.write('*/\n') outfile.write('\n') outfile.write('// warning: this file is generated with command\n') outfile.write('// %s\n' % ( " ".join(sys.argv) )) outfile.write('// at %s\n' % time.strftime( '%c' )) outfile.write('// it will be overwritten by next run - do not modify!\n') outfile.write('\n') if with_pragma: outfile.write('#pragma once\n') outfile.write('\n') if with_dds_include: outfile.write('#include "%s.hpp"\n' % ( parser.service_abbr )) class DtsGenerator(object): def generate( self, outfile, parser ): outputHeader( outfile, parser, 'DTS' ) outfile.write('\n') outfile.write('/**\n') outfile.write(' * Type definitions \n') outfile.write(' * => DataWriterObjects (DWOs)\n') outfile.write(' * => DataTopicServers (DTSs)\n') outfile.write(' */\n') outfile.write('\n') outfile.write('namespace DDSGeneric\n') outfile.write('{\n') outfile.write('template \n') outfile.write('class GenericDataWriter;\n') outfile.write('}\n') outfile.write('\n') outfile.write('namespace DTS\n') outfile.write('{\n') outfile.write(' template class GenericDts;\n') outfile.write(' template class GenericDtsImpl;\n') outfile.write('\n') for struct_name in sorted(parser.struct_names): # Add ProjectName (from idl file) topic_name = "%s::%s" % ( parser.module_name, struct_name ) dwo_name = "Dwo%s" % ( struct_name ) outfile.write(' // Topic %s\n' % ( topic_name )) outfile.write(' // Interface\n') outfile.write(' using %s = GenericDts<%s>;\n' % ( struct_name, topic_name )) outfile.write(' // Interface impl\n') outfile.write(' using %s = DDSGeneric::GenericDataWriter<%s>;\n' % ( dwo_name, topic_name )) outfile.write(' using %sImpl = GenericDtsImpl<%s>;\n' % ( struct_name, dwo_name )) outfile.write('\n') outfile.write('} // namespace DTS\n') outfile.write('\n') class DtcGenerator(object): def generate( self, outfile, parser ): outputHeader( outfile, parser, 'DTC' ) outfile.write('\n') outfile.write('/**\n') outfile.write(' * Type definitions \n') outfile.write(' * => DataTopicClients (DTCs)\n') outfile.write(' */\n') outfile.write('\n') outfile.write('namespace DDSGeneric\n') outfile.write('{\n') outfile.write('template \n') outfile.write('class GenericDataReader;\n') outfile.write('template \n') outfile.write('class GenericDataReaderContentFilter;\n') outfile.write('class DynamicDataReader;\n') outfile.write('}\n') outfile.write('\n') outfile.write('namespace DTC\n') outfile.write('{\n') outfile.write(' template class GenericDtc;\n') outfile.write(' template class GenericDtcImpl;\n') outfile.write(' template class GenericDtcSampleInfo;\n') outfile.write(' template class GenericDtcImplSampleInfo;\n') outfile.write('\n') for struct_name in sorted(parser.struct_names): # Add ProjectName (from idl file) topic_name = "%s::%s" % ( parser.module_name, struct_name ) dro_name = "Dro%s" % ( struct_name ) dro_name_cf = "Dro%sCF" % ( struct_name ) outfile.write(' // Topic %s\n' % ( topic_name )) outfile.write(' using %s = DDSGeneric::GenericDataReader<%s>;\n' % ( dro_name, topic_name )) outfile.write(' using %s = GenericDtc<%s>;\n' % ( struct_name, dro_name )) outfile.write(' using %sImpl = GenericDtcImpl<%s>;\n' % ( struct_name, dro_name )) outfile.write(' using %s = DDSGeneric::GenericDataReaderContentFilter<%s>;\n' % ( dro_name_cf, topic_name )) outfile.write(' using %sCF = GenericDtc<%s>;\n' % ( struct_name, dro_name_cf )) outfile.write(' using %sCFImpl = GenericDtcImpl<%s>;\n' % ( struct_name, dro_name_cf )) outfile.write(' namespace SampleInfo {\n') outfile.write(' using %s = GenericDtcSampleInfo<%s>;\n' % ( struct_name, dro_name )) outfile.write(' using %sImpl = GenericDtcImplSampleInfo<%s>;\n' % ( struct_name, dro_name )) outfile.write(' }\n') outfile.write('\n') outfile.write('} // namespace DTC\n') outfile.write('\n') def printFtTopicTypeNames( outfile, ft_data ): outfile.write(' template<> struct TopicNames<%s>' % ft_data.name) outfile.write(' {\n') outfile.write(' static constexpr const char *functionTopicName() { return "%s"; }\n' % ft_data.name) outfile.write(' static constexpr const char *replyTopicName() { return "%s"; }\n' % ft_data.getReplyTopicName()) outfile.write(' static constexpr const char *replyTopicTypeName() { return "%s"; }\n' % ft_data.getReplyTopicNameType( True )) outfile.write(' static constexpr const char *requestTopicName() { return "%s"; }\n' % ft_data.getRequestTopicName()) outfile.write(' static constexpr const char *requestTopicTypeName() { return "%s"; }\n' % ft_data.getRequestTopicNameType( True )) outfile.write(' };\n') def printFtTypedefs( outfile, ft_data ): if ft_data.needRequestTopicTypedef(): outfile.write(' using %s = %s;\n' % ( ft_data.getRequestTopicNameType( False ), ft_data.getRequestTopicType() )) if ft_data.needReplyTopicTypedef(): outfile.write(' using %s = %s;\n' % ( ft_data.getReplyTopicNameType( False ), ft_data.getReplyTopicType() )) class FtsGenerator(object): def generate( self, outfile, parser): outputHeader( outfile, parser, 'FTS' ) outfile.write('\n') outfile.write('namespace FTS\n') outfile.write('{\n') outfile.write('template class GenericFtsImpl;\n') outfile.write('template struct TopicNames;\n') outfile.write('}\n') outfile.write('namespace %s\n' % ( parser.module_name )) outfile.write('{\n') outfile.write(' // TypeDefinitions for Replies that are not implemented => using Core::FunctionReply\n') for ft_name in sorted(parser.ft_enums): printFtTypedefs( outfile, parser.ft_data[ft_name] ) outfile.write('} // namespace %s\n' % ( parser.module_name )) outfile.write('\n') outfile.write('\n') outfile.write('namespace FTS\n') outfile.write('{\n') outfile.write(' // TypeDefinitions for GenericFtsImpl\n') for ft_name in sorted(parser.ft_enums): ft_data = parser.ft_data[ft_name] dummy = '%sTemplateHelperDummy' % ft_data.name; outfile.write(' class %s;\n' % dummy) outfile.write(' using %s = GenericFtsImpl<%s, %s, %s>;\n' % (ft_data.name, ft_data.getRequestTopicType(), ft_data.getReplyTopicNameType(), dummy)) printFtTopicTypeNames( outfile, ft_data ) outfile.write('\n') outfile.write('} // namespace FTS\n') outfile.write('\n') class FtcGenerator(object): def generate( self, outfile, parser ): outputHeader( outfile, parser, 'FTC' ) outfile.write('\n') outfile.write('namespace FTC\n') outfile.write('{\n') outfile.write('template class GenericFtcImpl;\n') outfile.write('template struct TopicNames;\n') outfile.write('}\n') outfile.write('namespace %s\n' % ( parser.module_name )) outfile.write('{\n') outfile.write(' // TypeDefinitions for Replies that are not implemented => using Core::FunctionReply\n') for ft_name in sorted(parser.ft_enums): printFtTypedefs( outfile, parser.ft_data[ft_name] ) outfile.write('} // namespace %s\n' % ( parser.module_name )) outfile.write('\n') outfile.write('\n') outfile.write('namespace FTC\n') outfile.write('{\n') outfile.write(' // TypeDefinitions for GenericFtcImpl\n') for ft_name in sorted(parser.ft_enums): ft_data = parser.ft_data[ft_name] dummy = '%sTemplateHelperDummy' % ft_data.name; outfile.write(' class %s;\n' % dummy) outfile.write(' using %s = GenericFtcImpl<%s, %s, %s>;\n' % (ft_data.name, ft_data.getRequestTopicType(), ft_data.getReplyTopicNameType(), dummy)) printFtTopicTypeNames( outfile, ft_data ) outfile.write('\n') outfile.write('} // namespace FTC\n') outfile.write('\n') class OperatorRights(object): def generate( self, outfile, parser ): outputHeader( outfile, parser, 'Operator Rights', False ) outfile.write('namespace %s \n' % parser.module_name) outfile.write('{\n') outfile.write(' static const int Offset = %s; \n' % parser.op_right_offset) outfile.write('}\n\n') outfile.write('namespace OperatorRights\n') outfile.write('{\n') globalOffset = parser.op_right_offset << 24 for r in parser.op_rights: outfile.write('enum %s\n' % r.name) outfile.write('{\n') offsetPlugin = globalOffset + (r.offset << 16) groupCount = -1 for group in r.groups: groupCount = groupCount + 1 groupOffset = offsetPlugin + (groupCount << 8) for k,v,d in group.values: v += groupOffset outfile.write(' %s = %s,\n' % (k, hex(v))) outfile.write('};\n') outfile.write('\n') outfile.write('enum Groups_%s\n' % parser.module_name) outfile.write('{\n') pattern = re.compile('[\W]+') for r in parser.op_rights: offsetPlugin = globalOffset + (r.offset << 16) for group in r.groups: groupOffset = offsetPlugin + (groupCount << 8) name = pattern.sub('', group.name) outfile.write(' Group%s = %s,\n' % (name, hex(groupOffset))) outfile.write('};\n') outfile.write('\n') outfile.write('enum Plugins_%s\n' % parser.module_name) outfile.write('{\n') for r in parser.op_rights: offsetPlugin = globalOffset + (r.offset << 16) name = pattern.sub('', r.name) outfile.write(' Plugin%s = %s,\n' % (name, hex(offsetPlugin))) outfile.write('};\n') outfile.write('} // namespace OperatorRights\n') class OperatorRightsCpp(object): def generate( self, outfile, parser ): outputHeader( outfile, parser, 'Operator Rights (source)', False, False ) outfile.write('#include "%s_operator_rights.h"\n' % parser.service_abbr) outfile.write('#include \n\n\n') if len(parser.op_rights) == 0: return outfile.write('\nvoid doNothing()\n{\n const char * txt[] {\n') disamb = 'OperatorRights' globalOffset = parser.op_right_offset << 24 for r in parser.op_rights: offsetPlugin = globalOffset + (r.offset << 16) groupCount = -1 for group in r.groups: groupCount = groupCount + 1 groupOffset = offsetPlugin + (groupCount << 8) if group.name != '': outfile.write(' QT_TRANSLATE_NOOP("%s", "%s"),\n' % (disamb, group.name)) if group.desc != '': outfile.write(' QT_TRANSLATE_NOOP("%s", "%s"),\n' % (disamb, group.desc)) for aclName, aclId, aclDescr in group.values: outfile.write(' QT_TRANSLATE_NOOP("%s", "%s"),\n' % (disamb, aclDescr)) outfile.write(' };\n Q_UNUSED(txt);\n}\n') class OperatorRightsSql(object): def generate( self, outfile, parser ): outfile.write('BEGIN;\n') globalOffset = parser.op_right_offset << 24 if globalOffset > 0: outfile.write('--- Offset: %s = %s\n' % (globalOffset, hex(globalOffset))) groupId = globalOffset; for r in parser.op_rights: offsetPlugin = globalOffset + (r.offset << 16) groupCount = -1 for group in r.groups: groupCount = groupCount + 1 groupOffset = offsetPlugin + (groupCount << 8) outfile.write('\n--- %s - %s = %s\n' % (group.name, hex(groupOffset), groupOffset)) str = "INSERT INTO opm.opm_group (id, name, description, type_id, is_hidden) VALUES (%s, '%s', '%s', 4, false);\n" outfile.write(str % (groupOffset, group.name, group.desc)) for aclName, aclId, aclDescr in group.values: aclId += groupOffset outfile.write('--- Base: %s, %s - %s = %s\n' % (groupOffset, aclName, aclId, hex(aclId))) str = "INSERT INTO opm.opm_access_control_level (id, name, description) VALUES (%s, '%s', '%s');\n"; outfile.write(str % (aclId, aclName, aclDescr)); str = "INSERT INTO opm.opm_group (id, name, description, type_id, is_hidden) VALUES (%s, '%s', '%s', 1, true);\n"; outfile.write(str % (groupId, aclName, aclDescr)); str = "INSERT INTO opm.opm_acl_allow (group_id, acl_id) VALUES (%s, %s); -- group_id is: %s = %s\n"; outfile.write(str % (groupId, aclId, groupId, hex(groupId))); str = "INSERT INTO opm.opm_group_group (group_id, is_member_of_group_id) VALUES (%s, %s); -- %s\n" outfile.write(str % (groupOffset, groupId, group.name)) groupId = groupId + 1 outfile.write('\n') outfile.write('END;\n') def generate( parser, generator, out_filename ): try: outfile = open(out_filename, 'w') except: print("Could not open %s for writing" % out_filename, file=sys.stderr) sys.exit(4) generator.generate(outfile, parser) outfile.close() def usage( error ): print(error, file=sys.stderr) print("Usage: %s DTS|DTC|FTS|FTC|SQL " % sys.argv[0], file=sys.stderr) print(" %s ALL " % sys.argv[0], file=sys.stderr) print("i.e.: %s DTS exm_service.xml DtsTypeDefinitions.h" % sys.argv[0], file=sys.stderr) print("call: '%s'" % " ".join(sys.argv), file=sys.stderr) sys.exit(1) def main(): if len(sys.argv) != 4: usage("Invalid argument count") option_str = sys.argv[1] xml_filename = sys.argv[2] parser = FileParser() parser.build(xml_filename) if option_str == "DTS": generate(parser, DtsGenerator(), sys.argv[3]) elif option_str == "DTC": generate(parser, DtcGenerator(), sys.argv[3]) elif option_str == "FTS": generate(parser, FtsGenerator(), sys.argv[3]) elif option_str == "FTC": generate(parser, FtcGenerator(), sys.argv[3]) elif option_str == "SQL": out_dir = sys.argv[3] generate(parser, OperatorRightsSql(), os.path.join(out_dir, parser.service_abbr + '_operator_rights.sql')) elif option_str == "ALL": out_dir = sys.argv[3] fn = parser.service_abbr + '_%s_types.h' generate(parser, DtsGenerator(), fn % 'dts') generate(parser, DtcGenerator(), fn % 'dtc') generate(parser, FtsGenerator(), fn % 'fts') generate(parser, FtcGenerator(), fn % 'ftc') generate(parser, OperatorRights(), parser.service_abbr + '_operator_rights.h') generate(parser, OperatorRightsCpp(), parser.service_abbr + '_operator_rights.cpp') else: usage("invalid option '%s'" % option_str) sys.exit(0) if __name__ == "__main__": main()