1 #! /usr/bin/env python -- # -*- python -*- 
   2 ############################################################################## 
   4 # Zope Public License (ZPL) Version 1.0 
   5 # ------------------------------------- 
   7 # Copyright (c) Digital Creations.  All rights reserved. 
   9 # This license has been certified as Open Source(tm). 
  11 # Redistribution and use in source and binary forms, with or without 
  12 # modification, are permitted provided that the following conditions are 
  15 # 1. Redistributions in source code must retain the above copyright 
  16 #    notice, this list of conditions, and the following disclaimer. 
  18 # 2. Redistributions in binary form must reproduce the above copyright 
  19 #    notice, this list of conditions, and the following disclaimer in 
  20 #    the documentation and/or other materials provided with the 
  23 # 3. Digital Creations requests that attribution be given to Zope 
  24 #    in any manner possible. Zope includes a "Powered by Zope" 
  25 #    button that is installed by default. While it is not a license 
  26 #    violation to remove this button, it is requested that the 
  27 #    attribution remain. A significant investment has been put 
  28 #    into Zope, and this effort will continue if the Zope community 
  29 #    continues to grow. This is one way to assure that growth. 
  31 # 4. All advertising materials and documentation mentioning 
  32 #    features derived from or use of this software must display 
  33 #    the following acknowledgement: 
  35 #      "This product includes software developed by Digital Creations 
  36 #      for use in the Z Object Publishing Environment 
  37 #      (http://www.zope.org/)." 
  39 #    In the event that the product being advertised includes an 
  40 #    intact Zope distribution (with copyright and license included) 
  41 #    then this clause is waived. 
  43 # 5. Names associated with Zope or Digital Creations must not be used to 
  44 #    endorse or promote products derived from this software without 
  45 #    prior written permission from Digital Creations. 
  47 # 6. Modified redistributions of any form whatsoever must retain 
  48 #    the following acknowledgment: 
  50 #      "This product includes software developed by Digital Creations 
  51 #      for use in the Z Object Publishing Environment 
  52 #      (http://www.zope.org/)." 
  54 #    Intact (re-)distributions of any official Zope release do not 
  55 #    require an external acknowledgement. 
  57 # 7. Modifications are encouraged but must be packaged separately as 
  58 #    patches to official Zope releases.  Distributions that do not 
  59 #    clearly separate the patches from the original work must be clearly 
  60 #    labeled as unofficial distributions.  Modifications which do not 
  61 #    carry the name Zope may be packaged in any form, as long as they 
  62 #    conform to all of the clauses above. 
  67 #   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY 
  68 #   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  69 #   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
  70 #   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS 
  71 #   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
  72 #   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
  73 #   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 
  74 #   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
  75 #   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
  76 #   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
  77 #   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
  81 # This software consists of contributions made by Digital Creations and 
  82 # many individuals on behalf of Digital Creations.  Specific 
  83 # attributions are listed in the accompanying credits file. 
  85 ############################################################################## 
  86 '''Structured Text Manipulation 
  88 Parse a structured text string into a form that can be used with  
  89 structured formats, like html. 
  91 Structured text is text that uses indentation and simple 
  92 symbology to indicate the structure of a document.   
  94 A structured string consists of a sequence of paragraphs separated by 
  95 one or more blank lines.  Each paragraph has a level which is defined 
  96 as the minimum indentation of the paragraph.  A paragraph is a 
  97 sub-paragraph of another paragraph if the other paragraph is the last 
  98 preceding paragraph that has a lower level. 
 100 Special symbology is used to indicate special constructs: 
 102 - A single-line paragraph whose immediately succeeding paragraphs are lower 
 103   level is treated as a header. 
 105 - A paragraph that begins with a '-', '*', or 'o' is treated as an 
 106   unordered list (bullet) element. 
 108 - A paragraph that begins with a sequence of digits followed by a 
 109   white-space character is treated as an ordered list element. 
 111 - A paragraph that begins with a sequence of sequences, where each 
 112   sequence is a sequence of digits or a sequence of letters followed 
 113   by a period, is treated as an ordered list element. 
 115 - A paragraph with a first line that contains some text, followed by 
 116   some white-space and '--' is treated as 
 117   a descriptive list element. The leading text is treated as the 
 120 - Sub-paragraphs of a paragraph that ends in the word 'example' or the 
 121   word 'examples', or '::' is treated as example code and is output as is. 
 123 - Text enclosed single quotes (with white-space to the left of the 
 124   first quote and whitespace or puctuation to the right of the second quote) 
 125   is treated as example code. 
 127 - Text surrounded by '*' characters (with white-space to the left of the 
 128   first '*' and whitespace or puctuation to the right of the second '*') 
 131 - Text surrounded by '**' characters (with white-space to the left of the 
 132   first '**' and whitespace or puctuation to the right of the second '**') 
 135 - Text surrounded by '_' underscore characters (with whitespace to the left  
 136   and whitespace or punctuation to the right) is made underlined. 
 138 - Text encloded by double quotes followed by a colon, a URL, and concluded 
 139   by punctuation plus white space, *or* just white space, is treated as a 
 140   hyper link. For example: 
 142     "Zope":http://www.zope.org/ is ... 
 144   Is interpreted as '<a href="http://www.zope.org/">Zope</a> is ....' 
 145   Note: This works for relative as well as absolute URLs. 
 147 - Text enclosed by double quotes followed by a comma, one or more spaces, 
 148   an absolute URL and concluded by punctuation plus white space, or just 
 149   white space, is treated as a hyper link. For example:  
 151     "mail me", mailto:amos@digicool.com. 
 153   Is interpreted as '<a href="mailto:amos@digicool.com">mail me</a>.'  
 155 - Text enclosed in brackets which consists only of letters, digits, 
 156   underscores and dashes is treated as hyper links within the document. 
 159     As demonstrated by Smith [12] this technique is quite effective. 
 161   Is interpreted as '... by Smith <a href="#12">[12]</a> this ...'. Together 
 162   with the next rule this allows easy coding of references or end notes. 
 164 - Text enclosed in brackets which is preceded by the start of a line, two 
 165   periods and a space is treated as a named link. For example: 
 167     .. [12] "Effective Techniques" Smith, Joe ...  
 169   Is interpreted as '<a name="12">[12]</a> "Effective Techniques" ...'. 
 170   Together with the previous rule this allows easy coding of references or 
 174 - A paragraph that has blocks of text enclosed in '||' is treated as a 
 175   table. The text blocks correspond to table cells and table rows are 
 176   denoted by newlines. By default the cells are center aligned. A cell 
 177   can span more than one column by preceding a block of text with an 
 178   equivalent number of cell separators '||'. Newlines and '|' cannot 
 179   be a part of the cell text. For example: 
 181       |||| **Ingredients** || 
 182       || *Name* || *Amount* || 
 188     <TABLE BORDER=1 CELLPADDING=2> 
 190       <TD ALIGN=CENTER COLSPAN=2> <strong>Ingredients</strong> </TD> 
 193       <TD ALIGN=CENTER COLSPAN=1> <em>Name</em> </TD> 
 194       <TD ALIGN=CENTER COLSPAN=1> <em>Amount</em> </TD> 
 197       <TD ALIGN=CENTER COLSPAN=1>Spam</TD> 
 198       <TD ALIGN=CENTER COLSPAN=1>10</TD> 
 201       <TD ALIGN=CENTER COLSPAN=1>Eggs</TD> 
 202       <TD ALIGN=CENTER COLSPAN=1>3</TD> 
 210 #       Copyright 1996 Digital Creations, L.C., 910 Princess Anne 
 211 #       Street, Suite 300, Fredericksburg, Virginia 22401 U.S.A. All 
 212 #       rights reserved.  Copyright in this software is owned by DCLC, 
 213 #       unless otherwise indicated. Permission to use, copy and 
 214 #       distribute this software is hereby granted, provided that the 
 215 #       above copyright notice appear in all copies and that both that 
 216 #       copyright notice and this permission notice appear. Note that 
 217 #       any product, process or technology described in this software 
 218 #       may be the subject of other Intellectual Property rights 
 219 #       reserved by Digital Creations, L.C. and are not licensed 
 224 #       Digital Creations & DCLC, are trademarks of Digital Creations, L.C.. 
 225 #       All other trademarks are owned by their respective companies.  
 229 #       The software is provided "as is" without warranty of any kind, 
 230 #       either express or implied, including, but not limited to, the 
 231 #       implied warranties of merchantability, fitness for a particular 
 232 #       purpose, or non-infringement. This software could include 
 233 #       technical inaccuracies or typographical errors. Changes are 
 234 #       periodically made to the software; these changes will be 
 235 #       incorporated in new editions of the software. DCLC may make 
 236 #       improvements and/or changes in this software at any time 
 239 #     Limitation Of Liability  
 241 #       In no event will DCLC be liable for direct, indirect, special, 
 242 #       incidental, economic, cover, or consequential damages arising 
 243 #       out of the use of or inability to use this software even if 
 244 #       advised of the possibility of such damages. Some states do not 
 245 #       allow the exclusion or limitation of implied warranties or 
 246 #       limitation of liability for incidental or consequential 
 247 #       damages, so the above limitation or exclusion may not apply to 
 251 # If you have questions regarding this software, 
 254 #   Jim Fulton, jim@digicool.com 
 259 # Revision 1.1  2001/03/10 05:07:20  RD 
 260 # Added some simple sample apps 
 262 # Revision 1.27  2000/04/21 13:38:10  jim 
 263 # Added closing list tags. Woo hoo! 
 265 # Revision 1.26  2000/03/14 17:22:04  brian 
 268 # Revision 1.25  2000/02/17 00:53:24  klm 
 269 # HTML._str(): We were getting preformatted examples rendered twice, 
 270 # second time without preformatting.  Problem was a missing 'continue' 
 271 # in one of the cases. 
 273 # Revision 1.24  1999/12/13 16:32:48  klm 
 274 # Incorporated pavlos christoforou's mods to handle simple tables.  From 
 275 # his web page at http://www.zope.org/Members/gaaros/StructuredText: 
 277 #   Structured Text module with table support 
 279 #   A paragraph that has blocks of text enclosed in '||' is treated as a 
 280 #   table. The text blocks correspond to table cells and table rows are 
 281 #   denoted by newlines. By default the cells are center aligned. You can 
 282 #   change the defaults by modifying the CELL,ROW and TABLE class 
 283 #   attributes in class Table. A cell can span more than one column by 
 284 #   preceding a block of text with an equivalent number of cell separators 
 285 #   '||'. Newlines and '|' cannot be a part of the cell text. If you need 
 286 #   newlines use <BR>. For example: 
 288 #        |||| **Ingredients** || 
 289 #        || *Name* || *Amount* || 
 293 # Revision 1.23  1999/08/03 20:49:05  jim 
 294 # Fixed to allow list elements to introduce examples. 
 296 # Restructured _str using continue to avoid excessive nesting. 
 298 # Revision 1.22  1999/08/02 22:01:28  jim 
 299 # Fixed a bunch of bugs introduced by making ts_regex actually thread 
 302 # Also localized a bunch of regular expressions 
 303 # using "static" variables (aka always default arguments). 
 305 # Revision 1.21  1999/08/02 13:26:52  jim 
 306 # paragraph_divider needs to be a regular (thread-unsafe) regex 
 307 # since it gets passed to ts_regex.split, which is thread-safe 
 308 # and wants to use regs. 
 310 # Revision 1.20  1999/07/21 13:33:59  jim 
 313 # Revision 1.19  1999/07/15 16:43:15  jim 
 314 # Checked in Scott Robertson's thread-safety fixes. 
 316 # Revision 1.18  1999/03/24 00:03:18  klm 
 317 # Provide for relative links, eg <a href="file_in_same_dir">whatever</a>, 
 320 #   "whatever", :file_in_same_dir 
 324 #   "whatever"::file_in_same_dir 
 326 # .__init__(): relax the second gsub, using a '*' instead of a '+', so 
 327 # the stuff before the ':' can be missing, and also do postprocessing so 
 328 # any resulting '<a href=":file_in_same_dir">'s have the superfluous ':' 
 329 # removed.  *Seems* good! 
 331 # Revision 1.17  1999/03/12 23:21:39  klm 
 332 # Gratuituous checkin to test my cvs *update* logging hook. 
 334 # Revision 1.16  1999/03/12 17:12:12  klm 
 335 # Added support for underlined elements, in the obvious way (and 
 336 # included an entry in the module docstring for it). 
 338 # Added an entry in the module docstring describing what i *guess* is 
 339 # the criterion for identifying header elements.  (I'm going to have to 
 340 # delve into and understand the framework a bit better before *knowing* 
 343 # Revision 1.15  1999/03/11 22:40:18  klm 
 344 # Handle links that include '#' named links. 
 346 # Revision 1.14  1999/03/11 01:35:19  klm 
 347 # Fixed a small typo, and refined the module docstring link example, in 
 348 # order to do a checkin to exercise the CVS repository mirroring.  Might 
 349 # as well include my last checkin message, with some substantial stuff: 
 351 # Links are now recognized whether or not the candidate strings are 
 352 # terminated with punctuation before the trailing whitespace.  The old 
 353 # form - trailing punctuation then whitespace - is preserved, but the 
 354 # punctuation is now unnecessary. 
 356 # The regular expressions are a bit more complicated, but i've factored 
 357 # out the common parts and but them in variables with suggestive names, 
 358 # which may make them easier to understand. 
 360 # Revision 1.13  1999/03/11 00:49:57  klm 
 361 # Links are now recognized whether or not the candidate strings are 
 362 # terminated with punctuation before the trailing whitespace.  The old 
 363 # form - trailing punctuation then whitespace - is preserved, but the 
 364 # punctuation is now unnecessary. 
 366 # The regular expressions are a bit more complicated, but i've factored 
 367 # out the common parts and but them in variables with suggestive names, 
 368 # which may make them easier to understand. 
 370 # Revision 1.12  1999/03/10 00:15:46  klm 
 371 # Committing with version 1.0 of the license. 
 373 # Revision 1.11  1999/02/08 18:13:12  klm 
 374 # Trival checkin (spelling fix "preceedeing" -> "preceding" and similar) 
 375 # to see what pitfalls my environment presents to accomplishing a 
 376 # successful checkin.  (It turns out that i can't do it from aldous because 
 377 # the new version of cvs doesn't support the '-t' and '-f' options in the 
 378 # cvswrappers file...) 
 380 # Revision 1.10  1998/12/29 22:30:43  amos 
 381 # Improved doc string to describe hyper link and references capabilities. 
 383 # Revision 1.9  1998/12/04 20:15:31  jim 
 384 # Detabification and new copyright. 
 386 # Revision 1.8  1998/02/27 18:45:22  jim 
 387 # Various updates, including new indentation utilities. 
 389 # Revision 1.7  1997/12/12 15:39:54  jim 
 390 # Added level as argument for html_with_references. 
 392 # Revision 1.6  1997/12/12 15:27:25  jim 
 393 # Added additional pattern matching for HTML references. 
 395 # Revision 1.5  1997/03/08 16:01:03  jim 
 396 # Moved code to recognize: "foo bar", url. 
 397 # into object initializer, so it gets applied in all cases. 
 399 # Revision 1.4  1997/02/17 23:36:35  jim 
 400 # Added support for "foo title", http:/foohost/foo 
 402 # Revision 1.3  1996/12/06 15:57:37  jim 
 403 # Fixed bugs in character tags. 
 405 # Added -t command-line option to generate title if: 
 407 #    - The first paragraph is one line (i.e. a heading) and 
 409 #    - All other paragraphs are indented. 
 411 # Revision 1.2  1996/10/28 13:56:02  jim 
 412 # Fixed bug in ordered lists. 
 413 # Added option for either HTML-style headings or descriptive-list style 
 416 # Revision 1.1  1996/10/23 14:00:45  jim 
 417 # *** empty log message *** 
 422 import ts_regex
, regex
 
 423 from ts_regex 
import gsub
 
 424 from string 
import split
, join
, strip
, find
 
 426 def untabify(aString
, 
 427              indent_tab
=ts_regex
.compile('\(\n\|^\)\( *\)\t').search_group
, 
 430     Convert indentation tabs to spaces. 
 435         ts_results 
= indent_tab(rest
, (1,2)) 
 437             start
, grps 
= ts_results
 
 440             result
=result
+rest
[:start
] 
 441             rest
="\n%s%s" % (' ' * ((indent
/8+1)*8), 
 442                              rest
[start
+indent
+1+lnl
:]) 
 446 def indent(aString
, indent
=2): 
 447     """Indent a string the given number of spaces""" 
 448     r
=split(untabify(aString
),'\n') 
 450     if not r
[-1]: del r
[-1] 
 452     return "%s%s\n" % (tab
,join(r
,'\n'+tab
)) 
 454 def reindent(aString
, indent
=2, already_untabified
=0): 
 455     "reindent a block of text, so that the minimum indent is as given" 
 457     if not already_untabified
: aString
=untabify(aString
) 
 459     l
=indent_level(aString
)[0] 
 460     if indent
==l
: return aString
 
 468         for s 
in split(aString
,'\n'): append(tab
+s
) 
 471         for s 
in split(aString
,'\n'): append(s
[l
:]) 
 475 def indent_level(aString
, 
 476                  indent_space
=ts_regex
.compile('\n\( *\)').search_group
, 
 479     Find the minimum indentation for a string, not counting blank lines. 
 486         ts_results 
= indent_space(text
, (1,2), start
) 
 488             start
, grps 
= ts_results
 
 491             if start 
< l 
and text
[start
] != '\n':       # Skip blank lines 
 492                 if not i
: return (0,aString
) 
 493                 if i 
< indent
: indent 
= i
 
 495             return (indent
,aString
) 
 497 def paragraphs(list,start
): 
 501     while i 
< l 
and list[i
][0] > level
: i
=i
+1 
 505     if not list: return [] 
 510         sublen
=paragraphs(list,i
) 
 512         r
.append((list[i
-1][1],structure(list[i
:i
+sublen
]))) 
 518     CELL
='  <TD ALIGN=CENTER COLSPAN=%i>%s</TD>\n' 
 519     ROW
=' <TR>\n%s </TR>\n' 
 520     TABLE
='\n<TABLE BORDER=1 CELLPADDING=2>\n%s</TABLE>' 
 522     def create(self
,aPar
,td
=ts_regex
.compile( 
 523         '[ \t\n]*||\([^\0|]*\)').match_group
): 
 524         '''parses a table and returns nested list representing the 
 527         text
