mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-22 05:38:14 +00:00
Add tool to generate an XML file describing the Linphone API.
This commit is contained in:
parent
f59489c76d
commit
2472742b6f
1 changed files with 673 additions and 0 deletions
673
tools/genapixml.py
Executable file
673
tools/genapixml.py
Executable file
|
|
@ -0,0 +1,673 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
import argparse
|
||||
import string
|
||||
import sys
|
||||
import xml.etree.ElementTree as ET
|
||||
import xml.dom.minidom as minidom
|
||||
|
||||
|
||||
class CObject:
|
||||
def __init__(self, name):
|
||||
self.name = name.strip()
|
||||
self.briefDescription = ''
|
||||
self.detailedDescription = None
|
||||
self.deprecated = False
|
||||
|
||||
|
||||
class CEnumValue(CObject):
|
||||
pass
|
||||
|
||||
|
||||
class CEnum(CObject):
|
||||
def __init__(self, name):
|
||||
CObject.__init__(self, name)
|
||||
self.values = []
|
||||
self.associatedTypedef = None
|
||||
|
||||
def addValue(self, value):
|
||||
self.values.append(value)
|
||||
|
||||
|
||||
class CStructMember(CObject):
|
||||
def __init__(self, name, t):
|
||||
CObject.__init__(self, name)
|
||||
self.ctype = t.strip()
|
||||
|
||||
|
||||
class CStruct(CObject):
|
||||
def __init__(self, name):
|
||||
CObject.__init__(self, name)
|
||||
self.members = []
|
||||
self.associatedTypedef = None
|
||||
|
||||
def addMember(self, member):
|
||||
self.members.append(member)
|
||||
|
||||
|
||||
class CTypedef(CObject):
|
||||
def __init__(self, name, definition):
|
||||
CObject.__init__(self, name)
|
||||
self.definition = definition.strip()
|
||||
|
||||
|
||||
class CArgument(CObject):
|
||||
def __init__(self, t, name = '', enums = [], structs = []):
|
||||
CObject.__init__(self, name)
|
||||
self.description = None
|
||||
keywords = [ 'const', 'struct', 'enum', 'signed', 'unsigned', '*' ]
|
||||
fullySplittedType = []
|
||||
splittedType = t.strip().split(' ')
|
||||
for s in splittedType:
|
||||
if s.startswith('*'):
|
||||
fullySplittedType.append('*')
|
||||
if len(s) > 1:
|
||||
fullySplittedType.append(s[1:])
|
||||
elif s.endswith('*'):
|
||||
fullySplittedType.append(s[:-1])
|
||||
fullySplittedType.append('*')
|
||||
else:
|
||||
fullySplittedType.append(s)
|
||||
self.completeType = ' '.join(fullySplittedType)
|
||||
isStruct = False
|
||||
isEnum = False
|
||||
for s in fullySplittedType:
|
||||
if not s in keywords:
|
||||
self.ctype = s
|
||||
if s == 'struct':
|
||||
isStruct = True
|
||||
if s == 'enum':
|
||||
isEnum = True
|
||||
if isStruct:
|
||||
for st in structs:
|
||||
if st.associatedTypedef is not None:
|
||||
self.ctype = st.associatedTypedef.name
|
||||
elif isEnum:
|
||||
for e in enums:
|
||||
if e.associatedTypedef is not None:
|
||||
self.ctype = e.associatedTypedef.name
|
||||
|
||||
def __str__(self):
|
||||
return self.completeType + " " + self.name
|
||||
|
||||
|
||||
class CArgumentsList:
|
||||
def __init__(self):
|
||||
self.arguments = []
|
||||
|
||||
def addArgument(self, arg):
|
||||
self.arguments.append(arg)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.arguments)
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.arguments[key]
|
||||
|
||||
def __str__(self):
|
||||
argstr = []
|
||||
for arg in self.arguments:
|
||||
argstr.append(str(arg))
|
||||
return ', '.join(argstr)
|
||||
|
||||
|
||||
class CFunction(CObject):
|
||||
def __init__(self, name, returnarg, argslist):
|
||||
CObject.__init__(self, name)
|
||||
self.returnArgument = returnarg
|
||||
self.arguments = argslist
|
||||
self.location = None
|
||||
|
||||
|
||||
class CEvent(CFunction):
|
||||
pass
|
||||
|
||||
|
||||
class CProperty:
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.getter = None
|
||||
self.setter = None
|
||||
|
||||
|
||||
class CClass(CObject):
|
||||
def __init__(self, st):
|
||||
CObject.__init__(self, st.associatedTypedef.name)
|
||||
if st.deprecated or st.associatedTypedef.deprecated:
|
||||
self.deprecated = True
|
||||
if len(st.associatedTypedef.briefDescription) > 0:
|
||||
self.briefDescription = st.associatedTypedef.briefDescription
|
||||
elif len(st.briefDescription) > 0:
|
||||
self.briefDescription = st.briefDescription
|
||||
if st.associatedTypedef.detailedDescription is not None:
|
||||
self.detailedDescription = st.associatedTypedef.detailedDescription
|
||||
elif st.detailedDescription is not None:
|
||||
self.detailedDescription = st.detailedDescription
|
||||
self.__struct = st
|
||||
self.events = {}
|
||||
self.classMethods = {}
|
||||
self.instanceMethods = {}
|
||||
self.properties = {}
|
||||
self.__computeCFunctionPrefix()
|
||||
|
||||
def __computeCFunctionPrefix(self):
|
||||
self.cFunctionPrefix = ''
|
||||
first = True
|
||||
for l in self.name:
|
||||
if l.isupper() and not first:
|
||||
self.cFunctionPrefix += '_'
|
||||
self.cFunctionPrefix += l.lower()
|
||||
first = False
|
||||
self.cFunctionPrefix += '_'
|
||||
|
||||
def __addPropertyGetter(self, name, f):
|
||||
if not name in self.properties:
|
||||
prop = CProperty(name)
|
||||
self.properties[name] = prop
|
||||
self.properties[name].getter = f
|
||||
|
||||
def __addPropertySetter(self, name, f):
|
||||
if not name in self.properties:
|
||||
prop = CProperty(name)
|
||||
self.properties[name] = prop
|
||||
self.properties[name].setter = f
|
||||
|
||||
def __addClassMethod(self, f):
|
||||
name = f.name[len(self.cFunctionPrefix):]
|
||||
if string.find(name, 'get_') == 0 and len(f.arguments) == 0:
|
||||
self.__addPropertyGetter(name[4:], f)
|
||||
elif string.find(name, 'is_') == 0 and len(f.arguments) == 0 and f.returnArgument.ctype == 'bool_t':
|
||||
self.__addPropertyGetter(name[3:], f)
|
||||
elif string.rfind(name, '_enabled') == (len(name) - 8) and len(f.arguments) == 0 and f.returnArgument.ctype == 'bool_t':
|
||||
self.__addPropertyGetter(name, f)
|
||||
elif string.find(name, 'set_') == 0 and len(f.arguments) == 1:
|
||||
self.__addPropertySetter(name[4:], f)
|
||||
elif string.find(name, 'enable_') == 0 and len(f.arguments) == 1 and f.arguments[0].ctype == 'bool_t':
|
||||
self.__addPropertySetter(name[7:] + '_enabled', f)
|
||||
else:
|
||||
if not f.name in self.classMethods:
|
||||
self.classMethods[f.name] = f
|
||||
|
||||
def __addInstanceMethod(self, f):
|
||||
name = f.name[len(self.cFunctionPrefix):]
|
||||
if string.find(name, 'get_') == 0 and len(f.arguments) == 1:
|
||||
self.__addPropertyGetter(name[4:], f)
|
||||
elif string.find(name, 'is_') == 0 and len(f.arguments) == 1 and f.returnArgument.ctype == 'bool_t':
|
||||
self.__addPropertyGetter(name[3:], f)
|
||||
elif string.rfind(name, '_enabled') == (len(name) - 8) and len(f.arguments) == 1 and f.returnArgument.ctype == 'bool_t':
|
||||
self.__addPropertyGetter(name, f)
|
||||
elif string.find(name, 'set_') == 0 and len(f.arguments) == 2:
|
||||
self.__addPropertySetter(name[4:], f)
|
||||
elif string.find(name, 'enable_') == 0 and len(f.arguments) == 2 and f.arguments[1].ctype == 'bool_t':
|
||||
self.__addPropertySetter(name[7:] + '_enabled', f)
|
||||
else:
|
||||
if not f.name in self.instanceMethods:
|
||||
self.instanceMethods[f.name] = f
|
||||
|
||||
def addEvent(self, ev):
|
||||
if not ev.name in self.events:
|
||||
self.events[ev.name] = ev
|
||||
|
||||
def addMethod(self, f):
|
||||
if len(f.arguments) > 0 and f.arguments[0].ctype == self.name:
|
||||
self.__addInstanceMethod(f)
|
||||
else:
|
||||
self.__addClassMethod(f)
|
||||
|
||||
|
||||
class Project:
|
||||
def __init__(self):
|
||||
self.verbose = False
|
||||
self.prettyPrint = False
|
||||
self.enums = []
|
||||
self.__structs = []
|
||||
self.__typedefs = []
|
||||
self.__events = []
|
||||
self.__functions = []
|
||||
self.classes = []
|
||||
|
||||
def add(self, elem):
|
||||
if isinstance(elem, CClass):
|
||||
if self.verbose:
|
||||
print("Adding class " + elem.name)
|
||||
self.classes.append(elem)
|
||||
elif isinstance(elem, CEnum):
|
||||
if self.verbose:
|
||||
print("Adding enum " + elem.name)
|
||||
for ev in elem.values:
|
||||
print("\t" + ev.name)
|
||||
self.enums.append(elem)
|
||||
elif isinstance(elem, CStruct):
|
||||
if self.verbose:
|
||||
print("Adding struct " + elem.name)
|
||||
for sm in elem.members:
|
||||
print("\t" + sm.ctype + " " + sm.name)
|
||||
self.__structs.append(elem)
|
||||
elif isinstance(elem, CTypedef):
|
||||
if self.verbose:
|
||||
print("Adding typedef " + elem.name)
|
||||
print("\t" + elem.definition)
|
||||
self.__typedefs.append(elem)
|
||||
elif isinstance(elem, CEvent):
|
||||
if self.verbose:
|
||||
print("Adding event " + elem.name)
|
||||
print("\tReturns: " + elem.returnArgument.ctype)
|
||||
print("\tArguments: " + str(elem.arguments))
|
||||
self.__events.append(elem)
|
||||
elif isinstance(elem, CFunction):
|
||||
if self.verbose:
|
||||
print("Adding function " + elem.name)
|
||||
print("\tReturns: " + elem.returnArgument.ctype)
|
||||
print("\tArguments: " + str(elem.arguments))
|
||||
self.__functions.append(elem)
|
||||
|
||||
def __cleanDescription(self, descriptionNode):
|
||||
for para in descriptionNode.findall('./para'):
|
||||
for n in para.findall('./parameterlist'):
|
||||
para.remove(n)
|
||||
for n in para.findall("./simplesect[@kind='return']"):
|
||||
para.remove(n)
|
||||
for n in para.findall("./simplesect[@kind='see']"):
|
||||
t = ''.join(n.itertext())
|
||||
n.clear()
|
||||
n.tag = 'see'
|
||||
n.text = t
|
||||
for n in para.findall("./simplesect[@kind='note']"):
|
||||
n.tag = 'note'
|
||||
n.attrib = {}
|
||||
for n in para.findall(".//xrefsect"):
|
||||
para.remove(n)
|
||||
for n in para.findall('.//ref'):
|
||||
n.attrib = {}
|
||||
if descriptionNode.tag == 'parameterdescription':
|
||||
descriptionNode.tag = 'description'
|
||||
if descriptionNode.tag == 'simplesect':
|
||||
descriptionNode.tag = 'description'
|
||||
descriptionNode.attrib = {}
|
||||
return descriptionNode
|
||||
|
||||
def __discoverClasses(self):
|
||||
for td in self.__typedefs:
|
||||
if string.find(td.definition, 'enum ') == 0:
|
||||
for e in self.enums:
|
||||
if (e.associatedTypedef is None) and td.definition[5:] == e.name:
|
||||
e.associatedTypedef = td
|
||||
break
|
||||
elif string.find(td.definition, 'struct ') == 0:
|
||||
structFound = False
|
||||
for st in self.__structs:
|
||||
if (st.associatedTypedef is None) and td.definition[7:] == st.name:
|
||||
st.associatedTypedef = td
|
||||
structFound = True
|
||||
break
|
||||
if not structFound:
|
||||
name = td.definition[7:]
|
||||
print("Structure with no associated typedef: " + name)
|
||||
st = CStruct(name)
|
||||
st.associatedTypedef = td
|
||||
self.add(st)
|
||||
for td in self.__typedefs:
|
||||
if string.find(td.definition, 'struct ') == 0:
|
||||
for st in self.__structs:
|
||||
if st.associatedTypedef == td:
|
||||
self.add(CClass(st))
|
||||
break
|
||||
# Sort classes by length of name (longest first), so that methods are put in the right class
|
||||
self.classes.sort(key = lambda c: len(c.name), reverse = True)
|
||||
for e in self.__events:
|
||||
for c in self.classes:
|
||||
if string.find(e.name, c.name) == 0:
|
||||
c.addEvent(e)
|
||||
for f in self.__functions:
|
||||
for c in self.classes:
|
||||
if c.cFunctionPrefix == f.name[0 : len(c.cFunctionPrefix)]:
|
||||
c.addMethod(f)
|
||||
break
|
||||
|
||||
def __parseCEnumValue(self, node):
|
||||
ev = CEnumValue(node.find('./name').text)
|
||||
deprecatedNode = node.find(".//xrefsect[xreftitle='Deprecated']")
|
||||
if deprecatedNode is not None:
|
||||
ev.deprecated = True
|
||||
ev.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip()
|
||||
ev.detailedDescription = self.__cleanDescription(node.find('./detaileddescription'))
|
||||
return ev
|
||||
|
||||
def __parseCEnumMemberdef(self, node):
|
||||
e = CEnum(node.find('./name').text)
|
||||
deprecatedNode = node.find(".//xrefsect[xreftitle='Deprecated']")
|
||||
if deprecatedNode is not None:
|
||||
e.deprecated = True
|
||||
e.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip()
|
||||
e.detailedDescription = self.__cleanDescription(node.find('./detaileddescription'))
|
||||
enumvalues = node.findall("enumvalue[@prot='public']")
|
||||
for enumvalue in enumvalues:
|
||||
ev = self.__parseCEnumValue(enumvalue)
|
||||
e.addValue(ev)
|
||||
return e
|
||||
|
||||
def __findCEnum(self, tree):
|
||||
memberdefs = tree.findall("./compounddef[@kind='group']/sectiondef[@kind='enum']/memberdef[@kind='enum'][@prot='public']")
|
||||
for m in memberdefs:
|
||||
e = self.__parseCEnumMemberdef(m)
|
||||
self.add(e)
|
||||
|
||||
def __parseCStructMember(self, node, structname):
|
||||
name = node.find('./name').text
|
||||
definition = node.find('./definition').text
|
||||
t = definition[0:string.find(definition, structname + "::" + name)]
|
||||
sm = CStructMember(name, t)
|
||||
deprecatedNode = node.find(".//xrefsect[xreftitle='Deprecated']")
|
||||
if deprecatedNode is not None:
|
||||
sm.deprecated = True
|
||||
sm.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip()
|
||||
sm.detailedDescription = self.__cleanDescription(node.find('./detaileddescription'))
|
||||
return sm
|
||||
|
||||
def __parseCStructCompounddef(self, node):
|
||||
s = CStruct(node.find('./compoundname').text)
|
||||
deprecatedNode = node.find(".//xrefsect[xreftitle='Deprecated']")
|
||||
if deprecatedNode is not None:
|
||||
s.deprecated = True
|
||||
s.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip()
|
||||
s.detailedDescription = self.__cleanDescription(node.find('./detaileddescription'))
|
||||
structmembers = node.findall("sectiondef/memberdef[@kind='variable'][@prot='public']")
|
||||
for structmember in structmembers:
|
||||
sm = self.__parseCStructMember(structmember, s.name)
|
||||
s.addMember(sm)
|
||||
return s
|
||||
|
||||
def __findCStruct(self, tree):
|
||||
compounddefs = tree.findall("./compounddef[@kind='struct'][@prot='public']")
|
||||
for c in compounddefs:
|
||||
s = self.__parseCStructCompounddef(c)
|
||||
self.add(s)
|
||||
|
||||
def __parseCTypedefMemberdef(self, node):
|
||||
name = node.find('./name').text
|
||||
definition = node.find('./definition').text
|
||||
if string.find(definition, 'typedef ') == 0:
|
||||
definition = definition[8 :]
|
||||
if string.rfind(name, 'Cb') == len(name) - 2:
|
||||
pos = string.find(definition, "(*")
|
||||
if pos == -1:
|
||||
return None
|
||||
returntype = definition[0:pos].strip()
|
||||
if returntype != "void":
|
||||
return None
|
||||
returnarg = CArgument(returntype, enums = self.enums, structs = self.__structs)
|
||||
definition = definition[pos + 2 :]
|
||||
pos = string.find(definition, "(")
|
||||
definition = definition[pos + 1 : -1]
|
||||
argslist = CArgumentsList()
|
||||
for argdef in definition.split(', '):
|
||||
argType = ''
|
||||
starPos = string.rfind(argdef, '*')
|
||||
spacePos = string.rfind(argdef, ' ')
|
||||
if starPos != -1:
|
||||
argType = argdef[0 : starPos + 1]
|
||||
argName = argdef[starPos + 1 :]
|
||||
elif spacePos != -1:
|
||||
argType = argdef[0 : spacePos]
|
||||
argName = argdef[spacePos + 1 :]
|
||||
argslist.addArgument(CArgument(argType, argName, self.enums, self.__structs))
|
||||
if len(argslist) > 0:
|
||||
paramdescs = node.findall("detaileddescription/para/parameterlist[@kind='param']/parameteritem")
|
||||
if paramdescs:
|
||||
for arg in argslist.arguments:
|
||||
for paramdesc in paramdescs:
|
||||
if arg.name == paramdesc.find('./parameternamelist').find('./parametername').text:
|
||||
arg.description = self.__cleanDescription(paramdesc.find('./parameterdescription'))
|
||||
missingDocWarning = ''
|
||||
for arg in argslist.arguments:
|
||||
if arg.description == None:
|
||||
missingDocWarning += "\t'" + arg.name + "' parameter not documented\n";
|
||||
if missingDocWarning != '':
|
||||
print(name + ":\n" + missingDocWarning)
|
||||
f = CEvent(name, returnarg, argslist)
|
||||
deprecatedNode = node.find(".//xrefsect[xreftitle='Deprecated']")
|
||||
if deprecatedNode is not None:
|
||||
f.deprecated = True
|
||||
f.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip()
|
||||
f.detailedDescription = self.__cleanDescription(node.find('./detaileddescription'))
|
||||
return f
|
||||
else:
|
||||
pos = string.rfind(definition, " " + name)
|
||||
if pos != -1:
|
||||
definition = definition[0 : pos]
|
||||
td = CTypedef(name, definition)
|
||||
deprecatedNode = node.find(".//xrefsect[xreftitle='Deprecated']")
|
||||
if deprecatedNode is not None:
|
||||
td.deprecated = True
|
||||
td.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip()
|
||||
td.detailedDescription = self.__cleanDescription(node.find('./detaileddescription'))
|
||||
return td
|
||||
return None
|
||||
|
||||
def __findCTypedef(self, tree):
|
||||
memberdefs = tree.findall("./compounddef[@kind='group']/sectiondef[@kind='typedef']/memberdef[@kind='typedef'][@prot='public']")
|
||||
for m in memberdefs:
|
||||
td = self.__parseCTypedefMemberdef(m)
|
||||
self.add(td)
|
||||
|
||||
def __parseCFunctionMemberdef(self, node):
|
||||
missingDocWarning = ''
|
||||
name = node.find('./name').text
|
||||
t = ''.join(node.find('./type').itertext())
|
||||
returnarg = CArgument(t, enums = self.enums, structs = self.__structs)
|
||||
returndesc = node.find("./detaileddescription/para/simplesect[@kind='return']")
|
||||
if returndesc is not None:
|
||||
returnarg.description = self.__cleanDescription(returndesc)
|
||||
elif returnarg.completeType != 'void':
|
||||
missingDocWarning += "\tReturn value is not documented\n"
|
||||
argslist = CArgumentsList()
|
||||
argslistNode = node.findall('./param')
|
||||
for argNode in argslistNode:
|
||||
argType = ''.join(argNode.find('./type').itertext())
|
||||
argName = ''
|
||||
argNameNode = argNode.find('./declname')
|
||||
if argNameNode is not None:
|
||||
argName = ''.join(argNameNode.itertext())
|
||||
if argType != 'void':
|
||||
argslist.addArgument(CArgument(argType, argName, self.enums, self.__structs))
|
||||
if len(argslist) > 0:
|
||||
paramdescs = node.findall("./detaileddescription/para/parameterlist[@kind='param']/parameteritem")
|
||||
if paramdescs:
|
||||
for arg in argslist.arguments:
|
||||
for paramdesc in paramdescs:
|
||||
if arg.name == paramdesc.find('./parameternamelist').find('./parametername').text:
|
||||
arg.description = self.__cleanDescription(paramdesc.find('./parameterdescription'))
|
||||
missingDocWarning = ''
|
||||
for arg in argslist.arguments:
|
||||
if arg.description == None:
|
||||
missingDocWarning += "\t'" + arg.name + "' parameter not documented\n";
|
||||
f = CFunction(name, returnarg, argslist)
|
||||
deprecatedNode = node.find(".//xrefsect[xreftitle='Deprecated']")
|
||||
if deprecatedNode is not None:
|
||||
f.deprecated = True
|
||||
f.briefDescription = ''.join(node.find('./briefdescription').itertext()).strip()
|
||||
f.detailedDescription = self.__cleanDescription(node.find('./detaileddescription'))
|
||||
locationNode = node.find('./location')
|
||||
if locationNode is not None:
|
||||
f.location = locationNode.get('file')
|
||||
if not f.location.endswith('.h'):
|
||||
missingDocWarning += "\tNot documented in a header file ('" + f.location + "')\n";
|
||||
if missingDocWarning != '':
|
||||
print(name + ":\n" + missingDocWarning)
|
||||
return f
|
||||
|
||||
def __findCFunction(self, tree):
|
||||
memberdefs = tree.findall("./compounddef[@kind='group']/sectiondef[@kind='func']/memberdef[@kind='function'][@prot='public'][@static='no']")
|
||||
for m in memberdefs:
|
||||
f = self.__parseCFunctionMemberdef(m)
|
||||
self.add(f)
|
||||
|
||||
def initFromFiles(self, xmlfiles):
|
||||
trees = []
|
||||
for f in xmlfiles:
|
||||
tree = None
|
||||
try:
|
||||
if self.verbose:
|
||||
print("Parsing XML file: " + f.name)
|
||||
tree = ET.parse(f)
|
||||
except ET.ParseError as e:
|
||||
print(e)
|
||||
if tree is not None:
|
||||
trees.append(tree)
|
||||
for tree in trees:
|
||||
self.__findCEnum(tree)
|
||||
for tree in trees:
|
||||
self.__findCStruct(tree)
|
||||
for tree in trees:
|
||||
self.__findCTypedef(tree)
|
||||
for tree in trees:
|
||||
self.__findCFunction(tree)
|
||||
self.__discoverClasses()
|
||||
|
||||
def check(self):
|
||||
for c in self.classes:
|
||||
for name, p in c.properties.iteritems():
|
||||
if p.getter is None and p.setter is not None:
|
||||
print("Property '" + name + "' of class '" + c.name + "' has a setter but no getter")
|
||||
|
||||
|
||||
class Generator:
|
||||
def __init__(self, outputfile):
|
||||
self.__outputfile = outputfile
|
||||
|
||||
def __generateEnum(self, cenum, enumsNode):
|
||||
enumNodeAttributes = { 'name' : cenum.name }
|
||||
if cenum.associatedTypedef is not None:
|
||||
enumNodeAttributes['name'] = cenum.associatedTypedef.name
|
||||
if cenum.deprecated:
|
||||
enumNodeAttributes['deprecated'] = 'true'
|
||||
enumNode = ET.SubElement(enumsNode, 'enum', enumNodeAttributes)
|
||||
if cenum.briefDescription != '':
|
||||
enumBriefDescriptionNode = ET.SubElement(enumNode, 'briefdescription')
|
||||
enumBriefDescriptionNode.text = cenum.briefDescription
|
||||
enumNode.append(cenum.detailedDescription)
|
||||
if len(cenum.values) > 0:
|
||||
enumValuesNode = ET.SubElement(enumNode, 'values')
|
||||
for value in cenum.values:
|
||||
enumValuesNodeAttributes = { 'name' : value.name }
|
||||
if value.deprecated:
|
||||
enumValuesNodeAttributes['deprecated'] = 'true'
|
||||
valueNode = ET.SubElement(enumValuesNode, 'value', enumValuesNodeAttributes)
|
||||
if value.briefDescription != '':
|
||||
valueBriefDescriptionNode = ET.SubElement(valueNode, 'briefdescription')
|
||||
valueBriefDescriptionNode.text = value.briefDescription
|
||||
valueNode.append(value.detailedDescription)
|
||||
|
||||
def __generateFunction(self, parentNode, nodeName, f):
|
||||
functionAttributes = { 'name' : f.name }
|
||||
if f.location is not None:
|
||||
functionAttributes['location'] = f.location
|
||||
if f.deprecated:
|
||||
functionAttributes['deprecated'] = 'true'
|
||||
functionNode = ET.SubElement(parentNode, nodeName, functionAttributes)
|
||||
returnValueAttributes = { 'type' : f.returnArgument.completeType }
|
||||
returnValueNode = ET.SubElement(functionNode, 'return', returnValueAttributes)
|
||||
if f.returnArgument.description is not None:
|
||||
returnValueNode.append(f.returnArgument.description)
|
||||
argumentsNode = ET.SubElement(functionNode, 'arguments')
|
||||
for arg in f.arguments:
|
||||
argumentNodeAttributes = { 'name' : arg.name, 'type' : arg.completeType }
|
||||
argumentNode = ET.SubElement(argumentsNode, 'argument', argumentNodeAttributes)
|
||||
if arg.description is not None:
|
||||
argumentNode.append(arg.description)
|
||||
if f.briefDescription != '':
|
||||
functionBriefDescriptionNode = ET.SubElement(functionNode, 'briefdescription')
|
||||
functionBriefDescriptionNode.text = f.briefDescription
|
||||
functionNode.append(f.detailedDescription)
|
||||
|
||||
def __generateClass(self, cclass, classesNode):
|
||||
classNodeAttributes = { 'name' : cclass.name, 'cfunctionprefix' : cclass.cFunctionPrefix }
|
||||
if cclass.deprecated:
|
||||
classNodeAttributes['deprecated'] = 'true'
|
||||
classNode = ET.SubElement(classesNode, 'class', classNodeAttributes)
|
||||
if len(cclass.events) > 0:
|
||||
eventsNode = ET.SubElement(classNode, 'events')
|
||||
eventnames = []
|
||||
for eventname in cclass.events:
|
||||
eventnames.append(eventname)
|
||||
eventnames.sort()
|
||||
for eventname in eventnames:
|
||||
self.__generateFunction(eventsNode, 'event', cclass.events[eventname])
|
||||
if len(cclass.classMethods) > 0:
|
||||
classMethodsNode = ET.SubElement(classNode, 'classmethods')
|
||||
methodnames = []
|
||||
for methodname in cclass.classMethods:
|
||||
methodnames.append(methodname)
|
||||
methodnames.sort()
|
||||
for methodname in methodnames:
|
||||
self.__generateFunction(classMethodsNode, 'classmethod', cclass.classMethods[methodname])
|
||||
if len(cclass.instanceMethods) > 0:
|
||||
instanceMethodsNode = ET.SubElement(classNode, 'instancemethods')
|
||||
methodnames = []
|
||||
for methodname in cclass.instanceMethods:
|
||||
methodnames.append(methodname)
|
||||
methodnames.sort()
|
||||
for methodname in methodnames:
|
||||
self.__generateFunction(instanceMethodsNode, 'instancemethod', cclass.instanceMethods[methodname])
|
||||
if len(cclass.properties) > 0:
|
||||
propertiesNode = ET.SubElement(classNode, 'properties')
|
||||
propnames = []
|
||||
for propname in cclass.properties:
|
||||
propnames.append(propname)
|
||||
propnames.sort()
|
||||
for propname in propnames:
|
||||
propertyNodeAttributes = { 'name' : propname }
|
||||
propertyNode = ET.SubElement(propertiesNode, 'property', propertyNodeAttributes)
|
||||
if cclass.properties[propname].getter is not None:
|
||||
self.__generateFunction(propertyNode, 'getter', cclass.properties[propname].getter)
|
||||
if cclass.properties[propname].setter is not None:
|
||||
self.__generateFunction(propertyNode, 'setter', cclass.properties[propname].setter)
|
||||
if cclass.briefDescription != '':
|
||||
classBriefDescriptionNode = ET.SubElement(classNode, 'briefdescription')
|
||||
classBriefDescriptionNode.text = cclass.briefDescription
|
||||
classNode.append(cclass.detailedDescription)
|
||||
|
||||
def generate(self, project):
|
||||
print("Generating XML document of Linphone API to '" + self.__outputfile.name + "'")
|
||||
apiNode = ET.Element('api')
|
||||
project.enums.sort(key = lambda e: e.name)
|
||||
if len(project.enums) > 0:
|
||||
enumsNode = ET.SubElement(apiNode, 'enums')
|
||||
for cenum in project.enums:
|
||||
self.__generateEnum(cenum, enumsNode)
|
||||
if len(project.classes) > 0:
|
||||
classesNode = ET.SubElement(apiNode, 'classes')
|
||||
project.classes.sort(key = lambda c: c.name)
|
||||
for cclass in project.classes:
|
||||
self.__generateClass(cclass, classesNode)
|
||||
s = '<?xml version="1.0" encoding="UTF-8" ?>\n'
|
||||
s += ET.tostring(apiNode, 'utf-8')
|
||||
if project.prettyPrint:
|
||||
s = minidom.parseString(s).toprettyxml(indent='\t')
|
||||
self.__outputfile.write(s)
|
||||
|
||||
|
||||
|
||||
def main(argv = None):
|
||||
if argv is None:
|
||||
argv = sys.argv
|
||||
argparser = argparse.ArgumentParser(description="Generate XML version of the Linphone API.")
|
||||
argparser.add_argument('-o', '--outputfile', metavar='outputfile', type=argparse.FileType('w'), help="Output XML file describing the Linphone API.")
|
||||
argparser.add_argument('--verbose', help="Increase output verbosity", action='store_true')
|
||||
argparser.add_argument('--pretty', help="XML pretty print", action='store_true')
|
||||
argparser.add_argument('xmlfile', metavar='xmlfile', type=argparse.FileType('r'), nargs='+', help="XML file generated by doxygen.")
|
||||
args = argparser.parse_args()
|
||||
if args.outputfile == None:
|
||||
args.outputfile = open('api.xml', 'w')
|
||||
project = Project()
|
||||
if args.verbose:
|
||||
project.verbose = True
|
||||
if args.pretty:
|
||||
project.prettyPrint = True
|
||||
project.initFromFiles(args.xmlfile)
|
||||
project.check()
|
||||
gen = Generator(args.outputfile)
|
||||
gen.generate(project)
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Loading…
Add table
Reference in a new issue