478 lines
20 KiB
Python
Executable File
478 lines
20 KiB
Python
Executable File
#!/usr/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
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 <typename T>\n')
|
|
outfile.write('class GenericDataWriter;\n')
|
|
outfile.write('}\n')
|
|
outfile.write('\n')
|
|
outfile.write('namespace DTS\n')
|
|
outfile.write('{\n')
|
|
outfile.write(' template<typename T> class GenericDts;\n')
|
|
outfile.write(' template<typename T> class GenericDtsImpl;\n')
|
|
outfile.write('\n')
|
|
|
|
for struct_name in sorted(parser.struct_names):
|
|
|
|
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 <typename T>\n')
|
|
outfile.write('class GenericDataReader;\n')
|
|
outfile.write('template <typename T>\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<typename T> class GenericDtc;\n')
|
|
outfile.write(' template<typename T> class GenericDtcImpl;\n')
|
|
outfile.write(' template<typename T> class GenericDtcSampleInfo;\n')
|
|
outfile.write(' template<typename T> class GenericDtcImplSampleInfo;\n')
|
|
outfile.write('\n')
|
|
|
|
for struct_name in sorted(parser.struct_names):
|
|
|
|
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 <typename REQ, typename REP, typename DUMMY> class GenericFtsImpl;\n')
|
|
outfile.write('template<typename GENERIC_FTS> 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 <typename REQ, typename REP, typename DUMMY> class GenericFtcImpl;\n')
|
|
outfile.write('template<typename GENERIC_FTC> 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 <QCoreApplication>\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 <service_file.xml> <outfile> " % sys.argv[0], file=sys.stderr)
|
|
print(" %s ALL <service_file.xml> <outdir> " % 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()
|