=filter(None,split(aPar
,'\n')) 
 534                 if pos
[0]==len(line
):break 
 536             self
.table
.append(row
) 
 540         '''Creates an HTML representation of table''' 
 542         for row 
in self
.table
: 
 550                     htmlrow
.append(self
.CELL
%(colspan
,cell
)) 
 552             htmltable
.append(self
.ROW
%join(htmlrow
,'')) 
 553         return self
.TABLE
%join(htmltable
,'') 
 555 optional_trailing_punctuation 
= '\(,\|\([.:?;]\)\)?' 
 556 trailing_space 
= '\([\0- ]\)' 
 557 not_punctuation_or_whitespace 
= "[^-,.?:\0- ]" 
 560 class StructuredText
: 
 562     """Model text as structured collection of paragraphs. 
 564     Structure is implied by the indentation level. 
 566     This class is intended as a base classes that do actual text 
 570     def __init__(self
, aStructuredString
, level
=0, 
 571                  paragraph_divider
=regex
.compile('\(\n *\)+\n'), 
 573         '''Convert a structured text string into a structured text object. 
 577           aStructuredString -- The string to be parsed. 
 578           level -- The level of top level headings to be created. 
 581         aStructuredString 
= gsub( 
 582             '\"\([^\"\0]+\)\":'         # title: <"text":> 
 583             + ('\([-:a-zA-Z0-9_,./?=@#~]+%s\)' 
 584                % not_punctuation_or_whitespace
) 
 585             + optional_trailing_punctuation
 
 587             '<a href="\\2">\\1</a>\\4\\5\\6', 
 590         aStructuredString 
= gsub( 
 591             '\"\([^\"\0]+\)\",[\0- ]+'            # title: <"text", > 
 592             + ('\([a-zA-Z]*:[-:a-zA-Z0-9_,./?=@#~]*%s\)' 
 593                % not_punctuation_or_whitespace
) 
 594             + optional_trailing_punctuation
 
 596             '<a href="\\2">\\1</a>\\4\\5\\6', 
 599         protoless 
= find(aStructuredString
, '<a href=":') 
 601             aStructuredString 
= gsub('<a href=":', '<a href="', 
 605         paragraphs
=ts_regex
.split(untabify(aStructuredString
), 
 607         paragraphs
=map(indent_level
,paragraphs
) 
 609         self
.structure
=structure(paragraphs
) 
 613         return str(self
.structure
) 
 616 ctag_prefix
="\([\0- (]\|^\)" 
 617 ctag_suffix
="\([\0- ,.:;!?)]\|$\)" 
 618 ctag_middle
="[%s]\([^\0- %s][^%s]*[^\0- %s]\|[^%s]\)[%s]" 
 619 ctag_middl2
="[%s][%s]\([^\0- %s][^%s]*[^\0- %s]\|[^%s]\)[%s][%s]" 
 623              ctag_prefix
+(ctag_middle 
% (("*",)*6) )+ctag_suffix
), 
 624          strong
=regex
.compile( 
 625              ctag_prefix
+(ctag_middl2 
% (("*",)*8))+ctag_suffix
), 
 627              ctag_prefix
+(ctag_middle 
% (("_",)*6) )+ctag_suffix
), 
 629              ctag_prefix
+(ctag_middle 
% (("\'",)*6))+ctag_suffix
), 
 632     s
=gsub(strong
,'\\1<strong>\\2</strong>\\3',s
) 
 633     s
=gsub(under
, '\\1<u>\\2</u>\\3',s
) 
 634     s
=gsub(code
,  '\\1<code>\\2</code>\\3',s
) 
 635     s
=gsub(em
,    '\\1<em>\\2</em>\\3',s
) 
 638 class HTML(StructuredText
): 
 641     An HTML structured text formatter. 
 645                 extra_dl
=regex
.compile("</dl>\n<dl>"), 
 646                 extra_ul
=regex
.compile("</ul>\n<ul>"), 
 647                 extra_ol
=regex
.compile("</ol>\n<ol>"), 
 650         Return an HTML string representation of the structured text data. 
 653         s
=self
._str
(self
.structure
,self
.level
) 
 654         s
=gsub(extra_dl
,'\n',s
) 
 655         s
=gsub(extra_ul
,'\n',s
) 
 656         s
=gsub(extra_ol
,'\n',s
) 
 659     def ul(self
, before
, p
, after
): 
 660         if p
: p
="<p>%s</p>" % strip(ctag(p
)) 
 661         return ('%s<ul><li>%s\n%s\n</li></ul>\n' 
 664     def ol(self
, before
, p
, after
): 
 665         if p
: p
="<p>%s</p>" % strip(ctag(p
)) 
 666         return ('%s<ol><li>%s\n%s\n</li></ol>\n' 
 669     def dl(self
, before
, t
, d
, after
): 
 670         return ('%s<dl><dt>%s</dt><dd><p>%s</p>\n%s\n</dd></dl>\n' 
 671                 % (before
,ctag(t
),ctag(d
),after
)) 
 673     def head(self
, before
, t
, level
, d
): 
 674         if level 
> 0 and level 
< 6: 
 675             return ('%s<h%d>%s</h%d>\n%s\n' 
 676                     % (before
,level
,strip(ctag(t
)),level
,d
)) 
 678         t
="<p><strong>%s</strong><p>" % strip(ctag(t
)) 
 679         return ('%s<dl><dt>%s\n</dt><dd>%s\n</dd></dl>\n' 
 682     def normal(self
,before
,p
,after
): 
 683         return '%s<p>%s</p>\n%s\n' % (before
,ctag(p
),after
) 
 685     def pre(self
,structure
,tagged
=0): 
 686         if not structure
: return '' 
 692             r
="%s%s\n\n%s" % (r
,html_quote(s
[0]),self
.pre(s
[1],1)) 
 693         if not tagged
: r
=r
+'</PRE>\n' 
 696     def table(self
,before
,table
,after
): 
 697         return '%s<p>%s</p>\n%s\n' % (before
,ctag(table
),after
) 
 699     def _str(self
,structure
,level
, 
 701              bullet
=ts_regex
.compile('[ \t\n]*[o*-][ \t\n]+\([^\0]*\)' 
 703              example
=ts_regex
.compile('[\0- ]examples?:[\0- ]*$' 
 705              dl
=ts_regex
.compile('\([^\n]+\)[ \t]+--[ \t\n]+\([^\0]*\)' 
 707              nl
=ts_regex
.compile('\n').search
, 
 709                  '[ \t]*\(\([0-9]+\|[a-zA-Z]+\)[.)]\)+[ \t\n]+\([^\0]*\|$\)' 
 711              olp
=ts_regex
.compile('[ \t]*([0-9]+)[ \t\n]+\([^\0]*\|$\)' 
 717             ts_results 
= bullet(s
[0], (1,)) 
 720                 if s
[0][-2:]=='::' and s
[1]: ps
=self
.pre(s
[1]) 
 721                 else: ps
=self
._str
(s
[1],level
) 
 724             ts_results 
= ol(s
[0], (3,)) 
 727                 if s
[0][-2:]=='::' and s
[1]: ps
=self
.pre(s
[1]) 
 728                 else: ps
=self
._str
(s
[1],level
) 
 731             ts_results 
= olp(s
[0], (1,)) 
 734                 if s
[0][-2:]=='::' and s
[1]: ps
=self
.pre(s
[1]) 
 735                 else: ps
=self
._str
(s
[1],level
) 
 738             ts_results 
= dl(s
[0], (1,2)) 
 741                 r
=self
.dl(r
,t
,d
,self
._str
(s
[1],level
)) 
 743             if example(s
[0]) >= 0 and s
[1]: 
 744                 # Introduce an example, using pre tags: 
 745                 r
=self
.normal(r
,s
[0],self
.pre(s
[1])) 
 747             if s
[0][-2:]=='::' and s
[1]: 
 748                 # Introduce an example, using pre tags: 
 749                 r
=self
.normal(r
,s
[0][:-1],self
.pre(s
[1])) 
 751             if table
.create(s
[0]): 
 753                 r
=self
.table(r
,table
.html(),self
._str
(s
[1],level
)) 
 757                 if nl(s
[0]) < 0 and s
[1] and s
[0][-1:] != ':': 
 760                     r
=self
.head(r
,t
,level
, 
 761                                 self
._str
(s
[1],level 
and level
+1)) 
 763                     r
=self
.normal(r
,s
[0],self
._str
(s
[1],level
)) 
 769                        (regex
.compile('&'), '&'), 
 770                        (regex
.compile("<"), '<' ), 
 771                        (regex
.compile(">"), '>' ), 
 772                        (regex
.compile('"'), '"') 
 775         for re
,name 
in character_entities
: 
 776             text
=gsub(re
,name
,text
) 
 779 def html_with_references(text
, level
=1): 
 781         '[\0\n].. \[\([-_0-9_a-zA-Z-]+\)\]', 
 782         '\n  <a name="\\1">[\\1]</a>', 
 786         '\([\0- ,]\)\[\([0-9_a-zA-Z-]+\)\]\([\0- ,.:]\)', 
 787         '\\1<a href="#\\2">[\\2]</a>\\3', 
 791         '\([\0- ,]\)\[\([^]]+\)\.html\]\([\0- ,.:]\)', 
 792         '\\1<a href="\\2.html">[\\2]</a>\\3', 
 795     return HTML(text
,level
=level
) 
 801     opts
,args
=getopt
.getopt(sys
.argv
[1:],'tw') 
 805         s
=open(infile
,'r').read() 
 811         if filter(lambda o
: o
[0]=='-w', opts
): 
 812             print 'Content-Type: text/html\n' 
 815             s
=ts_regex
.sub('^#![^\n]+','',s
) 
 817         r
=ts_regex
.compile('\([\0-\n]*\n\)') 
 818         ts_results 
= r
.match_group(s
, (1,)) 
 820             s
=s
[len(ts_results
[1]):] 
 821         s
=str(html_with_references(s
)) 
 823             t
=s
[4:find(s
,'</h1>')] 
 824             s
='''<html><head><title>%s</title> 
 831         print html_with_references(s
) 
 833 if __name__
=="__main__": main()