diff options
author | David Turner <david@freetype.org> | 2000-10-26 07:52:40 +0000 |
---|---|---|
committer | David Turner <david@freetype.org> | 2000-10-26 07:52:40 +0000 |
commit | 205fc3faf29159a86c4f838edc587952afbb74aa (patch) | |
tree | e1954f3809ee043cb8026fc052e3382c9163c180 /docs | |
parent | a4e2894e03de65c5e0cd14b11b6fa30b14ed6769 (diff) |
updates to the API reference generators
the basic parsing routines seem to work ok
we now generate a list of DocBlock objects from
a list of input file, we now need to sort them
by "kind" (i.e. type/macro/functions) to generate
several web pages, as well as a global index
Diffstat (limited to 'docs')
-rw-r--r-- | docs/docmaker.py | 670 |
1 files changed, 375 insertions, 295 deletions
diff --git a/docs/docmaker.py b/docs/docmaker.py index aa1ba84f..dbfd8b75 100644 --- a/docs/docmaker.py +++ b/docs/docmaker.py @@ -28,12 +28,9 @@ html_header = """ vlink="#51188E" alink="#FF0000"> <center><h1>FreeType 2 API Reference</h1></center> -<center><table width="80%"><tr><td> """ html_footer = """ -</td></tr> -</table></center> </body> </html> """ @@ -49,12 +46,12 @@ code_footer = """ para_header = "<p>" para_footer = "</p>" -block_header = """<table width="100%"><tr><td>""" -block_footer = "</table>" +block_header = """<center><hr width="550"><table width="550"><tr><td>""" +block_footer = "</table></center>" -source_header = """<table width="100%"><tr bgcolor="#D6E8FF" width="100%"><td><pre> +source_header = """<center><table width="550"><tr bgcolor="#D6E8FF" width="100%"><td><pre> """ -source_footer = """</pre></table> +source_footer = """</pre></table></center> <br><br> """ @@ -144,175 +141,18 @@ source_footer = """</pre></table> # -def make_block_list(): - """parse a file and extract comments blocks from it""" - - list = [] - block = [] - format = 0 - - # we use "format" to store the state of our parser: - # - # 0 - wait for beginning of comment - # 1 - parse comment format 1 - # 2 - parse comment format 2 - # - # 4 - wait for beginning of source (or comment ??) - # 5 - process source - # - - comment = [] - source = [] - state = 0 - - for line in fileinput.input(): - - l = len( line ) - if l > 0 and line[l - 1] == '\012': - line = line[0 : l - 1] - - # stripped version of the line - line2 = string.strip( line ) - l = len( line2 ) - - # if this line begins with a comment and we are processing some - # source, exit to state 0 - # - # unless we encounter something like: - # - # /*@..... - # /*#..... - # - # /* @..... - # /* #..... - # - if format >= 4 and l > 2 and line2[0 : 2] == '/*': - if l < 4 or ( line2[3] != '@' and line2[3:4] != ' @' and - line2[3] != '#' and line2[3:4] != ' #'): - list.append( ( block, source ) ) - format = 0 - - if format == 0: #### wait for beginning of comment #### - - if l > 3 and line2[0 : 3] == '/**': - i = 3 - while i < l and line2[i] == '*': - i = i + 1 - - if i == l: - # this is '/**' followed by any number of '*', the - # beginning of a Format 1 block - # - block = [] - source = [] - format = 1 - - elif i == l - 1 and line2[i] == '/': - # this is '/**' followed by any number of '*', followed - # by a '/', i.e. the beginning of a Format 2 or 3 block - # - block = [] - source = [] - format = 2 - - ############################################################## - # - # FORMAT 1 - # - elif format == 1: - - # if the line doesn't begin with a "*", something went - # wrong, and we must exit, and forget the current block.. - if l == 0 or line2[0] != '*': - block = [] - format = 0 - - # otherwise, we test for an end of block, which is an - # arbitrary number of '*', followed by '/' - else: - i = 1 - while i < l and line2[i] == '*': - i = i + 1 - - # test for the end of the block - if i < l and line2[i] == '/': - if block != []: - format = 4 - else: - format = 0 - else: - # otherwise simply append line to current block - block.append( line2 ) - - continue - - ############################################################## - # - # FORMAT 2 - # - elif format == 2: - - # if the line doesn't begin with '/*' and end with '*/', - # this is the end of the format 2 format - if l < 4 or line2[: 2] != '/*' or line2[-2 :] != '*/': - if block != []: - format = 4 - else: - format = 0 - else: - # remove the start and end comment delimiters, then - # right-strip the line - line2 = string.rstrip( line2[2 : -2] ) - - # check for end of a format2 block, i.e. a run of '*' - if string.count( line2, '*' ) == l - 4: - if block != []: - format = 4 - else: - format = 0 - else: - # otherwise, add the line to the current block - block.append( line2 ) - - continue - - - - if format >= 4: #### source processing #### - - if l > 0: - format = 5 - - if format == 5: - source.append( line ) - - - if format >= 4: - list.append( [block, source] ) - - return list - - - -# This function is only used for debugging -# -def dump_block_list( list ): - """dump a comment block list""" - for block in list: - print "----------------------------------------" - for line in block[0]: - print line - for line in block[1]: - print line - - print "---------the end-----------------------" - - ############################################################################## # # The DocCode class is used to store source code lines # +# self.lines contains a set of source code lines that will +# be dumped as HTML in a <PRE> tag. +# +# the object is filled line by line by the parser, it strips the +# leading "margin" space from each input line before storing it +# in self.lines +# class DocCode: def __init__( self, margin = 0 ): @@ -325,27 +165,26 @@ class DocCode: line = line[self.margin :] self.lines.append( line ) - - def dump( self ): - - max_width = 50 + def dump( self ): for line in self.lines: print "--" + line - print "" + def get_identifier( self ): + # this function should never be called + return "UNKNOWN_CODE_IDENTIFIER!!" def dump_html( self ): # clean the last empty lines l = len( self.lines ) - 1 - while len > 0 and string.strip( lines[len - 1] ) == "": - len = len - 1 + while l > 0 and string.strip( self.lines[l - 1] ) == "": + l = l - 1 print code_header - for line in self.lines[0 : len]: - print lines + for line in self.lines[0 : l]: + print line print code_footer @@ -354,6 +193,8 @@ class DocCode: # The DocParagraph is used to store text paragraphs # self.words is simply a list of words for the paragraph # +# the paragraph is filled line by line by the parser.. +# class DocParagraph: def __init__( self ): @@ -370,7 +211,16 @@ class DocParagraph: # last = len(self.words) self.words[last:last] = string.split( line ) - + + # this function is used to retrieve the first word of a given + # paragraph.. + def get_identifier( self ): + if self.words: + return self.words[0] + + # should never happen + return "UNKNOWN_PARA_IDENTIFIER!!" + def dump( self ): @@ -391,7 +241,7 @@ class DocParagraph: if cursor > 0: print line - print "" + #print "§" #for debugging only def dump_html( self ): @@ -428,6 +278,11 @@ class DocParagraph: # ( "x", [ DocParagraph ] ), # ( "y", [ DocParagraph, DocCode ] ) ] # +# in self.items +# +# the DocContent object is entirely built at creation time, you must +# pass a list of input text lines lin the "lines_list" parameter.. +# # class DocContent: @@ -436,10 +291,13 @@ class DocContent: code_mode = 0 code_margin = 0 text = [] - paragraph = None - code = None - elements = [] - field = None + paragraph = None # represents the current DocParagraph + code = None # represents the current DocCode + + elements = [] # the list of elements for the current field, + # contains DocParagraph or DocCode objects + + field = None # the current field for aline in lines_list: @@ -470,16 +328,21 @@ class DocContent: # the token `::' # if len( words ) >= 2 and words[1] == "::": + + # start a new field - complete current paragraph if any if paragraph: elements.append( paragraph ) paragraph = None + # append previous "field" to self.items self.items.append( ( field, elements ) ) + # start new field and elements list field = words[0] elements = [] words = words[2 :] - + + # append remaining words to current paragraph if len( words ) > 0: line = string.join( words ) if not paragraph: @@ -487,9 +350,12 @@ class DocContent: paragraph.add( line ) else: + # we're in code mode.. line = aline # the code block ends with a line that has a single '}' on it + # that is located at the same column that the opening + # accolade.. if line == " " * code_margin + '}': if code: @@ -514,6 +380,15 @@ class DocContent: self.items.append( ( field, elements ) ) + def get_identifier( self ): + if self.items: + item = self.items[0] + for element in item[1]: + return element.get_identifier() + + # should never happen + return "UNKNOWN_CONTENT_IDENTIFIER!!" + def dump( self ): for item in self.items: @@ -566,44 +441,67 @@ class DocContent: # The DocBlock class is used to store a given comment block. It contains # a list of markers, as well as a list of contents for each marker. # +# "self.items" is a list of ( marker, contents ) elements, where +# 'marker' is a lowercase marker string, and 'contents' is a DocContent +# object +# +# "self.source" is simply a list of text lines taken from the +# uncommented source itself.. +# +# finally, "self.identifier" is a simple identifier used to +# uniquely identify the block # class DocBlock: def __init__( self, block_line_list = [], source_line_list = [] ): - self.markers = [] - self.contents = [] - self.source = source_line_list - - marker = "" - content = [] - alphanum = string.letters + string.digits + "_" + self.items = [] # current ( marker, contents ) list + self.identifier = None + marker = None # current marker + content = [] # current content lines list + alphanum = string.letters + string.digits + "_" for line in block_line_list: line2 = string.lstrip( line ) l = len( line2 ) margin = len( line ) - l - - if l > 3 and line2[0] == '<': - i = 1 - while i < l and line2[i] in alphanum: - i = i + 1 - if i < l and line2[i] == '>': - if marker or content: - self.add( marker, content ) - marker = line2[1 : i] - content = [] - line2 = string.lstrip( line2[i + 1 :] ) - l = len( line2 ) - line = " " * margin + line2 + + if l > 3: + ender = None + if line2[0] == '<': + ender = '>' + elif line2[0] == '@': + ender = ':' + + if ender: + i = 1 + while i < l and line2[i] in alphanum: + i = i + 1 + if i < l and line2[i] == ender: + if marker and content: + self.add( marker, content ) + marker = line2[1 : i] + content = [] + line2 = string.lstrip( line2[i + 1 :] ) + l = len( line2 ) + line = " " * margin + line2 content.append( line ) - if marker or content: + if marker and content: self.add( marker, content ) - + self.source = [] + if self.items: + self.source = source_line_list + + + # this function is used to add a new element to self.items + # 'marker' is a marker string, or None + # 'lines' is a list of text lines used to compute a list of + # DocContent objects + # def add( self, marker, lines ): - + # remove the first and last empty lines from the content list l = len( lines ) if l > 0: @@ -617,115 +515,289 @@ class DocBlock: # add a new marker only if its marker and its content list aren't empty if l > 0 and marker: - self.markers.append( marker ) - self.contents.append( lines ) + content = DocContent(lines) + self.items.append( ( string.lower(marker), content ) ) + if not self.identifier: + self.identifier = content.get_identifier() + + def dump( self ): - for i in range( len( self.markers ) ): - print "[" + self.markers[i] + "]" - for line in self.contents[i]: - print "-- " + line + for i in range( len( self.items ) ): + print "[" + self.items[i][0] + "]" + content = self.items[i][1] + content.dump() - def doc_contents( self ): - contents = [] - for item in self.contents: - contents.append( DocContent( item ) ) - return contents + def dump_html( self ): + + types = [ 'type', 'struct', 'functype', 'function', 'constant', + 'enum', 'macro' ] + if not self.items: + return + + # start of a block + print block_header + + print "<h2>" + self.identifier + "</h2>" -def dump_doc_blocks( block_list ): - for block in block_list: - docblock = DocBlock( block ) - docblock.dump() - print "<<------------------->>" + # print source code + if not self.source: + return + + lines = self.source + l = len( lines ) - 1 + while l >= 0 and string.strip( lines[l] ) == "": + l = l - 1 + print source_header + for line in lines[0 : l + 1]: + print line + print source_footer + # dump each (marker,content) element + for element in self.items: + + marker = element[0] + content = element[1] + if marker == "description": + print "<ul>" + content.dump_html() + print "</ul>" + + elif not (marker in types): + print "<h4>" + marker + "</h4>" + print "<ul>" + content.dump_html() + print "</ul>" + + print "" + + print block_footer + + +# filter a given list of DocBlocks. Returns a new list +# of DocBlock objects that only contains element whose +# "type" (i.e. first marker) is in the "types" parameter # -# -# -def dump_single_content( block_list ): +def filter_blocks( block_list, types ): + + new_list = [] + for block in block_list: + if block.items: + element = block.items[0] + marker = element[0] + if marker in types: + new_list.append( block ) - block = block_list[0] - docblock = DocBlock( block ) + return new_list - print "<block>" - for i in range( len( docblock.markers ) ): - marker = docblock.markers[i] - contents = docblock.contents[i] - - print "<marker " + marker + ">" - doccontent = DocContent( contents ) - doccontent.dump() - - print "</marker>" +# perform a lexicographical comparison of two DocBlock +# objects. Returns -1, 0 or 1 +# +def block_lexicographical_compare( b1, b2 ): + if not b1.identifier: + return -1 + if not b2.identifier: + return 1 - print "</block>" + id1 = string.lower(b1.identifier) + id2 = string.lower(b2.identifier) + if id1 < id2: + return -1 + elif id1 == id2: + return 0 + else: + return 1 + +def block_make_list( source_block_list ): + list = [] -def dump_doc_contents( block_list ): + for block in source_block_list: + docblock = DocBlock( block[0], block[1] ) + list.append( docblock ) - for block in block_list: - docblock = DocBlock( block ) - print "<block>" - - for i in range( len( docblock.markers ) ): - print "<marker " + docblock.markers[i] + ">" - content = DocContent( docblock.contents[i] ) - content.dump() - print "</marker>" - print "</block>" + return list +# dump a list block as a single HTML page +# def dump_html_1( block_list ): - + print html_header - types = [ 'Type', 'Struct', 'FuncType', 'Function', 'Constant', - 'Enumeration' ] - for block in block_list: + block.dump_html() - docblock = DocBlock( block[0], block[1] ) - - if len( docblock.markers ) == 0: - continue + print html_footer - print block_header - for i in range( len( docblock.markers ) ): - marker = docblock.markers[i] - content = docblock.contents[i] - dcontent = DocContent( content ) - - if marker == "Description": - print "<ul><p>" - dcontent.dump() - print "</p></ul>" - - elif marker in types: - print "<h3><font color=blue>" + content[0] + "</font></h3>" - else: - print "<h4>" + marker + "</h4>" - print "<ul><p>" - dcontent.dump_html() - print "</p></ul>" - - print "" - print block_footer - - # print source code - lines = block[1] - l = len( lines ) - 1 - while l >= 0 and string.strip( lines[l] ) == "": - l = l - 1 - print source_header - for line in lines[0 : l + 1]: - print line - print source_footer - - print html_footer + +def make_block_list(): + """parse a file and extract comments blocks from it""" + + list = [] + block = [] + format = 0 + + # we use "format" to store the state of our parser: + # + # 0 - wait for beginning of comment + # 1 - parse comment format 1 + # 2 - parse comment format 2 + # + # 4 - wait for beginning of source (or comment ??) + # 5 - process source + # + + comment = [] + source = [] + state = 0 + + for line in fileinput.input(): + + l = len( line ) + if l > 0 and line[l - 1] == '\012': + line = line[0 : l - 1] + + # stripped version of the line + line2 = string.strip( line ) + l = len( line2 ) + + # if this line begins with a comment and we are processing some + # source, exit to state 0 + # + # unless we encounter something like: + # + # /*@..... + # /*#..... + # + # /* @..... + # /* #..... + # + if format >= 4 and l > 2 and line2[0 : 2] == '/*': + if l < 4 or ( line2[3] != '@' and line2[3:4] != ' @' and + line2[3] != '#' and line2[3:4] != ' #'): + list.append( ( block, source ) ) + format = 0 + + if format == 0: #### wait for beginning of comment #### + + if l > 3 and line2[0 : 3] == '/**': + i = 3 + while i < l and line2[i] == '*': + i = i + 1 + + if i == l: + # this is '/**' followed by any number of '*', the + # beginning of a Format 1 block + # + block = [] + source = [] + format = 1 + + elif i == l - 1 and line2[i] == '/': + # this is '/**' followed by any number of '*', followed + # by a '/', i.e. the beginning of a Format 2 or 3 block + # + block = [] + source = [] + format = 2 + + ############################################################## + # + # FORMAT 1 + # + elif format == 1: + + # if the line doesn't begin with a "*", something went + # wrong, and we must exit, and forget the current block.. + if l == 0 or line2[0] != '*': + block = [] + format = 0 + + # otherwise, we test for an end of block, which is an + # arbitrary number of '*', followed by '/' + else: + i = 1 + while i < l and line2[i] == '*': + i = i + 1 + + # test for the end of the block + if i < l and line2[i] == '/': + if block != []: + format = 4 + else: + format = 0 + else: + # otherwise simply append line to current block + block.append( line2[i:] ) + + continue + + ############################################################## + # + # FORMAT 2 + # + elif format == 2: + + # if the line doesn't begin with '/*' and end with '*/', + # this is the end of the format 2 format + if l < 4 or line2[: 2] != '/*' or line2[-2 :] != '*/': + if block != []: + format = 4 + else: + format = 0 + else: + # remove the start and end comment delimiters, then + # right-strip the line + line2 = string.rstrip( line2[2 : -2] ) + + # check for end of a format2 block, i.e. a run of '*' + if string.count( line2, '*' ) == l - 4: + if block != []: + format = 4 + else: + format = 0 + else: + # otherwise, add the line to the current block + block.append( line2 ) + + continue + + + + if format >= 4: #### source processing #### + + if l > 0: + format = 5 + + if format == 5: + source.append( line ) + + + if format >= 4: + list.append( [block, source] ) + + return list + + + +# This function is only used for debugging +# +def dump_block_list( list ): + """dump a comment block list""" + for block in list: + print "----------------------------------------" + for line in block[0]: + print line + for line in block[1]: + print line + + print "---------the end-----------------------" @@ -733,8 +805,16 @@ def main( argv ): """main program loop""" sys.stderr.write( "extracting comment blocks from sources...\n" ) list = make_block_list() + list = block_make_list(list) - dump_html_1( list ) + list2 = filter_blocks( list, ['type','macro','enum','constant', 'functype'] ) + #list2 = list + list2.sort( block_lexicographical_compare ) + + dump_html_1( list2 ) + #dump_doc_blocks( list ) + #dump_block_lists( list ) + #dump_html_1( list ) # If called from the command line |