From 6d315e33bd750d74a4943208ae2de04a49545713 Mon Sep 17 00:00:00 2001 From: David Turner Date: Mon, 21 Aug 2000 23:01:32 +0000 Subject: [PATCH] significant updates. The generated HTML is now much more pleasant.. --- docs/docmaker.py | 534 ++++++++++++++++++++++++++++++----------------- 1 file changed, 339 insertions(+), 195 deletions(-) diff --git a/docs/docmaker.py b/docs/docmaker.py index 5a6ea0e7b..5f35dbdb3 100644 --- a/docs/docmaker.py +++ b/docs/docmaker.py @@ -6,8 +6,56 @@ import fileinput, sys, string -# This function is used to parse a source file, and extract comment blocks -# from it. The following comment block formats are recognized : +html_header = """ + +
+FreeType 2 API Reference + + +
+ +

FreeType 2 API Reference

+
+
+""" + +html_footer = """ +
+ + +""" + +code_header = """ +
+"""
+
+code_footer = """
+
+""" + +para_header = "

" +para_footer = "

" + +block_header = """
""" +block_footer = "
" + +source_header = """
+"""
+source_footer = """
+

+""" + +# The FreeType 2 reference is extracted from the source files. These contain +# various comment blocks that follow one of the following formats: # # /************************** # * @@ -35,9 +83,31 @@ import fileinput, sys, string # /* */ # /**************************/ # -# Each block is modeled as a simple list of text strings -# The function returns a list of blocks, i.e. a list of strings lists +# Each block contains a list of markers, each one can be followed by +# some arbitrary text or a list of fields. Here's an example: # +# +# MyStruct +# +# +# this structure holds some data +# +# +# x :: horizontal coordinate +# y :: vertical coordinate +# +# +# This example defines three markers: 'Struct', 'Description' & 'Fields' +# The first two markers contain arbitrary text, while the last one contains +# a list of field +# +# +# each field is simple of the format: WORD :: TEXT.... +# +# Note that typically, each comment block is followed by some source +# code declaration that may need to be kept in the reference.. +# + def make_block_list(): """parse a file and extract comments blocks from it""" @@ -45,32 +115,61 @@ def make_block_list(): 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(): - line = string.strip(line) - l = len(line) + # remove trailing CR + l = len(line) + if l > 0 and line[l-1] == '\012': + line = line[0:l-1] - if format == 0: - if l > 3 and line[0:3] == '/**': + # stripped version of the line + line2 = string.strip(line) + l = len(line2) + + # if this line begins with a comment and we're processing some source, exit + # to state 0 + # + if format >= 4 and l > 2 and line2[0:2] == '/*': + list.append( (block,source) ) + format = 0 + + if format == 0: ##################### wait beginning of comment ########### + if l > 3 and line2[0:3] == '/**': i = 3 - while (i < l) and (line[i] == '*'): + 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 = []; - format = 1; + block = [] + source = [] + format = 1 - elif (i == l-1) and (line[i] == '/'): + 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 = []; - format = 2; - + block = [] + source = [] + format = 2 + ############################################################## # # FORMAT 1 @@ -79,7 +178,7 @@ def make_block_list(): # if the line doesn't begin with a "*", something went # wrong, and we must exit, and forget the current block.. - if (l == 0) or (line[0] != '*'): + if (l == 0) or (line2[0] != '*'): block = [] format = 0 @@ -87,17 +186,19 @@ def make_block_list(): # arbitrary number of '*', followed by '/' else: i = 1 - while (i < l) and (line[i] == '*'): + while (i < l) and (line2[i] == '*'): i = i+1 # test for the end of the block - if (i < l) and (line[i] == '/'): - if block != []: list.append( block ) - format = 0 - block = [] - + if (i < l) and (line2[i] == '/'): + if block != []: + format = 4 + else: + format = 0 else: - block.append( line[1:] ) + # otherwise simply append line to current block + block.append(line2) + continue ############################################################## # @@ -107,27 +208,47 @@ def make_block_list(): # if the line doesn't begin with '/*' and end with '*/', # this is the end of the format 2 format.. - if (l < 4 ) or (line[:2] != '/*') or (line[-2:] != '*/'): - if block != []: list.append(block) - block = [] - format = 0 - continue - - # remove the start and end comment delimiters, then right-strip - # the line - line = string.rstrip(line[2:-2]) - - # check for end of a format2 block, i.e. a run of '*' - if string.count(line,'*') == l-4: - if block != []: list.append(block) - block = [] - format = 0 + if (l < 4 ) or (line2[:2] != '/*') or (line2[-2:] != '*/'): + if block != []: + format = 4 + else: + format = 0 else: - # otherwise, add the line to the current block - block.append(line) + # 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 # @@ -135,118 +256,117 @@ def dump_block_list( list ): """dump a comment block list""" for block in list: print "----------------------------------------" - for line in block: - print line + 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 +# +class DocCode: - -###################################################################################### -# -# -# The DocParagraph is used to store either simple text paragraph or -# source code lines -# -# -# If the paragraph contains source code (use code=1 when initializing the -# object), self.lines is a list of source code strings -# -# Otherwise, self.lines is simply a list of words for the paragraph -# -class DocParagraph: - - def __init__(self,code=0,margin=0): + def __init__(self,margin=0): self.lines = [] - self.code = code self.margin = margin def add(self,line): - - if self.code==0: - # get rid of unwanted spaces in the paragraph - self.lines.extend( string.split(line) ) - - else: - # remove margin whitespace - if string.strip( line[:self.margin] ) == "": line = line[self.margin:] - self.lines.append(line) + # remove margin whitespace + if string.strip( line[:self.margin] ) == "": line = line[self.margin:] + self.lines.append(line) def dump(self): max_width = 50 - if self.code == 0: - cursor = 0 - line = "" - - for word in self.lines: + for line in self.lines: + print "--" + line - if cursor+len(word)+1 > max_width: - print line - cursor = 0 - line = "" - - line = line + word + " " - cursor = cursor + len(word) + 1 - - if cursor > 0: - print line - - else: - for line in self.lines: - print "--" + line - print "" -###################################################################################### + 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 + + print code_header + for line in self.lines[0:len]: + print lines + print code_footer + + +############################################################################## # +# The DocParagraph is used to store either simple text paragraphs +# self.words is simply a list of words for the paragraph # -# The DocContent class is used to store the content of a given marker -# Each DocContent can have its own text, plus a list of fields. Each field -# has its own text too +class DocParagraph: + + def __init__(self): + self.words = [] + + def add(self,line): + # get rid of unwanted spaces in the paragraph + self.words.extend( string.split(line) ) + + + def dump(self): + + max_width = 50 + cursor = 0 + line = "" + + for word in self.words: + + if cursor+len(word)+1 > max_width: + print line + cursor = 0 + line = "" + + line = line + word + " " + cursor = cursor + len(word) + 1 + + if cursor > 0: + print line + + print "" + + + def dump_html(self): + + print para_header + self.dump() + print para_footer + + +########################################################################### # -# Hence, the following lines : +# DocContent is used to store the content of a given marker. # -# """ -# Some arbitraty text: -# -# fieldone :: some arbitraty text for this field, -# note that the text stretches to several lines -# -# fieldtwo :: some other text -# -# """ -# -# will be stored as (each text is a list of string: -# -# self.fields = [ "", "fieldone", "fieldtwo" ] -# self.texts = [ -# [ "some arbitraty text for this field," , -# "note that the text stretches to several lines" ], -# -# [ "some other text" ] -# ] # # class DocContent: - def __init__(self, paragraph_lines=[]): - - self.fields = [] - self.texts = [] - - code_mode = 0 - code_margin = 0 - - field = "" - text = [] - paragraph = None + def __init__(self,lines_list): + self.items = [] + code_mode = 0 + code_margin = 0 + text = [] + paragraph = None + code = None + elements = [] + field = None - for aline in paragraph_lines: + for aline in lines_list: if code_mode == 0: line = string.lstrip(aline) @@ -255,39 +375,35 @@ class DocContent: # if the line is empty, this is the end of the current # paragraph - if line == "": + if l == 0 or line == '{': + if paragraph: - text.append(paragraph) - paragraph = None - continue - - # test for the beginning of a code block, i.e.'{' is the first - # and only character on the line.. - # - if line == '{': - code_mode = 1 - code_margin = margin - if paragraph: - text.append(paragraph) - paragraph = DocParagraph( 1, margin ) - continue + elements.append(paragraph) + paragraph = None + + if line == "": + continue + + code_mode = 1 + code_margin = margin + code = None + continue words = string.split(line) # test for a field delimiter on the start of the line, i.e. - # the oken `::' + # the token `::' # if len(words) >= 2 and words[1] == "::": if paragraph: - text.append(paragraph) - paragraph = None - - self.fields.append(field) - self.texts.append(text) + elements.append(paragraph) + paragraph = None + + self.items.append( (field,elements) ) - field = words[0] - text = [] - words = words[2:] + field = words[0] + elements = [] + words = words[2:] if len(words) > 0: line = string.join(words) @@ -300,60 +416,73 @@ class DocContent: # the code block ends with a line that has a single '}' on it if line == " "*code_margin+'}': - text.append(paragraph) - paragraph = None + + if code: + elements.append(code) + code = None + code_mode = 0 code_margin = 0 # otherwise, add the line to the current paragraph else: - paragraph.add(line) + if not code: + code = DocCode() + code.add(line) if paragraph: - text.append(paragraph) + elements.append(paragraph) + + if code: + elements.append(code) - self.fields.append( field ) - self.texts.append( text ) + self.items.append( (field,elements) ) + - def dump(self): - for i in range(len(self.fields)): - field = self.fields[i] - if field: print "" + for item in self.items: + field = item[0] + if field: + print "" - for paras in self.texts[i]: - paras.dump() + for element in item[1]: + element.dump() - if field: print " " + if field: + print " " def dump_html(self): - n = len(self.fields) + + n = len(self.items) + in_table = 0 + for i in range(n): - field = self.fields[i] - if field==[]: - print "

