1# ToHTML (c) 2002, 2003, 2005, 2006, 2007, 2008 2# David Turner <david@freetype.org> 3 4from sources import * 5from content import * 6from formatter import * 7 8import time 9 10 11# The following defines the HTML header used by all generated pages. 12html_header_1 = """\ 13<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 14"http://www.w3.org/TR/html4/loose.dtd"> 15<html> 16<head> 17<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 18<title>\ 19""" 20 21html_header_2 = """\ 22 API Reference</title> 23<style type="text/css"> 24 body { font-family: Verdana, Geneva, Arial, Helvetica, serif; 25 color: #000000; 26 background: #FFFFFF; } 27 28 p { text-align: justify; } 29 h1 { text-align: center; } 30 li { text-align: justify; } 31 td { padding: 0 0.5em 0 0.5em; } 32 td.left { padding: 0 0.5em 0 0.5em; 33 text-align: left; } 34 35 a:link { color: #0000EF; } 36 a:visited { color: #51188E; } 37 a:hover { color: #FF0000; } 38 39 span.keyword { font-family: monospace; 40 text-align: left; 41 white-space: pre; 42 color: darkblue; } 43 44 pre.colored { color: blue; } 45 46 ul.empty { list-style-type: none; } 47</style> 48</head> 49<body> 50""" 51 52html_header_3 = """ 53<table align=center><tr><td><font size=-1>[<a href="\ 54""" 55 56html_header_3i = """ 57<table align=center><tr><td width="100%"></td> 58<td><font size=-1>[<a href="\ 59""" 60 61html_header_4 = """\ 62">Index</a>]</font></td> 63<td width="100%"></td> 64<td><font size=-1>[<a href="\ 65""" 66 67html_header_5 = """\ 68">TOC</a>]</font></td></tr></table> 69<center><h1>\ 70""" 71 72html_header_5t = """\ 73">Index</a>]</font></td> 74<td width="100%"></td></tr></table> 75<center><h1>\ 76""" 77 78html_header_6 = """\ 79 API Reference</h1></center> 80""" 81 82 83# The HTML footer used by all generated pages. 84html_footer = """\ 85</body> 86</html>\ 87""" 88 89# The header and footer used for each section. 90section_title_header = "<center><h1>" 91section_title_footer = "</h1></center>" 92 93# The header and footer used for code segments. 94code_header = '<pre class="colored">' 95code_footer = '</pre>' 96 97# Paragraph header and footer. 98para_header = "<p>" 99para_footer = "</p>" 100 101# Block header and footer. 102block_header = '<table align=center width="75%"><tr><td>' 103block_footer_start = """\ 104</td></tr></table> 105<hr width="75%"> 106<table align=center width="75%"><tr><td><font size=-2>[<a href="\ 107""" 108block_footer_middle = """\ 109">Index</a>]</font></td> 110<td width="100%"></td> 111<td><font size=-2>[<a href="\ 112""" 113block_footer_end = """\ 114">TOC</a>]</font></td></tr></table> 115""" 116 117# Description header/footer. 118description_header = '<table align=center width="87%"><tr><td>' 119description_footer = "</td></tr></table><br>" 120 121# Marker header/inter/footer combination. 122marker_header = '<table align=center width="87%" cellpadding=5><tr bgcolor="#EEEEFF"><td><em><b>' 123marker_inter = "</b></em></td></tr><tr><td>" 124marker_footer = "</td></tr></table>" 125 126# Header location header/footer. 127header_location_header = '<table align=center width="87%"><tr><td>' 128header_location_footer = "</td></tr></table><br>" 129 130# Source code extracts header/footer. 131source_header = '<table align=center width="87%"><tr bgcolor="#D6E8FF"><td><pre>\n' 132source_footer = "\n</pre></table><br>" 133 134# Chapter header/inter/footer. 135chapter_header = '<br><table align=center width="75%"><tr><td><h2>' 136chapter_inter = '</h2><ul class="empty"><li>' 137chapter_footer = '</li></ul></td></tr></table>' 138 139# Index footer. 140index_footer_start = """\ 141<hr> 142<table><tr><td width="100%"></td> 143<td><font size=-2>[<a href="\ 144""" 145index_footer_end = """\ 146">TOC</a>]</font></td></tr></table> 147""" 148 149# TOC footer. 150toc_footer_start = """\ 151<hr> 152<table><tr><td><font size=-2>[<a href="\ 153""" 154toc_footer_end = """\ 155">Index</a>]</font></td> 156<td width="100%"></td> 157</tr></table> 158""" 159 160 161# source language keyword coloration/styling 162keyword_prefix = '<span class="keyword">' 163keyword_suffix = '</span>' 164 165section_synopsis_header = '<h2>Synopsis</h2>' 166section_synopsis_footer = '' 167 168 169# Translate a single line of source to HTML. This will convert 170# a "<" into "<.", ">" into ">.", etc. 171def html_quote( line ): 172 result = string.replace( line, "&", "&" ) 173 result = string.replace( result, "<", "<" ) 174 result = string.replace( result, ">", ">" ) 175 return result 176 177 178# same as 'html_quote', but ignores left and right brackets 179def html_quote0( line ): 180 return string.replace( line, "&", "&" ) 181 182 183def dump_html_code( lines, prefix = "" ): 184 # clean the last empty lines 185 l = len( self.lines ) 186 while l > 0 and string.strip( self.lines[l - 1] ) == "": 187 l = l - 1 188 189 # The code footer should be directly appended to the last code 190 # line to avoid an additional blank line. 191 print prefix + code_header, 192 for line in self.lines[0 : l + 1]: 193 print '\n' + prefix + html_quote( line ), 194 print prefix + code_footer, 195 196 197 198class HtmlFormatter( Formatter ): 199 200 def __init__( self, processor, project_title, file_prefix ): 201 Formatter.__init__( self, processor ) 202 203 global html_header_1, html_header_2, html_header_3 204 global html_header_4, html_header_5, html_footer 205 206 if file_prefix: 207 file_prefix = file_prefix + "-" 208 else: 209 file_prefix = "" 210 211 self.headers = processor.headers 212 self.project_title = project_title 213 self.file_prefix = file_prefix 214 self.html_header = html_header_1 + project_title + \ 215 html_header_2 + \ 216 html_header_3 + file_prefix + "index.html" + \ 217 html_header_4 + file_prefix + "toc.html" + \ 218 html_header_5 + project_title + \ 219 html_header_6 220 221 self.html_index_header = html_header_1 + project_title + \ 222 html_header_2 + \ 223 html_header_3i + file_prefix + "toc.html" + \ 224 html_header_5 + project_title + \ 225 html_header_6 226 227 self.html_toc_header = html_header_1 + project_title + \ 228 html_header_2 + \ 229 html_header_3 + file_prefix + "index.html" + \ 230 html_header_5t + project_title + \ 231 html_header_6 232 233 self.html_footer = "<center><font size=""-2"">generated on " + \ 234 time.asctime( time.localtime( time.time() ) ) + \ 235 "</font></center>" + html_footer 236 237 self.columns = 3 238 239 def make_section_url( self, section ): 240 return self.file_prefix + section.name + ".html" 241 242 def make_block_url( self, block ): 243 return self.make_section_url( block.section ) + "#" + block.name 244 245 def make_html_words( self, words ): 246 """ convert a series of simple words into some HTML text """ 247 line = "" 248 if words: 249 line = html_quote( words[0] ) 250 for w in words[1:]: 251 line = line + " " + html_quote( w ) 252 253 return line 254 255 def make_html_word( self, word ): 256 """analyze a simple word to detect cross-references and styling""" 257 # look for cross-references 258 m = re_crossref.match( word ) 259 if m: 260 try: 261 name = m.group( 1 ) 262 rest = m.group( 2 ) 263 block = self.identifiers[name] 264 url = self.make_block_url( block ) 265 return '<a href="' + url + '">' + name + '</a>' + rest 266 except: 267 # we detected a cross-reference to an unknown item 268 sys.stderr.write( \ 269 "WARNING: undefined cross reference '" + name + "'.\n" ) 270 return '?' + name + '?' + rest 271 272 # look for italics and bolds 273 m = re_italic.match( word ) 274 if m: 275 name = m.group( 1 ) 276 rest = m.group( 3 ) 277 return '<i>' + name + '</i>' + rest 278 279 m = re_bold.match( word ) 280 if m: 281 name = m.group( 1 ) 282 rest = m.group( 3 ) 283 return '<b>' + name + '</b>' + rest 284 285 return html_quote( word ) 286 287 def make_html_para( self, words ): 288 """ convert words of a paragraph into tagged HTML text, handle xrefs """ 289 line = "" 290 if words: 291 line = self.make_html_word( words[0] ) 292 for word in words[1:]: 293 line = line + " " + self.make_html_word( word ) 294 # convert `...' quotations into real left and right single quotes 295 line = re.sub( r"(^|\W)`(.*?)'(\W|$)", \ 296 r'\1‘\2’\3', \ 297 line ) 298 # convert tilde into non-breakable space 299 line = string.replace( line, "~", " " ) 300 301 return para_header + line + para_footer 302 303 def make_html_code( self, lines ): 304 """ convert a code sequence to HTML """ 305 line = code_header + '\n' 306 for l in lines: 307 line = line + html_quote( l ) + '\n' 308 309 return line + code_footer 310 311 def make_html_items( self, items ): 312 """ convert a field's content into some valid HTML """ 313 lines = [] 314 for item in items: 315 if item.lines: 316 lines.append( self.make_html_code( item.lines ) ) 317 else: 318 lines.append( self.make_html_para( item.words ) ) 319 320 return string.join( lines, '\n' ) 321 322 def print_html_items( self, items ): 323 print self.make_html_items( items ) 324 325 def print_html_field( self, field ): 326 if field.name: 327 print "<table><tr valign=top><td><b>" + field.name + "</b></td><td>" 328 329 print self.make_html_items( field.items ) 330 331 if field.name: 332 print "</td></tr></table>" 333 334 def html_source_quote( self, line, block_name = None ): 335 result = "" 336 while line: 337 m = re_source_crossref.match( line ) 338 if m: 339 name = m.group( 2 ) 340 prefix = html_quote( m.group( 1 ) ) 341 length = len( m.group( 0 ) ) 342 343 if name == block_name: 344 # this is the current block name, if any 345 result = result + prefix + '<b>' + name + '</b>' 346 elif re_source_keywords.match( name ): 347 # this is a C keyword 348 result = result + prefix + keyword_prefix + name + keyword_suffix 349 elif self.identifiers.has_key( name ): 350 # this is a known identifier 351 block = self.identifiers[name] 352 result = result + prefix + '<a href="' + \ 353 self.make_block_url( block ) + '">' + name + '</a>' 354 else: 355 result = result + html_quote( line[:length] ) 356 357 line = line[length:] 358 else: 359 result = result + html_quote( line ) 360 line = [] 361 362 return result 363 364 def print_html_field_list( self, fields ): 365 print "<p></p>" 366 print "<table cellpadding=3 border=0>" 367 for field in fields: 368 if len( field.name ) > 22: 369 print "<tr valign=top><td colspan=0><b>" + field.name + "</b></td></tr>" 370 print "<tr valign=top><td></td><td>" 371 else: 372 print "<tr valign=top><td><b>" + field.name + "</b></td><td>" 373 374 self.print_html_items( field.items ) 375 print "</td></tr>" 376 print "</table>" 377 378 def print_html_markup( self, markup ): 379 table_fields = [] 380 for field in markup.fields: 381 if field.name: 382 # we begin a new series of field or value definitions, we 383 # will record them in the 'table_fields' list before outputting 384 # all of them as a single table 385 # 386 table_fields.append( field ) 387 else: 388 if table_fields: 389 self.print_html_field_list( table_fields ) 390 table_fields = [] 391 392 self.print_html_items( field.items ) 393 394 if table_fields: 395 self.print_html_field_list( table_fields ) 396 397 # 398 # Formatting the index 399 # 400 def index_enter( self ): 401 print self.html_index_header 402 self.index_items = {} 403 404 def index_name_enter( self, name ): 405 block = self.identifiers[name] 406 url = self.make_block_url( block ) 407 self.index_items[name] = url 408 409 def index_exit( self ): 410 # block_index already contains the sorted list of index names 411 count = len( self.block_index ) 412 rows = ( count + self.columns - 1 ) / self.columns 413 414 print "<table align=center border=0 cellpadding=0 cellspacing=0>" 415 for r in range( rows ): 416 line = "<tr>" 417 for c in range( self.columns ): 418 i = r + c * rows 419 if i < count: 420 bname = self.block_index[r + c * rows] 421 url = self.index_items[bname] 422 line = line + '<td><a href="' + url + '">' + bname + '</a></td>' 423 else: 424 line = line + '<td></td>' 425 line = line + "</tr>" 426 print line 427 428 print "</table>" 429 430 print index_footer_start + \ 431 self.file_prefix + "toc.html" + \ 432 index_footer_end 433 434 print self.html_footer 435 436 self.index_items = {} 437 438 def index_dump( self, index_filename = None ): 439 if index_filename == None: 440 index_filename = self.file_prefix + "index.html" 441 442 Formatter.index_dump( self, index_filename ) 443 444 # 445 # Formatting the table of content 446 # 447 def toc_enter( self ): 448 print self.html_toc_header 449 print "<center><h1>Table of Contents</h1></center>" 450 451 def toc_chapter_enter( self, chapter ): 452 print chapter_header + string.join( chapter.title ) + chapter_inter 453 print "<table cellpadding=5>" 454 455 def toc_section_enter( self, section ): 456 print '<tr valign=top><td class="left">' 457 print '<a href="' + self.make_section_url( section ) + '">' + \ 458 section.title + '</a></td><td>' 459 460 print self.make_html_para( section.abstract ) 461 462 def toc_section_exit( self, section ): 463 print "</td></tr>" 464 465 def toc_chapter_exit( self, chapter ): 466 print "</table>" 467 print chapter_footer 468 469 def toc_index( self, index_filename ): 470 print chapter_header + \ 471 '<a href="' + index_filename + '">Global Index</a>' + \ 472 chapter_inter + chapter_footer 473 474 def toc_exit( self ): 475 print toc_footer_start + \ 476 self.file_prefix + "index.html" + \ 477 toc_footer_end 478 479 print self.html_footer 480 481 def toc_dump( self, toc_filename = None, index_filename = None ): 482 if toc_filename == None: 483 toc_filename = self.file_prefix + "toc.html" 484 485 if index_filename == None: 486 index_filename = self.file_prefix + "index.html" 487 488 Formatter.toc_dump( self, toc_filename, index_filename ) 489 490 # 491 # Formatting sections 492 # 493 def section_enter( self, section ): 494 print self.html_header 495 496 print section_title_header 497 print section.title 498 print section_title_footer 499 500 maxwidth = 0 501 for b in section.blocks.values(): 502 if len( b.name ) > maxwidth: 503 maxwidth = len( b.name ) 504 505 width = 70 # XXX magic number 506 if maxwidth <> 0: 507 # print section synopsis 508 print section_synopsis_header 509 print "<table align=center cellspacing=5 cellpadding=0 border=0>" 510 511 columns = width / maxwidth 512 if columns < 1: 513 columns = 1 514 515 count = len( section.block_names ) 516 rows = ( count + columns - 1 ) / columns 517 518 for r in range( rows ): 519 line = "<tr>" 520 for c in range( columns ): 521 i = r + c * rows 522 line = line + '<td></td><td>' 523 if i < count: 524 name = section.block_names[i] 525 line = line + '<a href="#' + name + '">' + name + '</a>' 526 527 line = line + '</td>' 528 line = line + "</tr>" 529 print line 530 531 print "</table><br><br>" 532 print section_synopsis_footer 533 534 print description_header 535 print self.make_html_items( section.description ) 536 print description_footer 537 538 def block_enter( self, block ): 539 print block_header 540 541 # place html anchor if needed 542 if block.name: 543 print '<h4><a name="' + block.name + '">' + block.name + '</a></h4>' 544 545 # dump the block C source lines now 546 if block.code: 547 header = '' 548 for f in self.headers.keys(): 549 if block.source.filename.find( f ) >= 0: 550 header = self.headers[f] + ' (' + f + ')' 551 break; 552 553# if not header: 554# sys.stderr.write( \ 555# 'WARNING: No header macro for ' + block.source.filename + '.\n' ) 556 557 if header: 558 print header_location_header 559 print 'Defined in ' + header + '.' 560 print header_location_footer 561 562 print source_header 563 for l in block.code: 564 print self.html_source_quote( l, block.name ) 565 print source_footer 566 567 def markup_enter( self, markup, block ): 568 if markup.tag == "description": 569 print description_header 570 else: 571 print marker_header + markup.tag + marker_inter 572 573 self.print_html_markup( markup ) 574 575 def markup_exit( self, markup, block ): 576 if markup.tag == "description": 577 print description_footer 578 else: 579 print marker_footer 580 581 def block_exit( self, block ): 582 print block_footer_start + self.file_prefix + "index.html" + \ 583 block_footer_middle + self.file_prefix + "toc.html" + \ 584 block_footer_end 585 586 def section_exit( self, section ): 587 print html_footer 588 589 def section_dump_all( self ): 590 for section in self.sections: 591 self.section_dump( section, self.file_prefix + section.name + '.html' ) 592 593# eof 594