#!/usr/bin/env python #****************************************************************************** # rblti, Copyright 2005 by Mathieu Bouchard and Heri Andria # pylti, Copyright 2005 by Michael Neuroth # a wrapper for ltilib using SWIG #****************************************************************************** # # Tool to generate header files for SWIG to process the nested classes "parameters" # # 1) generate XML files for the ltilib with doxygen (tested with version 1.4.3) (use this switch in doc.cfg file: GENERATE_XML = YES) # 2) generate the new header files for SWIG with this python script from xml.dom import minidom import os import sys from distutils.text_file import TextFile str_version = '0.32' basedir=None # handle the settings: WORKAREA has to be defined ! if len(sys.argv)>1: basedir = sys.argv[1] else: workarea = os.getenv('WORKAREA') # is pylti not part of the ltilib ? Yes --> than we need a directory structure of WORKAREA_PATH/import/ltilib/xml if workarea<>None: basedir = workarea+os.sep+'import'+os.sep+'ltilib'+os.sep+'xml'+os.sep # check if we are in misc directory of the ltilib distribution (ltilib/misc/pylti) # very simple way: navigate up and navigate down again else: strCheckPath = '..'+os.sep+'..'+os.sep+'misc'+os.sep+'pylti'+'-'+str_version try: # try to read lti.i, this is a good indication of a pylti directory aTestFile = TextFile(filename=strCheckPath+os.sep+'lti.i') basedir = '..'+os.sep+'..'+os.sep+'xml'+os.sep # move up ltipy and misc directory except IOError: pass output_dir = 'generated' #output_dir = 'generated_ruby' def f(x): return 'classlti_1_1'+x+'.xml' #def g(x): return 'lti::_'+x+'::_'+x+'_parameters' def g(x): return 'lti::_'+x+'::'+x+'_parameters' # list of tuples with ( xml-file-name, full-qualified-name of the base class ) lst = [ (f('functor_1_1parameters'), 'lti::ioObject') , (f('ioFunctor_1_1parameters'), g('functor')) , (f('ioImage_1_1parameters'), g('ioFunctor')) , (f('usePalette_1_1parameters'), g('functor')) , (f('segmentation_1_1parameters'), g('functor')) , (f('regionGrowing_1_1parameters'), g('segmentation')) , (f('meanShiftSegmentation_1_1parameters'), g('segmentation')) , (f('kMeansSegmentation_1_1parameters'), g('segmentation')) , (f('whiteningSegmentation_1_1parameters'), g('segmentation')) , (f('csPresegmentation_1_1parameters'), g('segmentation')) , (f('colorQuantization_1_1parameters'), g('functor')) , (f('kMColorQuantization_1_1parameters'), g('colorQuantization')) , (f('viewerBase_1_1parameters'), g('functor')) , (f('externViewer_1_1parameters'), g('viewerBase')) , (f('objectsFromMask_1_1parameters'), g('segmentation')) , (f('objectsFromMask_1_1objectStruct'), 'lti::ioObject') , (f('tree_1_1node'), 'lti::ioObject') , (f('featureExtractor_1_1parameters'), g('functor')) , (f('globalFeatureExtractor_1_1parameters'),g('featureExtractor')) , (f('localFeatureExtractor_1_1parameters'), g('featureExtractor')) , (f('geometricFeatures_1_1parameters'), g('globalFeatureExtractor')) , (f('localMoments_1_1parameters'), g('localFeatureExtractor')) , (f('chromaticityHistogram_1_1parameters'), g('globalFeatureExtractor')) , (f('modifier_1_1parameters'), g('functor')) , (f('polygonApproximation_1_1parameters'), g('modifier')) , (f('transform_1_1parameters'), g('functor')) , (f('gradientFunctor_1_1parameters'), g('transform')) , (f('skeleton_1_1parameters'), g('transform')) , (f('colorContrastGradient_1_1parameters'), g('gradientFunctor')) , (f('edgeDetector_1_1parameters'), g('modifier')) , (f('classicEdgeDetector_1_1parameters'), g('edgeDetector')) , (f('cannyEdges_1_1parameters'), g('edgeDetector')) , (f('filter_1_1parameters'), g('modifier')) , (f('convolution_1_1parameters'), g('filter')) , (f('morphology_1_1parameters'), g('modifier')) , (f('dilation_1_1parameters'), g('morphology')) , (f('erosion_1_1parameters'), g('morphology')) , (f('distanceTransform_1_1parameters'), g('morphology')) , (f('classifier_1_1parameters'), 'lti::ioObject') , (f('classifier_1_1outputTemplate'), 'lti::ioObject') , (f('classifier_1_1outputVector'), 'lti::ioObject') , (f('decisionTree_1_1parameters'), g('classifier')) , (f('ioBMP_1_1parameters'), g('ioFunctor')) , (f('ioPNG_1_1parameters'), g('ioFunctor')) , (f('ioJPEG_1_1parameters'), g('ioFunctor')) , (f('distanceTransform_1_1sedMask'), None) ] # some constants nl = '\n' # Doku: #------- # 'memberdef' ==> 'kind'=function # --> 'name' # --> 'type' # Return Type # --> 'param' # Argumente # --> 'type' def WriteFile(name,txt): f = open(name,'w') f.write(txt) def GetAttribute(attribs,key): for k,v in attribs: if k==key: return v def GetValue(elem): #print elem,elem.firstChild,elem.nodeType if elem.nodeType == elem.TEXT_NODE: return elem.data elif elem.nodeType == elem.ELEMENT_NODE: if elem.firstChild <> None: s = '' for e in elem.childNodes: s += GetValue(e) #+' ' return s return '' elif elem.nodeType == elem.ATTRIBUTE_NODE: return 'xxxx' elif elem.firstChild.nodeType == elem.TEXT_NODE: return elem.firstChild.data return '???' def GetValueForItem(node,itemname,bOnlyFirst=False): s = '' nodes = node.getElementsByTagName(itemname) #print '>>>>>>>',nodes,itemname,len(nodes) if bOnlyFirst: s += GetValue( nodes[0] ) else: for node in nodes: s += GetValue( node ) s += ' ' return s def ProcessFunction(member,classname,newclassname,bIsConst=False,bIsPureVirtual=False,bIsHeader=True): s = '' arg = 'arg' names = member.getElementsByTagName('name') # es sollte immer nur einen Namen geben ! nameNode = names[0] name = GetValue(nameNode) s += GetValueForItem(member,'type',bOnlyFirst=True) s += ' ' if not bIsHeader: s += classname+'::' s += GetValueForItem(member,'name') s += '( ' # Behandlung des Constructors bIsConstructor = (name == classname) params = member.getElementsByTagName('param') for i in range(len(params)): if i>0: s += ', ' s += GetValueForItem(params[i],'type') s += ' '+arg+str(i) s += ' )' if bIsConst: s += ' const' if bIsPureVirtual: s += ' = 0' if not bIsHeader: s += nl s += '{'+nl s += ' '+'pObj->'+name+'(' for i in range(len(params)): if i>0: s += ', ' s += arg+str(i) s += ');'+nl s += '}' s += ';'+nl # dies ist fuer das manuelle name mangling notwendig ! s = s.replace(classname,newclassname) return s def VerifyParameterType(sType): """ Sonderbehandlung fuer den Typ, falls es ein parameters Typ ist, notwendig, da der parameters Typ mit einem define umbenannt wird... Beispiel: gradientFunctor::parameters --> gradientFunctor_parameters """ s = sType elem = sType.split('::') if len(elem)>1 and elem[-1]=='parameters': s = 'lti_'+sType.replace('::','_') print "FOUND:",s return s def ProcessAttribute(member): s = '' sType = GetValueForItem(member,'type',bOnlyFirst=True) sType = VerifyParameterType(sType) s += sType s += ' ' s += GetValueForItem(member,'name') s += GetValueForItem(member,'argsstring') s += ';' return s def ProcessEnum(member): s = '' s += 'enum ' name = GetValueForItem(member,'name',bOnlyFirst=True) # Behandlung der unbenannten enums if name[0]=='@': name = '' s += name s += ' {'+nl items = member.getElementsByTagName('enumvalue') for i in range(len(items)): e = items[i] if i>0: s += ',' s += GetValueForItem(e,'name') val = GetValueForItem(e,'initializer') if val<>None and len(val)>0: s += ' = ' + val s += nl s += '};'+nl return s def ProcessMember(member,classname,newclassname,bIsHeader): s = '' attribs = member.attributes.items() if GetAttribute(attribs,'prot')=='public': if GetAttribute(attribs,'kind')=='function': s = ProcessFunction(member, classname, newclassname, GetAttribute(attribs,'const')=='yes', GetAttribute(attribs,'virt')=='pure-virtual', bIsHeader ) #, GetAttribute(attribs,'virtual')=='virtual' elif GetAttribute(attribs,'kind')=='variable': s = ProcessAttribute(member) elif GetAttribute(attribs,'kind')=='enum': s = ProcessEnum(member) else: s = '/* not a function or attribute */' return s+'\n' def ProcessAllMembers(theclassname,thenewclassname,members,bIsHeader=True,indent=' '*4): s = '' for member in members: s += indent+ProcessMember(member,theclassname,thenewclassname,bIsHeader) return s def ProcessHeaderFile(classname,theclassname,thenewclassname,members,baseclassname=None): s = '' s += '#ifndef _'+thenewclassname+'_h'+nl s += '#define _'+thenewclassname+'_h'+nl s += nl sClose = '' names = classname.split('::') sTypedef = 'typedef ' for n in range(len(names)): if n0: sPre += '_' s += sPre+names[n]+' {'+nl if nNone: s += ' : public '+baseclassname s += nl s += '{'+nl s += 'public:'+nl s += ProcessAllMembers(theclassname,thenewclassname,members) #s += 'private:'+nl #s += ' /*pObj*/'+nl s += '};'+nl s += sClose # s += sTypedef+thenewclassname+' '+thenewclassname[1:]+';'+nl # erstes _ vom Klassennamen entfernen s += sTypedef+thenewclassname+' '+thenewclassname+';'+nl s += '}' s += nl s += '#endif'+nl return s def ProcessCppFile(classname,theclassname,thenewclassname,members): s = '' s += nl s += '#include "'+thenewclassname+'.h"'+nl s += nl s += ProcessAllMembers(theclassname,thenewclassname,members,bIsHeader=False,indent='') s += nl return s def ProcessClass(classname,theclassname,thenewclassname,members,baseclassname=None): s = '' s += ProcessHeaderFile(classname,theclassname,thenewclassname,members,baseclassname) s += nl #s += ProcessCppFile(classname,theclassname,thenewclassname,members) return s def ProcessFile(filename,baseclassname,add_to_output=None): dom = minidom.parse(filename) #elem = dom.getElementsByTagName('compoundname') members = dom.getElementsByTagName('memberdef') classitem = dom.getElementsByTagName('compoundname') classname = GetValue(classitem[0]) # lti::object print "processing",classname,"...", nameitems = classname.split('::') theclassname = nameitems[-1] # object s = '' for i in range(len(nameitems)): # ignoriere das erste lti:: if i>0: # s += '_' if i>1: s += '_' #to prevent class names starting with '_', Ruby hates that s += nameitems[i] thenewclassname = s #classname.replace('::','_') # lti_object print thenewclassname # outputfilename = thenewclassname outputfilename = '_'+thenewclassname if add_to_output<>None: outputfilename += add_to_output outputfilename += '.h' s = ProcessClass(classname,theclassname,thenewclassname,members,baseclassname) WriteFile(output_dir+os.sep+outputfilename,s) def ProcessAllFiles(lst): for e in lst: filename = basedir+e[0] ProcessFile(filename,e[1]) #------------------------------------------------- ProcessAllFiles(lst)