mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2025-07-28 00:21:53 +03:00
added an XML description of the API, moved the script generating it here.
* Makefile.am doc/Makefile.am doc/libxml2-api.xml doc/parsedecl.py: added an XML description of the API, moved the script generating it here. Added a "make api" target Daniel
This commit is contained in:
336
doc/parsedecl.py
Executable file
336
doc/parsedecl.py
Executable file
@ -0,0 +1,336 @@
|
||||
#!/usr/bin/python -u
|
||||
#
|
||||
# tries to parse the output of gtk-doc declaration files and make
|
||||
# an XML reusable description from them
|
||||
#
|
||||
# TODO: try to extracts comments from the DocBook output of
|
||||
|
||||
import sys
|
||||
import string
|
||||
|
||||
macros = []
|
||||
structs = []
|
||||
typedefs = []
|
||||
enums = {}
|
||||
functions = {}
|
||||
private_functions = {}
|
||||
ret_types = {}
|
||||
types = {}
|
||||
|
||||
sections = []
|
||||
files = {}
|
||||
identifiers_file = {}
|
||||
identifiers_type = {}
|
||||
|
||||
def mormalizeTypeSpaces(raw, function):
|
||||
global types
|
||||
|
||||
tokens = string.split(raw)
|
||||
type = ''
|
||||
for token in tokens:
|
||||
if type != '':
|
||||
type = type + ' ' + token
|
||||
else:
|
||||
type = token
|
||||
if types.has_key(type):
|
||||
types[type].append(function)
|
||||
else:
|
||||
types[type] = [function]
|
||||
return type
|
||||
|
||||
def removeComments(raw):
|
||||
while string.find(raw, '/*') > 0:
|
||||
e = string.find(raw, '/*')
|
||||
tmp = raw[0:e]
|
||||
raw = raw[e:]
|
||||
e = string.find(raw, '*/')
|
||||
if e > 0:
|
||||
raw = tmp + raw[e + 2:]
|
||||
else:
|
||||
raw = tmp
|
||||
return raw
|
||||
|
||||
def extractArgs(raw, function):
|
||||
raw = removeComments(raw)
|
||||
list = string.split(raw, ",")
|
||||
ret = []
|
||||
for arg in list:
|
||||
i = len(arg)
|
||||
if i == 0:
|
||||
continue
|
||||
i = i - 1
|
||||
c = arg[i]
|
||||
while string.find(string.letters, c) >= 0 or \
|
||||
string.find(string.digits, c) >= 0:
|
||||
i = i - 1
|
||||
if i < 0:
|
||||
break
|
||||
c = arg[i]
|
||||
name = arg[i+1:]
|
||||
while string.find(string.whitespace, c) >= 0:
|
||||
i = i - 1
|
||||
if i < 0:
|
||||
break
|
||||
c = arg[i]
|
||||
type = mormalizeTypeSpaces(arg[0:i+1], function)
|
||||
# print "list: %s -> %s, %s" % (list, type, name)
|
||||
ret.append((type, name))
|
||||
return ret
|
||||
|
||||
def extractTypes(raw, function):
|
||||
global ret_types
|
||||
|
||||
tokens = string.split(raw)
|
||||
type = ''
|
||||
for token in tokens:
|
||||
if type != '':
|
||||
type = type + ' ' + token
|
||||
else:
|
||||
type = token
|
||||
if ret_types.has_key(type):
|
||||
ret_types[type].append(function)
|
||||
else:
|
||||
ret_types[type] = [function]
|
||||
return type
|
||||
|
||||
def parseMacro():
|
||||
global input
|
||||
global macros
|
||||
|
||||
line = input.readline()[:-1]
|
||||
while line != "</MACRO>":
|
||||
if line[0:6] == "<NAME>" and line[-7:] == "</NAME>":
|
||||
name = line[6:-7]
|
||||
line = input.readline()[:-1]
|
||||
|
||||
macros.append(name)
|
||||
identifiers_type[name] = "macro"
|
||||
|
||||
def parseStruct():
|
||||
global input
|
||||
global structs
|
||||
|
||||
line = input.readline()[:-1]
|
||||
while line != "</STRUCT>":
|
||||
if line[0:6] == "<NAME>" and line[-7:] == "</NAME>":
|
||||
name = line[6:-7]
|
||||
line = input.readline()[:-1]
|
||||
|
||||
structs.append(name)
|
||||
identifiers_type[name] = "struct"
|
||||
|
||||
def parseTypedef():
|
||||
global input
|
||||
global typedefs
|
||||
|
||||
line = input.readline()[:-1]
|
||||
while line != "</TYPEDEF>":
|
||||
if line[0:6] == "<NAME>" and line[-7:] == "</NAME>":
|
||||
name = line[6:-7]
|
||||
line = input.readline()[:-1]
|
||||
|
||||
typedefs.append(name)
|
||||
identifiers_type[name] = "typedef"
|
||||
|
||||
def parseEnum():
|
||||
global input
|
||||
global enums
|
||||
|
||||
line = input.readline()[:-1]
|
||||
consts = []
|
||||
while line != "</ENUM>":
|
||||
if line[0:6] == "<NAME>" and line[-7:] == "</NAME>":
|
||||
name = line[6:-7]
|
||||
elif string.find(line, 'enum') >= 0:
|
||||
pass
|
||||
elif string.find(line, '{') >= 0:
|
||||
pass
|
||||
elif string.find(line, '}') >= 0:
|
||||
pass
|
||||
elif string.find(line, ';') >= 0:
|
||||
pass
|
||||
else:
|
||||
comment = string.find(line, '/*')
|
||||
if comment >= 0:
|
||||
line = line[0:comment]
|
||||
decls = string.split(line, ",")
|
||||
for decl in decls:
|
||||
val = string.split(decl, "=")[0]
|
||||
tokens = string.split(val)
|
||||
if len(tokens) >= 1:
|
||||
token = tokens[0]
|
||||
if string.find(string.letters, token[0]) >= 0:
|
||||
consts.append(token)
|
||||
identifiers_type[token] = "const"
|
||||
line = input.readline()[:-1]
|
||||
|
||||
enums[name] = consts
|
||||
identifiers_type[name] = "enum"
|
||||
|
||||
def parseStaticFunction():
|
||||
global input
|
||||
global private_functions
|
||||
|
||||
line = input.readline()[:-1]
|
||||
type = None
|
||||
signature = None
|
||||
while line != "</USER_FUNCTION>":
|
||||
if line[0:6] == "<NAME>" and line[-7:] == "</NAME>":
|
||||
name = line[6:-7]
|
||||
elif line[0:9] == "<RETURNS>" and line[-10:] == "</RETURNS>":
|
||||
type = extractTypes(line[9:-10], name)
|
||||
else:
|
||||
signature = line
|
||||
line = input.readline()[:-1]
|
||||
|
||||
args = extractArgs(signature, name)
|
||||
private_functions[name] = (type , args)
|
||||
identifiers_type[name] = "private_func"
|
||||
|
||||
def parseFunction():
|
||||
global input
|
||||
global functions
|
||||
|
||||
line = input.readline()[:-1]
|
||||
type = None
|
||||
signature = None
|
||||
while line != "</FUNCTION>":
|
||||
if line[0:6] == "<NAME>" and line[-7:] == "</NAME>":
|
||||
name = line[6:-7]
|
||||
elif line[0:9] == "<RETURNS>" and line[-10:] == "</RETURNS>":
|
||||
type = extractTypes(line[9:-10], name)
|
||||
else:
|
||||
signature = line
|
||||
line = input.readline()[:-1]
|
||||
|
||||
args = extractArgs(signature, name)
|
||||
functions[name] = (type , args)
|
||||
identifiers_type[name] = "function"
|
||||
|
||||
def parseSection():
|
||||
global input
|
||||
global sections
|
||||
global files
|
||||
global identifiers_file
|
||||
|
||||
tokens = []
|
||||
line = input.readline()[:-1]
|
||||
while line != "</SECTION>":
|
||||
if line[0:6] == "<FILE>" and line[-7:] == "</FILE>":
|
||||
name = line[6:-7]
|
||||
elif len(line) > 0:
|
||||
tokens.append(line)
|
||||
line = input.readline()[:-1]
|
||||
|
||||
sections.append(name)
|
||||
files[name] = tokens
|
||||
for token in tokens:
|
||||
identifiers_file[token] = name
|
||||
#
|
||||
# Small transitivity for enum values
|
||||
#
|
||||
if enums.has_key(token):
|
||||
for const in enums[token]:
|
||||
identifiers_file[const] = name
|
||||
|
||||
print "Parsing: libxml-decl.txt"
|
||||
input = open('libxml-decl.txt')
|
||||
while 1:
|
||||
line = input.readline()
|
||||
if not line:
|
||||
break
|
||||
line = line[:-1]
|
||||
if line == "<MACRO>":
|
||||
parseMacro()
|
||||
elif line == "<ENUM>":
|
||||
parseEnum()
|
||||
elif line == "<FUNCTION>":
|
||||
parseFunction()
|
||||
elif line == "<STRUCT>":
|
||||
parseStruct()
|
||||
elif line == "<TYPEDEF>":
|
||||
parseTypedef()
|
||||
elif line == "<USER_FUNCTION>":
|
||||
parseStaticFunction()
|
||||
elif len(line) >= 1 and line[0] == "<":
|
||||
print "unhandled %s" % (line)
|
||||
|
||||
print "Parsed: %d macros. %d structs, %d typedefs, %d enums" % (
|
||||
len(macros), len(structs), len(typedefs), len(enums))
|
||||
c = 0
|
||||
for enum in enums.keys():
|
||||
consts = enums[enum]
|
||||
c = c + len(consts)
|
||||
print " %d constants, %d functions and %d private functions" % (
|
||||
c, len(functions.keys()), len(private_functions.keys()))
|
||||
print "The functions manipulates %d different types" % (len(types.keys()))
|
||||
print "The functions returns %d different types" % (len(ret_types.keys()))
|
||||
|
||||
print "Parsing: libxml-decl-list.txt"
|
||||
input = open('libxml-decl-list.txt')
|
||||
while 1:
|
||||
line = input.readline()
|
||||
if not line:
|
||||
break
|
||||
line = line[:-1]
|
||||
if line == "<SECTION>":
|
||||
parseSection()
|
||||
elif len(line) >= 1 and line[0] == "<":
|
||||
print "unhandled %s" % (line)
|
||||
|
||||
print "Parsed: %d files %d identifiers" % (len(files), len(identifiers_file.keys()))
|
||||
|
||||
print "Saving XML description libxml2-api.xml"
|
||||
output = open("libxml2-api.xml", "w")
|
||||
output.write("<api name='libxml2'>\n")
|
||||
output.write(" <files>\n")
|
||||
for file in files.keys():
|
||||
output.write(" <file name='%s'>\n" % file)
|
||||
for symbol in files[file]:
|
||||
output.write(" <exports symbol='%s'/>\n" % (symbol))
|
||||
output.write(" </file>\n")
|
||||
output.write(" </files>\n")
|
||||
|
||||
output.write(" <symbols>\n")
|
||||
symbols=macros
|
||||
for i in structs: symbols.append(i)
|
||||
for i in typedefs: symbols.append(i)
|
||||
for i in enums.keys():
|
||||
symbols.append(i)
|
||||
for j in enums[i]:
|
||||
symbols.append(j)
|
||||
for i in functions.keys(): symbols.append(i)
|
||||
symbols.sort()
|
||||
prev = None
|
||||
for i in symbols:
|
||||
if i == prev:
|
||||
# print "Symbol %s redefined" % (i)
|
||||
continue
|
||||
else:
|
||||
prev = i
|
||||
if identifiers_type.has_key(i):
|
||||
type = identifiers_type[i]
|
||||
|
||||
if identifiers_file.has_key(i):
|
||||
file = identifiers_file[i]
|
||||
else:
|
||||
file = None
|
||||
|
||||
output.write(" <%s name='%s'" % (type, i))
|
||||
if file != None:
|
||||
output.write(" file='%s'" % (file))
|
||||
if type == "function":
|
||||
output.write(">\n");
|
||||
(ret, args) = functions[i]
|
||||
output.write(" <return type='%s'/>\n" % (ret))
|
||||
for arg in args:
|
||||
output.write(" <arg name='%s' type='%s'/>\n" % (
|
||||
arg[1], arg[0]))
|
||||
output.write(" </%s>\n" % (type));
|
||||
else:
|
||||
output.write("/>\n");
|
||||
else:
|
||||
print "Symbol %s not found in identifiers list" % (i)
|
||||
output.write(" </symbols>\n")
|
||||
output.write("</api>\n")
|
||||
print "generated XML for %d symbols" % (len(symbols))
|
Reference in New Issue
Block a user