ref: 48721c11b549480e9d3eaa3671866d9aa9d01ab1
parent: f95a603117672c12ff4a00e680519db17b21cf7b
author: David Turner <[email protected]>
date: Mon Aug 21 19:01:32 EDT 2000
significant updates. The generated HTML is now much more pleasant..
--- 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 = """
+<html>
+<header>
+<title>FreeType 2 API Reference</title>
+<basefont face="Georgia, Arial, Helvetica, Geneva">
+<style content="text/css">
+ P { text-align=justify }
+ H1 { text-align=center }
+ H2 { text-align=center }
+ LI { text-align=justify }
+</style>
+</header>
+<body text="#000000"
+ bgcolor="#FFFFFF"
+ link="#0000EF"
+ 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>
+"""
+
+code_header = """
+<font color=blue><pre>
+"""
+
+code_footer = """
+</pre></font>
+"""
+
+para_header = "<p>"
+para_footer = "</p>"
+
+block_header = """<table width="100%"><tr><td>"""
+block_footer = "</table>"
+
+source_header = """<table width="100%"><tr bgcolor="#D6E8FF" width="100%"><td><pre>
+"""
+source_footer = """</pre></table>
+<br><br>
+"""
+
+# The FreeType 2 reference is extracted from the source files. These contain
+# various comment blocks that follow one of the following formats:
#
# /**************************
# *
@@ -35,10 +83,32 @@
# /* */
# /**************************/
#
-# 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:
#
+# <Struct>
+# MyStruct
+#
+# <Description>
+# this structure holds some data
+#
+# <Fields>
+# 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,16 +115,43 @@
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:
@@ -61,16 +158,18 @@
# 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 @@
# 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 @@
# 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,28 +208,48 @@
# 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
+ 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])
- # 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(line2,'*') == l-4:
+ if block != []:
+ format = 4
+ else:
+ format = 0
+ else:
+ # otherwise, add the line to the current block
+ block.append(line2)
+
+ continue
- # 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
- else:
- # otherwise, add the line to the current block
- block.append(line)
+
+ 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 ):
@@ -135,43 +256,29 @@
"""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
#
-# 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:
+class DocCode:
- 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):
@@ -178,75 +285,88 @@
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 = ""
+ print ""
- 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 @@
# 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
+ elements.append(paragraph)
+ paragraph = None
+
+ if line == "":
+ continue
+
+ code_mode = 1
+ code_margin = margin
+ code = 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
-
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,61 +416,74 @@
# 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 "<field "+field+">"
+ for item in self.items:
+ field = item[0]
+ if field:
+ print "<field "+field+">"
- for paras in self.texts[i]:
- paras.dump()
+ for element in item[1]:
+ element.dump()
- if field: print "</field> "
+ if field:
+ print "</field> "
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 "<p>"
- for paras in self.texts[i]:
- print "<p>"
- paras.dump()
- print "</p>"
+ item = self.items[i]
+ field = item[0]
+
+ if not field:
+
+ if in_table:
+ print "</td></tr></table>"
+ in_table = 0
+
+ for element in item[1]:
+ element.dump_html()
else:
- if i==1:
+ if not in_table:
print "<table cellpadding=4><tr valign=top><td>"
+ in_table = 1
else:
print "</td></tr><tr valign=top><td>"
print "<b>"+field+"</b></td><td>"
- for paras in self.texts[i]:
- print "<p>"
- paras.dump()
- print "</p>"
-
- print "</td></tr>"
- if n > 1:
- print "</table>"
-
+ for element in item[1]:
+ element.dump_html()
+ if in_table:
+ print "</td></tr></table>"
+
######################################################################################
#
#
@@ -364,9 +493,10 @@
#
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_html_1( block_list ):
- print "<html><body>"
+ print html_header
+
types = [ 'Type', 'Struct', 'FuncType', 'Function', 'Constant', 'Enumeration' ]
for block in block_list:
- docblock = DocBlock(block)
- print "<hr>"
+
+ 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 @@
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 "<hr></body></html>"
-
+ 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)