507 lines
15 KiB
Python
507 lines
15 KiB
Python
from sources import *
|
|
from content import *
|
|
from formatter import *
|
|
|
|
import time
|
|
|
|
# The following defines the HTML header used by all generated pages.
|
|
#
|
|
html_header_1 = """\
|
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
|
"http://www.w3.org/TR/html4/loose.dtd">
|
|
<html>
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
|
<title>"""
|
|
|
|
html_header_2= """ API Reference</title>
|
|
<style type="text/css">
|
|
body { font-family: Verdana, Geneva, Arial, Helvetica, serif;
|
|
color: #000000;
|
|
background: #FFFFFF; }
|
|
|
|
p { text-align: justify; }
|
|
h1 { text-align: center; }
|
|
li { text-align: justify; }
|
|
td { padding: 0 0.5em 0 0.5em }
|
|
|
|
a:link { color: #0000EF; }
|
|
a:visited { color: #51188E; }
|
|
a:hover { color: #FF0000; }
|
|
|
|
span.keyword { font-family: monospace;
|
|
text-align: left;
|
|
white-space: pre;
|
|
color: darkblue; }
|
|
|
|
pre.colored { color: blue; }
|
|
|
|
ul.empty { list-style-type: none; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<center><h1>"""
|
|
|
|
html_header_3=""" API Reference</h1></center>
|
|
"""
|
|
|
|
|
|
|
|
# The HTML footer used by all generated pages.
|
|
#
|
|
html_footer = """\
|
|
</body>
|
|
</html>"""
|
|
|
|
# The header and footer used for each section.
|
|
#
|
|
section_title_header = "<center><h1>"
|
|
section_title_footer = "</h1></center>"
|
|
|
|
# The header and footer used for code segments.
|
|
#
|
|
code_header = '<pre class="colored">'
|
|
code_footer = '</pre>'
|
|
|
|
# Paragraph header and footer.
|
|
#
|
|
para_header = "<p>"
|
|
para_footer = "</p>"
|
|
|
|
# Block header and footer.
|
|
#
|
|
block_header = '<table align=center width="75%"><tr><td>'
|
|
block_footer = '</td></tr></table><hr width="75%">'
|
|
|
|
# Description header/footer.
|
|
#
|
|
description_header = '<table align=center width="87%"><tr><td>'
|
|
description_footer = "</td></tr></table><br>"
|
|
|
|
# Marker header/inter/footer combination.
|
|
#
|
|
marker_header = '<table align=center width="87%" cellpadding=5><tr bgcolor="#EEEEFF"><td><em><b>'
|
|
marker_inter = "</b></em></td></tr><tr><td>"
|
|
marker_footer = "</td></tr></table>"
|
|
|
|
# Source code extracts header/footer.
|
|
#
|
|
source_header = '<table align=center width="87%"><tr bgcolor="#D6E8FF"><td><pre>\n'
|
|
source_footer = "\n</pre></table><br>"
|
|
|
|
# Chapter header/inter/footer.
|
|
#
|
|
chapter_header = '<br><table align=center width="75%"><tr><td><h2>'
|
|
chapter_inter = '</h2><ul class="empty"><li>'
|
|
chapter_footer = '</li></ul></td></tr></table>'
|
|
|
|
|
|
# source language keyword coloration/styling
|
|
#
|
|
keyword_prefix = '<span class="keyword">'
|
|
keyword_suffix = '</span>'
|
|
|
|
section_synopsis_header = '<h2>Synopsis</h2>'
|
|
section_synopsis_footer = ''
|
|
|
|
# Translate a single line of source to HTML. This will convert
|
|
# a "<" into "<.", ">" into ">.", etc.
|
|
#
|
|
def html_quote( line ):
|
|
result = string.replace( line, "&", "&" )
|
|
result = string.replace( result, "<", "<" )
|
|
result = string.replace( result, ">", ">" )
|
|
return result
|
|
|
|
|
|
# same as 'html_quote', but ignores left and right brackets
|
|
#
|
|
def html_quote0( line ):
|
|
return string.replace( line, "&", "&" )
|
|
|
|
|
|
def dump_html_code( lines, prefix = "" ):
|
|
# clean the last empty lines
|
|
#
|
|
l = len( self.lines )
|
|
while l > 0 and string.strip( self.lines[l - 1] ) == "":
|
|
l = l - 1
|
|
|
|
# The code footer should be directly appended to the last code
|
|
# line to avoid an additional blank line.
|
|
#
|
|
print prefix + code_header,
|
|
for line in self.lines[0 : l+1]:
|
|
print '\n' + prefix + html_quote(line),
|
|
print prefix + code_footer,
|
|
|
|
|
|
|
|
class HtmlFormatter(Formatter):
|
|
|
|
def __init__( self, processor, project_title, file_prefix ):
|
|
|
|
Formatter.__init__( self, processor )
|
|
|
|
global html_header_1, html_header_2, html_header_3, html_footer
|
|
|
|
if file_prefix:
|
|
file_prefix = file_prefix + "-"
|
|
else:
|
|
file_prefix = ""
|
|
|
|
self.project_title = project_title
|
|
self.file_prefix = file_prefix
|
|
self.html_header = html_header_1 + project_title + html_header_2 + \
|
|
project_title + html_header_3
|
|
|
|
self.html_footer = "<center><font size=""-2"">generated on " + \
|
|
time.asctime( time.localtime( time.time() ) ) + \
|
|
"</font></center>" + html_footer
|
|
|
|
self.columns = 3
|
|
|
|
def make_section_url( self, section ):
|
|
return self.file_prefix + section.name + ".html"
|
|
|
|
|
|
def make_block_url( self, block ):
|
|
return self.make_section_url( block.section ) + "#" + block.name
|
|
|
|
|
|
def make_html_words( self, words ):
|
|
""" convert a series of simple words into some HTML text """
|
|
line = ""
|
|
if words:
|
|
line = html_quote( words[0] )
|
|
for w in words[1:]:
|
|
line = line + " " + html_quote( w )
|
|
|
|
return line
|
|
|
|
|
|
def make_html_word( self, word ):
|
|
"""analyze a simple word to detect cross-references and styling"""
|
|
# look for cross-references
|
|
#
|
|
m = re_crossref.match( word )
|
|
if m:
|
|
try:
|
|
name = m.group(1)
|
|
rest = m.group(2)
|
|
block = self.identifiers[name]
|
|
url = self.make_block_url( block )
|
|
return '<a href="' + url + '">' + name + '</a>' + rest
|
|
except:
|
|
# we detected a cross-reference to an unknown item
|
|
sys.stderr.write( \
|
|
"WARNING: undefined cross reference '" + name + "'.\n" )
|
|
return '?' + name + '?' + rest
|
|
|
|
# look for italics and bolds
|
|
m = re_italic.match( word )
|
|
if m:
|
|
name = m.group(1)
|
|
rest = m.group(3)
|
|
return '<i>' + name + '</i>' + rest
|
|
|
|
m = re_bold.match( word )
|
|
if m:
|
|
name = m.group(1)
|
|
rest = m.group(3)
|
|
return '<b>' + name + '</b>' + rest
|
|
|
|
return html_quote(word)
|
|
|
|
|
|
def make_html_para( self, words ):
|
|
""" convert a paragraph's words into tagged HTML text, handle xrefs """
|
|
line = ""
|
|
if words:
|
|
line = self.make_html_word( words[0] )
|
|
for word in words[1:]:
|
|
line = line + " " + self.make_html_word( word )
|
|
# convert `...' quotations into real left and right single quotes
|
|
line = re.sub( r"(^|\W)`(.*?)'(\W|$)",
|
|
r'\1‘\2’\3',
|
|
line )
|
|
|
|
return para_header + line + para_footer
|
|
|
|
|
|
def make_html_code( self, lines ):
|
|
""" convert a code sequence to HTML """
|
|
line = code_header + '\n'
|
|
for l in lines:
|
|
line = line + html_quote( l ) + '\n'
|
|
|
|
return line + code_footer
|
|
|
|
|
|
def make_html_items( self, items ):
|
|
""" convert a field's content into some valid HTML """
|
|
lines = []
|
|
for item in items:
|
|
if item.lines:
|
|
lines.append( self.make_html_code( item.lines ) )
|
|
else:
|
|
lines.append( self.make_html_para( item.words ) )
|
|
|
|
return string.join( lines, '\n' )
|
|
|
|
|
|
def print_html_items( self, items ):
|
|
print self.make_html_items( items )
|
|
|
|
|
|
def print_html_field( self, field ):
|
|
if field.name:
|
|
print "<table><tr valign=top><td><p><b>"+field.name+"</b></p></td><td>"
|
|
|
|
print self.make_html_items( field.items )
|
|
|
|
if field.name:
|
|
print "</td></tr></table>"
|
|
|
|
|
|
def html_source_quote( self, line, block_name = None ):
|
|
result = ""
|
|
while line:
|
|
m = re_source_crossref.match( line )
|
|
if m:
|
|
name = m.group(2)
|
|
prefix = html_quote( m.group(1) )
|
|
length = len( m.group(0) )
|
|
|
|
if name == block_name:
|
|
# this is the current block name, if any
|
|
result = result + prefix + '<b>' + name + '</b>'
|
|
|
|
elif re_source_keywords.match(name):
|
|
# this is a C keyword
|
|
result = result + prefix + keyword_prefix + name + keyword_suffix
|
|
|
|
elif self.identifiers.has_key(name):
|
|
# this is a known identifier
|
|
block = self.identifiers[name]
|
|
result = result + prefix + '<a href="' + \
|
|
self.make_block_url(block) + '">' + name + '</a>'
|
|
else:
|
|
result = result + html_quote(line[:length])
|
|
|
|
line = line[length:]
|
|
else:
|
|
result = result + html_quote(line)
|
|
line = []
|
|
|
|
return result
|
|
|
|
|
|
def print_html_field_list( self, fields ):
|
|
print "<table cellpadding=3 border=0>"
|
|
for field in fields:
|
|
if len(field.name) > 22:
|
|
print "<tr valign=top><td colspan=0><b>"+field.name+"</b></td></tr>"
|
|
print "<tr valign=top><td></td><td>"
|
|
else:
|
|
print "<tr valign=top><td><b>" + field.name + "</b></td><td>"
|
|
|
|
self.print_html_items( field.items )
|
|
print "</td></tr>"
|
|
print "</table>"
|
|
|
|
|
|
def print_html_markup( self, markup ):
|
|
table_fields = []
|
|
for field in markup.fields:
|
|
if field.name:
|
|
# we begin a new series of field or value definitions, we
|
|
# will record them in the 'table_fields' list before outputting
|
|
# all of them as a single table
|
|
#
|
|
table_fields.append( field )
|
|
|
|
else:
|
|
if table_fields:
|
|
self.print_html_field_list( table_fields )
|
|
table_fields = []
|
|
|
|
self.print_html_items( field.items )
|
|
|
|
if table_fields:
|
|
self.print_html_field_list( table_fields )
|
|
|
|
#
|
|
# Formatting the index
|
|
#
|
|
|
|
def index_enter( self ):
|
|
print self.html_header
|
|
self.index_items = {}
|
|
|
|
def index_name_enter( self, name ):
|
|
block = self.identifiers[name]
|
|
url = self.make_block_url( block )
|
|
self.index_items[name] = url
|
|
|
|
def index_exit( self ):
|
|
|
|
# block_index already contains the sorted list of index names
|
|
count = len( self.block_index )
|
|
rows = (count + self.columns - 1)/self.columns
|
|
|
|
print "<table align=center border=0 cellpadding=0 cellspacing=0>"
|
|
for r in range(rows):
|
|
line = "<tr>"
|
|
for c in range(self.columns):
|
|
i = r + c*rows
|
|
if i < count:
|
|
bname = self.block_index[r + c * rows]
|
|
url = self.index_items[bname]
|
|
line = line + '<td><a href="' + url + '">' + bname + '</a></td>'
|
|
else:
|
|
line = line + '<td></td>'
|
|
line = line + "</tr>"
|
|
print line
|
|
|
|
print "</table>"
|
|
print self.html_footer
|
|
self.index_items = {}
|
|
|
|
def index_dump( self, index_filename = None ):
|
|
|
|
if index_filename == None:
|
|
index_filename = self.file_prefix + "index.html"
|
|
|
|
Formatter.index_dump( self, index_filename )
|
|
|
|
#
|
|
# Formatting the table of content
|
|
#
|
|
def toc_enter( self ):
|
|
print self.html_header
|
|
print "<center><h1>Table of Contents</h1></center>"
|
|
|
|
def toc_chapter_enter( self, chapter ):
|
|
print chapter_header + string.join(chapter.title) + chapter_inter
|
|
print "<table cellpadding=5>"
|
|
|
|
def toc_section_enter( self, section ):
|
|
print "<tr valign=top><td>"
|
|
print '<a href="' + self.make_section_url( section ) + '">' + \
|
|
section.title + '</a></td><td>'
|
|
|
|
print self.make_html_para( section.abstract )
|
|
|
|
def toc_section_exit( self, section ):
|
|
print "</td></tr>"
|
|
|
|
def toc_chapter_exit( self, chapter ):
|
|
print "</table>"
|
|
print chapter_footer
|
|
|
|
def toc_index( self, index_filename ):
|
|
print chapter_header + '<a href="' + index_filename + '">Global Index</a>' + chapter_inter + chapter_footer
|
|
|
|
def toc_exit( self ):
|
|
print self.html_footer
|
|
|
|
def toc_dump( self, toc_filename = None, index_filename = None ):
|
|
if toc_filename == None:
|
|
toc_filename = self.file_prefix + "toc.html"
|
|
|
|
if index_filename == None:
|
|
index_filename = self.file_prefix + "index.html"
|
|
|
|
Formatter.toc_dump( self, toc_filename, index_filename )
|
|
|
|
#
|
|
# Formatting sections
|
|
#
|
|
def section_enter( self, section ):
|
|
print self.html_header
|
|
|
|
print section_title_header
|
|
print section.title
|
|
print section_title_footer
|
|
|
|
maxwidth = 0
|
|
for b in section.blocks.values():
|
|
if len( b.name ) > maxwidth:
|
|
maxwidth = len( b.name )
|
|
|
|
width = 70 # XXX magic number
|
|
if maxwidth <> 0:
|
|
# print section synopsis
|
|
print section_synopsis_header
|
|
print "<table align=center cellspacing=5 cellpadding=0 border=0>"
|
|
|
|
columns = width / maxwidth
|
|
if columns < 1:
|
|
columns = 1
|
|
|
|
count = len( section.block_names )
|
|
rows = ( count + columns - 1 ) / columns
|
|
|
|
for r in range( rows ):
|
|
line = "<tr>"
|
|
for c in range( columns ):
|
|
i = r + c * rows
|
|
line = line + '<td></td><td>'
|
|
if i < count:
|
|
name = section.block_names[i]
|
|
line = line + '<a href="#' + name + '">' + name + '</a>'
|
|
|
|
line = line + '</td>'
|
|
line = line + "</tr>"
|
|
print line
|
|
|
|
print "</table><br><br>"
|
|
print section_synopsis_footer
|
|
|
|
print description_header
|
|
print self.make_html_items( section.description )
|
|
print description_footer
|
|
|
|
def block_enter( self, block ):
|
|
print block_header
|
|
|
|
# place html anchor if needed
|
|
if block.name:
|
|
print '<h4><a name="' + block.name + '">' + block.name + '</a></h4>'
|
|
|
|
# dump the block C source lines now
|
|
if block.code:
|
|
print source_header
|
|
for l in block.code:
|
|
print self.html_source_quote( l, block.name )
|
|
print source_footer
|
|
|
|
|
|
def markup_enter( self, markup, block ):
|
|
if markup.tag == "description":
|
|
print description_header
|
|
else:
|
|
print marker_header + markup.tag + marker_inter
|
|
|
|
self.print_html_markup( markup )
|
|
|
|
def markup_exit( self, markup, block ):
|
|
if markup.tag == "description":
|
|
print description_footer
|
|
else:
|
|
print marker_footer
|
|
|
|
def block_exit( self, block ):
|
|
print block_footer
|
|
|
|
|
|
def section_exit( self, section ):
|
|
print html_footer
|
|
|
|
|
|
def section_dump_all( self ):
|
|
for section in self.sections:
|
|
self.section_dump( section, self.file_prefix + section.name + '.html' )
|
|
|