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()