" - for paras in self.texts[i]: - print "

" - paras.dump() - print "

" + item = self.items[i] + field = item[0] + + if not field: + + if in_table: + print "" + in_table = 0 + + for element in item[1]: + element.dump_html() else: - if i==1: + if not in_table: print "" - if n > 1: - print "
" + in_table = 1 else: print "
" print ""+field+"" - for paras in self.texts[i]: - print "

" - paras.dump() - print "

" - - print "
" - + for element in item[1]: + element.dump_html() + + if in_table: + print "" ###################################################################################### # @@ -364,9 +493,10 @@ class DocContent: # class DocBlock: - def __init__(self, block_line_list=[]): + def __init__(self, block_line_list=[], source_line_list=[]): self.markers = [] self.contents = [] + self.source = source_line_list marker = "" content = [] @@ -468,11 +598,18 @@ def dump_doc_contents( block_list ): def dump_html_1( block_list ): - print "" + print html_header + types = [ 'Type', 'Struct', 'FuncType', 'Function', 'Constant', 'Enumeration' ] for block in block_list: - docblock = DocBlock(block) - print "
" + + docblock = DocBlock(block[0],block[1]) + + if len(docblock.markers) == 0: + continue + + print block_header + for i in range(len(docblock.markers)): marker = docblock.markers[i] content = docblock.contents[i] @@ -492,25 +629,32 @@ def dump_html_1( block_list ): print "

" 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 "
" - + print html_footer + + + + def main(argv): """main program loop""" print "extracting comment blocks from sources .." list = make_block_list() -# dump_block_list( list ) + dump_html_1( list ) -# dump_doc_blocks( list ) - -# print "dumping block contents .." -# dump_doc_contents(list) - - dump_html_1(list) - -# dump_single_content(list) # If called from the command line if __name__=='__main__': main(sys.argv)