| #!/usr/bin/python -u |
| # |
| # tries to parse the output of gtk-doc declaration files and make |
| # an XML reusable description from them |
| # |
| import sys |
| import string |
| |
| ids = {} |
| |
| macros = {} |
| variables = {} |
| structs = {} |
| typedefs = {} |
| enums = {} |
| functions = {} |
| user_functions = {} |
| ret_types = {} |
| types = {} |
| |
| sections = [] |
| files = {} |
| identifiers_file = {} |
| identifiers_type = {} |
| |
| ################################################################## |
| # |
| # Indexer to generate the word index |
| # |
| ################################################################## |
| index = {} |
| |
| |
| def indexString(id, str): |
| if str == None: |
| return |
| str = string.replace(str, "'", ' ') |
| str = string.replace(str, '"', ' ') |
| str = string.replace(str, "/", ' ') |
| str = string.replace(str, '*', ' ') |
| str = string.replace(str, "[", ' ') |
| str = string.replace(str, "]", ' ') |
| str = string.replace(str, "(", ' ') |
| str = string.replace(str, ")", ' ') |
| str = string.replace(str, "<", ' ') |
| str = string.replace(str, '>', ' ') |
| str = string.replace(str, "&", ' ') |
| str = string.replace(str, '#', ' ') |
| str = string.replace(str, ",", ' ') |
| str = string.replace(str, '.', ' ') |
| str = string.replace(str, ';', ' ') |
| tokens = string.split(str) |
| for token in tokens: |
| try: |
| c = token[0] |
| if string.find(string.letters, c) < 0: |
| pass |
| elif len(token) < 3: |
| pass |
| else: |
| lower = string.lower(token) |
| # TODO: generalize this a bit |
| if lower == 'and' or lower == 'the': |
| pass |
| elif index.has_key(token): |
| index[token].append(id) |
| else: |
| index[token] = [id] |
| except: |
| pass |
| |
| |
| |
| ################################################################## |
| # |
| # Parsing: libxml-decl.txt |
| # |
| ################################################################## |
| 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) |
| raw = string.replace(raw, '\n', ' ') |
| raw = string.replace(raw, '\r', ' ') |
| 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 or c == '_': |
| 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) |
| if name == 'void' and type == '': |
| pass |
| else: |
| 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 |
| global variables |
| |
| var = 1 |
| line = input.readline()[:-1] |
| while line != "</MACRO>": |
| if line[0:6] == "<NAME>" and line[-7:] == "</NAME>": |
| name = line[6:-7] |
| elif string.find(line, "#define") >= 0: |
| var = 0 |
| line = input.readline()[:-1] |
| |
| if var == 1: |
| variables[name] = ['', ''] # type, info |
| identifiers_type[name] = "variable" |
| else: |
| macros[name] = [[], ''] # args, info |
| 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[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[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 user_functions |
| |
| line = input.readline()[:-1] |
| type = None |
| signature = "" |
| 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 = signature + line |
| line = input.readline()[:-1] |
| |
| args = extractArgs(signature, name) |
| user_functions[name] = [[type, ''] , args, ''] |
| identifiers_type[name] = "functype" |
| |
| def parseFunction(): |
| global input |
| global functions |
| |
| line = input.readline()[:-1] |
| type = None |
| signature = "" |
| 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 = signature + line |
| line = input.readline()[:-1] |
| |
| args = extractArgs(signature, name) |
| functions[name] = [[type, ''] , args, ''] |
| identifiers_type[name] = "function" |
| |
| 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.keys()), len(structs.keys()), len(typedefs.keys()), |
| len(enums)) |
| c = 0 |
| for enum in enums.keys(): |
| consts = enums[enum][0] |
| c = c + len(consts) |
| print " %d variables, %d constants, %d functions and %d functypes" % ( |
| len(variables.keys()), c, len(functions.keys()), |
| len(user_functions.keys())) |
| print "The functions manipulates %d different types" % (len(types.keys())) |
| print "The functions returns %d different types" % (len(ret_types.keys())) |
| |
| ################################################################## |
| # |
| # Parsing: libxml-decl-list.txt |
| # |
| ################################################################## |
| 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][0]: |
| identifiers_file[const] = name |
| |
| 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())) |
| ################################################################## |
| # |
| # Parsing: xml/*.xml |
| # To enrich the existing info with extracted comments |
| # |
| ################################################################## |
| |
| nbcomments = 0 |
| |
| def insertParameterComment(id, name, value, is_param): |
| global nbcomments |
| |
| indexString(id, value) |
| if functions.has_key(id): |
| if is_param == 1: |
| args = functions[id][1] |
| found = 0 |
| for arg in args: |
| if arg[1] == name: |
| arg[2] = value |
| found = 1 |
| break |
| if found == 0 and name != '...': |
| print "Arg %s not found on function %s description" % (name, id) |
| return |
| else: |
| ret = functions[id][0] |
| ret[1] = value |
| elif user_functions.has_key(id): |
| if is_param == 1: |
| args = user_functions[id][1] |
| found = 0 |
| for arg in args: |
| if arg[1] == name: |
| arg[2] = value |
| found = 1 |
| break |
| if found == 0 and name != '...': |
| print "Arg %s not found on functype %s description" % (name, id) |
| print args |
| return |
| else: |
| ret = user_functions[id][0] |
| ret[1] = value |
| elif macros.has_key(id): |
| if is_param == 1: |
| args = macros[id][0] |
| found = 0 |
| for arg in args: |
| if arg[0] == name: |
| arg[1] = value |
| found = 1 |
| break |
| if found == 0: |
| args.append([name, value]) |
| else: |
| print "Return info for macro %s: %s" % (id, value) |
| # ret = macros[id][0] |
| # ret[1] = value |
| else: |
| print "lost specific comment %s: %s: %s" % (id, name, value) |
| return |
| nbcomments = nbcomments + 1 |
| |
| def insertComment(name, title, value, id): |
| global nbcomments |
| |
| ids[name] = id |
| indexString(name, value) |
| if functions.has_key(name): |
| functions[name][2] = value |
| return "function" |
| elif typedefs.has_key(name): |
| typedefs[name] = value |
| return "typedef" |
| elif macros.has_key(name): |
| macros[name][1] = value |
| return "macro" |
| elif variables.has_key(name): |
| variables[name][1] = value |
| return "variable" |
| elif structs.has_key(name): |
| structs[name] = value |
| return "struct" |
| elif enums.has_key(name): |
| enums[name][1] = value |
| return "enum" |
| elif user_functions.has_key(name): |
| user_functions[name][2] = value |
| return "user_function" |
| else: |
| print "lost comment %s: %s" % (name, value) |
| return "unknown" |
| nbcomments = nbcomments + 1 |
| |
| |
| import libxml2 |
| import os |
| |
| |
| def analyzeXMLDescriptionRow(doc, desc, id, row): |
| if doc == None or desc == None or id == None or row == None: |
| return |
| ctxt = doc.xpathNewContext() |
| ctxt.setContextNode(row) |
| param = ctxt.xpathEval("entry[1]/parameter") |
| entries = ctxt.xpathEval("entry") |
| if param == []: |
| is_param = 0 |
| name = None |
| else: |
| name = param[0].content |
| is_param = 1 |
| str = entries[1].content |
| str = string.replace(str, '\n', ' ') |
| str = string.replace(str, '\r', ' ') |
| str = string.replace(str, ' ', ' ') |
| str = string.replace(str, ' ', ' ') |
| str = string.replace(str, ' ', ' ') |
| while len(str) >= 1 and str[0] == ' ': |
| str=str[1:] |
| |
| insertParameterComment(id, name, str, is_param) |
| |
| |
| |
| def analyzeXMLDescription(doc, desc): |
| if doc == None or desc == None: |
| return |
| ctxt = doc.xpathNewContext() |
| ctxt.setContextNode(desc) |
| |
| # |
| # get the function name |
| # |
| try: |
| title = ctxt.xpathEval("title")[0].content |
| except: |
| return |
| old_id = ctxt.xpathEval("string(title/anchor/@id)") |
| id = string.replace(title, '(', ' '); |
| id = string.replace(id, ')', ' '); |
| id = string.split(id) [0] |
| |
| # |
| # get the function comments |
| # |
| comment = "" |
| paras = ctxt.xpathEval("para") |
| for para in paras: |
| str = para.content |
| str = string.replace(str, '\n', ' ') |
| str = string.replace(str, '\r', ' ') |
| str = string.replace(str, ' ', ' ') |
| str = string.replace(str, ' ', ' ') |
| str = string.replace(str, ' ', ' ') |
| while len(str) >= 1 and str[0] == ' ': |
| str=str[1:] |
| |
| comment = comment + str |
| |
| insertComment(id, title, comment, old_id) |
| |
| rows = ctxt.xpathEval("informaltable/tgroup/tbody/row") |
| for row in rows: |
| analyzeXMLDescriptionRow(doc, desc, id, row) |
| |
| def analyzeXMLDoc(doc): |
| if doc == None: |
| return |
| ctxt = doc.xpathNewContext() |
| descriptions = ctxt.xpathEval("//refsect2") |
| print len(descriptions) |
| for description in descriptions: |
| analyzeXMLDescription(doc, description) |
| |
| xmlfiles = 0 |
| filenames = os.listdir("xml") |
| for filename in filenames: |
| print filename |
| try: |
| doc = libxml2.parseFile("xml/" + filename) |
| analyzeXMLDoc(doc) |
| doc.freeDoc() |
| xmlfiles = xmlfiles + 1 |
| except: |
| print "failed to parse XML description %s" % ("xml/" + filename) |
| continue |
| |
| print "Parsed: %d XML files collexting %d comments" % (xmlfiles, nbcomments) |
| |
| ################################################################## |
| # |
| # Saving: libxml2-api.xml |
| # |
| ################################################################## |
| |
| def escape(raw): |
| raw = string.replace(raw, '&', '&') |
| raw = string.replace(raw, '<', '<') |
| raw = string.replace(raw, '>', '>') |
| raw = string.replace(raw, "'", ''') |
| raw = string.replace(raw, '"', '"') |
| return raw |
| |
| print "Saving XML description libxml2-api.xml" |
| output = open("libxml2-api.xml", "w") |
| output.write('<?xml version="1.0" encoding="ISO-8859-1"?>\n') |
| 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.keys() |
| for i in structs.keys(): symbols.append(i) |
| for i in variables.keys(): variables.append(i) |
| for i in typedefs.keys(): symbols.append(i) |
| for i in enums.keys(): |
| symbols.append(i) |
| for j in enums[i][0]: |
| symbols.append(j) |
| for i in functions.keys(): symbols.append(i) |
| for i in user_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, doc) = functions[i] |
| if doc != None and doc != '': |
| output.write(" <info>%s</info>\n" % (escape(doc))) |
| if ret[1] != None and ret[1] != '': |
| output.write(" <return type='%s' info='%s'/>\n" % ( |
| ret[0], escape(ret[1]))) |
| else: |
| if ret[0] != 'void' and\ |
| ret[0][0:4] != 'void': # This one is actually a bug in GTK Doc |
| print "Description for return on %s is missing" % (i) |
| output.write(" <return type='%s'/>\n" % (ret[0])) |
| for arg in args: |
| if arg[2] != None and arg[2] != '': |
| output.write(" <arg name='%s' type='%s' info='%s'/>\n" % |
| (arg[1], arg[0], escape(arg[2]))) |
| else: |
| if arg[0] != '...': |
| print "Description for %s on %s is missing" % (arg[1], i) |
| output.write(" <arg name='%s' type='%s'/>\n" % ( |
| arg[1], arg[0])) |
| output.write(" </%s>\n" % (type)); |
| elif type == 'functype': |
| output.write(">\n"); |
| (ret, args, doc) = user_functions[i] |
| if doc != None and doc != '': |
| output.write(" <info>%s</info>\n" % (escape(doc))) |
| if ret[1] != None and ret[1] != '': |
| output.write(" <return type='%s' info='%s'/>\n" % ( |
| ret[0], escape(ret[1]))) |
| else: |
| if ret[0] != 'void' and\ |
| ret[0][0:4] != 'void': # This one is actually a bug in GTK Doc |
| print "Description for return on %s is missing" % (i) |
| output.write(" <return type='%s'/>\n" % (ret[0])) |
| for arg in args: |
| if arg[2] != None and arg[2] != '': |
| output.write(" <arg name='%s' type='%s' info='%s'/>\n" % |
| (arg[1], arg[0], escape(arg[2]))) |
| else: |
| if arg[0] != '...': |
| print "Description for %s on %s is missing" % (arg[1], i) |
| output.write(" <arg name='%s' type='%s'/>\n" % ( |
| arg[1], arg[0])) |
| output.write(" </%s>\n" % (type)); |
| elif type == 'macro': |
| output.write(">\n"); |
| if macros[i][1] != None and macros[i][1] != '': |
| output.write(" <info>%s</info>\n" % (escape(macros[i][1]))) |
| else: |
| print "Description for %s is missing" % (i) |
| args = macros[i][0] |
| for arg in args: |
| if arg[1] != None and arg[1] != '': |
| output.write(" <arg name='%s' info='%s'/>\n" % |
| (arg[0], escape(arg[1]))) |
| else: |
| print "Description for %s on %s is missing" % (arg[1], i) |
| output.write(" <arg name='%s'/>\n" % (arg[0])) |
| output.write(" </%s>\n" % (type)); |
| elif type == 'struct': |
| if structs[i] != None and structs[i] != '': |
| output.write(" info='%s'/>\n" % (escape(structs[i]))) |
| else: |
| output.write("/>\n"); |
| elif type == 'variable': |
| if variables[i][1] != None and variables[i][1] != '': |
| output.write(" info='%s'/>\n" % (escape(variables[i]))) |
| else: |
| output.write("/>\n"); |
| elif type == 'typedef': |
| if typedefs[i] != None and typedefs[i] != '': |
| output.write(" info='%s'/>\n" % (escape(typedefs[i]))) |
| else: |
| output.write("/>\n"); |
| else: |
| output.write("/>\n"); |
| else: |
| print "Symbol %s not found in identifiers list" % (i) |
| output.write(" </symbols>\n") |
| output.write("</api>\n") |
| output.close() |
| print "generated XML for %d symbols" % (len(symbols)) |
| |
| ################################################################## |
| # |
| # Saving: libxml2-api.xml |
| # |
| ################################################################## |
| |
| hash = {} |
| for file in files.keys(): |
| for symbol in files[file]: |
| hash[symbol] = file |
| |
| def link(id): |
| if ids.has_key(id): |
| target = string.upper(ids[id]) |
| else: |
| target = string.upper(id) |
| if hash.has_key(id): |
| module = string.lower(hash[id]) |
| else: |
| module = 'index' |
| file = 'html/libxml-' + module + '.html'; |
| return file + '#' + target |
| |
| print "Saving XML crossreferences libxml2-refs.xml" |
| output = open("libxml2-refs.xml", "w") |
| output.write('<?xml version="1.0" encoding="ISO-8859-1"?>\n') |
| output.write("<apirefs name='libxml2'>\n") |
| output.write(" <references>\n") |
| typ = ids.keys() |
| typ.sort() |
| for id in typ: |
| output.write(" <reference name='%s' href='%s'/>\n" % (id, link(id))) |
| output.write(" </references>\n") |
| output.write(" <alpha>\n") |
| letter = None |
| ids = ids.keys() |
| ids.sort() |
| for id in ids: |
| if id[0] != letter: |
| if letter != None: |
| output.write(" </letter>\n") |
| letter = id[0] |
| output.write(" <letter name='%s'>\n" % (letter)) |
| output.write(" <ref name='%s'/>\n" % (id)) |
| if letter != None: |
| output.write(" </letter>\n") |
| output.write(" </alpha>\n") |
| output.write(" <constructors>\n") |
| typ = ret_types.keys() |
| typ.sort() |
| for type in typ: |
| if type == '' or type == 'void' or type == "int" or type == "char *" or \ |
| type == "const char *" : |
| continue |
| output.write(" <type name='%s'>\n" % (type)) |
| ids = ret_types[type] |
| for id in ids: |
| output.write(" <ref name='%s'/>\n" % (id)) |
| output.write(" </type>\n") |
| output.write(" </constructors>\n") |
| output.write(" <functions>\n") |
| typ = types.keys() |
| typ.sort() |
| for type in typ: |
| if type == '' or type == 'void' or type == "int" or type == "char *" or \ |
| type == "const char *" : |
| continue |
| output.write(" <type name='%s'>\n" % (type)) |
| ids = types[type] |
| for id in ids: |
| output.write(" <ref name='%s'/>\n" % (id)) |
| output.write(" </type>\n") |
| output.write(" </functions>\n") |
| |
| output.write(" <files>\n") |
| typ = files.keys() |
| typ.sort() |
| for file in typ: |
| output.write(" <file name='%s'>\n" % (file)) |
| for id in files[file]: |
| output.write(" <ref name='%s'/>\n" % (id)) |
| output.write(" </file>\n") |
| output.write(" </files>\n") |
| |
| output.write(" <index>\n") |
| typ = index.keys() |
| typ.sort() |
| letter = None |
| count = 0 |
| chunk = 0 |
| chunks = [] |
| for id in typ: |
| if len(index[id]) > 30: |
| continue |
| if id[0] != letter: |
| if letter == None or count > 200: |
| if letter != None: |
| output.write(" </letter>\n") |
| output.write(" </chunk>\n") |
| count = 0 |
| chunks.append(["chunk%s" % (chunk -1), first_letter, letter]) |
| output.write(" <chunk name='chunk%s'>\n" % (chunk)) |
| first_letter = id[0] |
| chunk = chunk + 1 |
| elif letter != None: |
| output.write(" </letter>\n") |
| letter = id[0] |
| output.write(" <letter name='%s'>\n" % (letter)) |
| output.write(" <word name='%s'>\n" % (id)) |
| tokens = index[id]; |
| tokens.sort() |
| tok = None |
| for token in index[id]: |
| if tok == token: |
| continue |
| tok = token |
| output.write(" <ref name='%s'/>\n" % (token)) |
| count = count + 1 |
| output.write(" </word>\n") |
| if letter != None: |
| output.write(" </letter>\n") |
| output.write(" </chunk>\n") |
| output.write(" <chunks>\n") |
| for ch in chunks: |
| output.write(" <chunk name='%s' start='%s' end='%s'/>\n" % ( |
| ch[0], ch[1], ch[2])) |
| output.write(" </chunks>\n") |
| output.write(" </index>\n") |
| |
| output.write("</apirefs>\n") |
| output.close() |