blob: 3868b1b6b67d32489ad09c2e95a8c404795c1f94 [file] [log] [blame]
Guido van Rossum4b8c6ea2000-02-04 15:39:30 +00001"""Generic output formatting.
2
3Formatter objects transform an abstract flow of formatting events into
4specific output events on writer objects. Formatters manage several stack
5structures to allow various properties of a writer object to be changed and
6restored; writers need not be able to handle relative changes nor any sort
7of ``change back'' operation. Specific writer properties which may be
8controlled via formatter objects are horizontal alignment, font, and left
9margin indentations. A mechanism is provided which supports providing
10arbitrary, non-exclusive style settings to a writer as well. Additional
11interfaces facilitate formatting events which are not reversible, such as
Tim Peters88869f92001-01-14 23:36:06 +000012paragraph separation.
Guido van Rossum4b8c6ea2000-02-04 15:39:30 +000013
14Writer objects encapsulate device interfaces. Abstract devices, such as
15file formats, are supported as well as physical devices. The provided
16implementations all work with abstract devices. The interface makes
17available mechanisms for setting the properties which formatter objects
Tim Peters88869f92001-01-14 23:36:06 +000018manage and inserting data into the output.
Guido van Rossum4b8c6ea2000-02-04 15:39:30 +000019"""
20
Guido van Rossuma0eab1d1995-08-07 20:07:36 +000021import sys
22
23
24AS_IS = None
25
Guido van Rossuma0eab1d1995-08-07 20:07:36 +000026
Guido van Rossum909507d1995-10-06 15:31:30 +000027class NullFormatter:
Raymond Hettingeraef22fb2002-05-29 16:18:42 +000028 """A formatter which does nothing.
29
30 If the writer parameter is omitted, a NullWriter instance is created.
31 No methods of the writer are called by NullFormatter instances.
32
33 Implementations should inherit from this class if implementing a writer
34 interface but don't need to inherit any implementation.
35
36 """
Guido van Rossum909507d1995-10-06 15:31:30 +000037
Guido van Rossumccd8b191996-10-07 21:29:49 +000038 def __init__(self, writer=None):
Raymond Hettinger094662a2002-06-01 01:29:16 +000039 if writer is None:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000040 writer = NullWriter()
41 self.writer = writer
Guido van Rossum909507d1995-10-06 15:31:30 +000042 def end_paragraph(self, blankline): pass
43 def add_line_break(self): pass
Fred Drakeca8cdc61996-10-08 21:57:47 +000044 def add_hor_rule(self, *args, **kw): pass
45 def add_label_data(self, format, counter, blankline=None): pass
Guido van Rossum909507d1995-10-06 15:31:30 +000046 def add_flowing_data(self, data): pass
47 def add_literal_data(self, data): pass
48 def flush_softspace(self): pass
Guido van Rossum9787bdaf1996-05-28 23:50:49 +000049 def push_alignment(self, align): pass
50 def pop_alignment(self): pass
Guido van Rossum909507d1995-10-06 15:31:30 +000051 def push_font(self, x): pass
52 def pop_font(self): pass
53 def push_margin(self, margin): pass
54 def pop_margin(self): pass
55 def set_spacing(self, spacing): pass
Guido van Rossum9787bdaf1996-05-28 23:50:49 +000056 def push_style(self, *styles): pass
57 def pop_style(self, n=1): pass
58 def assert_line_data(self, flag=1): pass
Guido van Rossum909507d1995-10-06 15:31:30 +000059
60
Guido van Rossuma0eab1d1995-08-07 20:07:36 +000061class AbstractFormatter:
Raymond Hettingeraef22fb2002-05-29 16:18:42 +000062 """The standard formatter.
63
64 This implementation has demonstrated wide applicability to many writers,
65 and may be used directly in most circumstances. It has been used to
66 implement a full-featured World Wide Web browser.
67
68 """
Guido van Rossuma0eab1d1995-08-07 20:07:36 +000069
Guido van Rossum8e449911996-08-26 16:19:23 +000070 # Space handling policy: blank spaces at the boundary between elements
71 # are handled by the outermost context. "Literal" data is not checked
72 # to determine context, so spaces in literal data are handled directly
73 # in all circumstances.
74
Guido van Rossuma0eab1d1995-08-07 20:07:36 +000075 def __init__(self, writer):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000076 self.writer = writer # Output device
77 self.align = None # Current alignment
78 self.align_stack = [] # Alignment stack
79 self.font_stack = [] # Font state
80 self.margin_stack = [] # Margin state
81 self.spacing = None # Vertical spacing state
82 self.style_stack = [] # Other state, e.g. color
83 self.nospace = 1 # Should leading space be suppressed
84 self.softspace = 0 # Should a space be inserted
85 self.para_end = 1 # Just ended a paragraph
86 self.parskip = 0 # Skipped space between paragraphs?
87 self.hard_break = 1 # Have a hard break
88 self.have_label = 0
Guido van Rossuma0eab1d1995-08-07 20:07:36 +000089
90 def end_paragraph(self, blankline):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +000091 if not self.hard_break:
92 self.writer.send_line_break()
93 self.have_label = 0
94 if self.parskip < blankline and not self.have_label:
95 self.writer.send_paragraph(blankline - self.parskip)
96 self.parskip = blankline
97 self.have_label = 0
98 self.hard_break = self.nospace = self.para_end = 1
99 self.softspace = 0
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000100
101 def add_line_break(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000102 if not (self.hard_break or self.para_end):
103 self.writer.send_line_break()
104 self.have_label = self.parskip = 0
105 self.hard_break = self.nospace = 1
106 self.softspace = 0
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000107
Guido van Rossum9787bdaf1996-05-28 23:50:49 +0000108 def add_hor_rule(self, *args, **kw):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000109 if not self.hard_break:
110 self.writer.send_line_break()
Guido van Rossum68468eb2003-02-27 20:14:51 +0000111 self.writer.send_hor_rule(*args, **kw)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000112 self.hard_break = self.nospace = 1
113 self.have_label = self.para_end = self.softspace = self.parskip = 0
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000114
Guido van Rossum9787bdaf1996-05-28 23:50:49 +0000115 def add_label_data(self, format, counter, blankline = None):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000116 if self.have_label or not self.hard_break:
117 self.writer.send_line_break()
118 if not self.para_end:
119 self.writer.send_paragraph((blankline and 1) or 0)
Walter Dörwald65230a22002-06-03 15:58:32 +0000120 if isinstance(format, str):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000121 self.writer.send_label_data(self.format_counter(format, counter))
122 else:
123 self.writer.send_label_data(format)
124 self.nospace = self.have_label = self.hard_break = self.para_end = 1
125 self.softspace = self.parskip = 0
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000126
127 def format_counter(self, format, counter):
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000128 label = ''
129 for c in format:
Fred Drake6f6a14f2001-05-11 19:25:08 +0000130 if c == '1':
131 label = label + ('%d' % counter)
132 elif c in 'aA':
133 if counter > 0:
134 label = label + self.format_letter(c, counter)
135 elif c in 'iI':
136 if counter > 0:
137 label = label + self.format_roman(c, counter)
138 else:
Guido van Rossum9787bdaf1996-05-28 23:50:49 +0000139 label = label + c
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000140 return label
141
142 def format_letter(self, case, counter):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000143 label = ''
144 while counter > 0:
145 counter, x = divmod(counter-1, 26)
Fred Drake6f6a14f2001-05-11 19:25:08 +0000146 # This makes a strong assumption that lowercase letters
147 # and uppercase letters form two contiguous blocks, with
148 # letters in order!
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000149 s = chr(ord(case) + x)
150 label = s + label
151 return label
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000152
153 def format_roman(self, case, counter):
154 ones = ['i', 'x', 'c', 'm']
155 fives = ['v', 'l', 'd']
Guido van Rossum9787bdaf1996-05-28 23:50:49 +0000156 label, index = '', 0
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000157 # This will die of IndexError when counter is too big
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000158 while counter > 0:
159 counter, x = divmod(counter, 10)
160 if x == 9:
Guido van Rossum9787bdaf1996-05-28 23:50:49 +0000161 label = ones[index] + ones[index+1] + label
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000162 elif x == 4:
Guido van Rossum9787bdaf1996-05-28 23:50:49 +0000163 label = ones[index] + fives[index] + label
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000164 else:
165 if x >= 5:
166 s = fives[index]
167 x = x-5
168 else:
169 s = ''
170 s = s + ones[index]*x
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000171 label = s + label
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000172 index = index + 1
Guido van Rossum9787bdaf1996-05-28 23:50:49 +0000173 if case == 'I':
Eric S. Raymondb08b2d32001-02-09 11:10:16 +0000174 return label.upper()
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000175 return label
176
Walter Dörwald65230a22002-06-03 15:58:32 +0000177 def add_flowing_data(self, data):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000178 if not data: return
179 # The following looks a bit convoluted but is a great improvement over
180 # data = regsub.gsub('[' + string.whitespace + ']+', ' ', data)
Walter Dörwald65230a22002-06-03 15:58:32 +0000181 prespace = data[:1].isspace()
182 postspace = data[-1:].isspace()
183 data = " ".join(data.split())
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000184 if self.nospace and not data:
185 return
186 elif prespace or self.softspace:
187 if not data:
188 if not self.nospace:
189 self.softspace = 1
190 self.parskip = 0
191 return
192 if not self.nospace:
193 data = ' ' + data
194 self.hard_break = self.nospace = self.para_end = \
195 self.parskip = self.have_label = 0
196 self.softspace = postspace
197 self.writer.send_flowing_data(data)
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000198
199 def add_literal_data(self, data):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000200 if not data: return
201 if self.softspace:
202 self.writer.send_flowing_data(" ")
203 self.hard_break = data[-1:] == '\n'
204 self.nospace = self.para_end = self.softspace = \
205 self.parskip = self.have_label = 0
206 self.writer.send_literal_data(data)
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000207
Guido van Rossumc7ae9201995-09-30 16:49:58 +0000208 def flush_softspace(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000209 if self.softspace:
210 self.hard_break = self.para_end = self.parskip = \
211 self.have_label = self.softspace = 0
212 self.nospace = 1
213 self.writer.send_flowing_data(' ')
Guido van Rossumc7ae9201995-09-30 16:49:58 +0000214
Guido van Rossum9787bdaf1996-05-28 23:50:49 +0000215 def push_alignment(self, align):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000216 if align and align != self.align:
217 self.writer.new_alignment(align)
218 self.align = align
219 self.align_stack.append(align)
220 else:
221 self.align_stack.append(self.align)
Guido van Rossum9787bdaf1996-05-28 23:50:49 +0000222
223 def pop_alignment(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000224 if self.align_stack:
225 del self.align_stack[-1]
226 if self.align_stack:
227 self.align = align = self.align_stack[-1]
228 self.writer.new_alignment(align)
229 else:
230 self.align = None
231 self.writer.new_alignment(None)
Guido van Rossum9787bdaf1996-05-28 23:50:49 +0000232
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000233 def push_font(self, (size, i, b, tt)):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000234 if self.softspace:
235 self.hard_break = self.para_end = self.softspace = 0
236 self.nospace = 1
237 self.writer.send_flowing_data(' ')
238 if self.font_stack:
239 csize, ci, cb, ctt = self.font_stack[-1]
240 if size is AS_IS: size = csize
241 if i is AS_IS: i = ci
242 if b is AS_IS: b = cb
243 if tt is AS_IS: tt = ctt
244 font = (size, i, b, tt)
245 self.font_stack.append(font)
246 self.writer.new_font(font)
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000247
248 def pop_font(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000249 if self.font_stack:
250 del self.font_stack[-1]
251 if self.font_stack:
252 font = self.font_stack[-1]
253 else:
254 font = None
255 self.writer.new_font(font)
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000256
257 def push_margin(self, margin):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000258 self.margin_stack.append(margin)
259 fstack = filter(None, self.margin_stack)
260 if not margin and fstack:
261 margin = fstack[-1]
262 self.writer.new_margin(margin, len(fstack))
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000263
264 def pop_margin(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000265 if self.margin_stack:
266 del self.margin_stack[-1]
267 fstack = filter(None, self.margin_stack)
268 if fstack:
269 margin = fstack[-1]
270 else:
271 margin = None
272 self.writer.new_margin(margin, len(fstack))
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000273
274 def set_spacing(self, spacing):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000275 self.spacing = spacing
276 self.writer.new_spacing(spacing)
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000277
Guido van Rossum9787bdaf1996-05-28 23:50:49 +0000278 def push_style(self, *styles):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000279 if self.softspace:
280 self.hard_break = self.para_end = self.softspace = 0
281 self.nospace = 1
282 self.writer.send_flowing_data(' ')
283 for style in styles:
284 self.style_stack.append(style)
285 self.writer.new_styles(tuple(self.style_stack))
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000286
Guido van Rossum9787bdaf1996-05-28 23:50:49 +0000287 def pop_style(self, n=1):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000288 del self.style_stack[-n:]
289 self.writer.new_styles(tuple(self.style_stack))
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000290
Guido van Rossum9787bdaf1996-05-28 23:50:49 +0000291 def assert_line_data(self, flag=1):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000292 self.nospace = self.hard_break = not flag
293 self.para_end = self.parskip = self.have_label = 0
Guido van Rossum9787bdaf1996-05-28 23:50:49 +0000294
295
296class NullWriter:
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000297 """Minimal writer interface to use in testing & inheritance.
298
299 A writer which only provides the interface definition; no actions are
300 taken on any methods. This should be the base class for all writers
301 which do not need to inherit any implementation methods.
302
303 """
Guido van Rossum3672aa21996-05-29 00:02:30 +0000304 def __init__(self): pass
Fred Drake28231681996-12-31 20:50:51 +0000305 def flush(self): pass
Guido van Rossum9787bdaf1996-05-28 23:50:49 +0000306 def new_alignment(self, align): pass
307 def new_font(self, font): pass
308 def new_margin(self, margin, level): pass
309 def new_spacing(self, spacing): pass
310 def new_styles(self, styles): pass
311 def send_paragraph(self, blankline): pass
312 def send_line_break(self): pass
313 def send_hor_rule(self, *args, **kw): pass
314 def send_label_data(self, data): pass
315 def send_flowing_data(self, data): pass
316 def send_literal_data(self, data): pass
317
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000318
Guido van Rossum3672aa21996-05-29 00:02:30 +0000319class AbstractWriter(NullWriter):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000320 """A writer which can be used in debugging formatters, but not much else.
321
322 Each method simply announces itself by printing its name and
323 arguments on standard output.
324
325 """
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000326
Guido van Rossum9787bdaf1996-05-28 23:50:49 +0000327 def new_alignment(self, align):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000328 print "new_alignment(%s)" % `align`
Guido van Rossum9787bdaf1996-05-28 23:50:49 +0000329
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000330 def new_font(self, font):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000331 print "new_font(%s)" % `font`
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000332
333 def new_margin(self, margin, level):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000334 print "new_margin(%s, %d)" % (`margin`, level)
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000335
336 def new_spacing(self, spacing):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000337 print "new_spacing(%s)" % `spacing`
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000338
339 def new_styles(self, styles):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000340 print "new_styles(%s)" % `styles`
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000341
342 def send_paragraph(self, blankline):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000343 print "send_paragraph(%s)" % `blankline`
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000344
345 def send_line_break(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000346 print "send_line_break()"
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000347
Guido van Rossum9787bdaf1996-05-28 23:50:49 +0000348 def send_hor_rule(self, *args, **kw):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000349 print "send_hor_rule()"
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000350
351 def send_label_data(self, data):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000352 print "send_label_data(%s)" % `data`
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000353
354 def send_flowing_data(self, data):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000355 print "send_flowing_data(%s)" % `data`
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000356
357 def send_literal_data(self, data):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000358 print "send_literal_data(%s)" % `data`
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000359
360
Guido van Rossum3672aa21996-05-29 00:02:30 +0000361class DumbWriter(NullWriter):
Raymond Hettingeraef22fb2002-05-29 16:18:42 +0000362 """Simple writer class which writes output on the file object passed in
363 as the file parameter or, if file is omitted, on standard output. The
364 output is simply word-wrapped to the number of columns specified by
365 the maxcol parameter. This class is suitable for reflowing a sequence
366 of paragraphs.
367
368 """
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000369
370 def __init__(self, file=None, maxcol=72):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000371 self.file = file or sys.stdout
372 self.maxcol = maxcol
373 NullWriter.__init__(self)
374 self.reset()
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000375
376 def reset(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000377 self.col = 0
378 self.atbreak = 0
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000379
380 def send_paragraph(self, blankline):
Fred Drakef4bb6561999-01-12 18:13:27 +0000381 self.file.write('\n'*blankline)
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000382 self.col = 0
383 self.atbreak = 0
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000384
385 def send_line_break(self):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000386 self.file.write('\n')
387 self.col = 0
388 self.atbreak = 0
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000389
Guido van Rossum9787bdaf1996-05-28 23:50:49 +0000390 def send_hor_rule(self, *args, **kw):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000391 self.file.write('\n')
392 self.file.write('-'*self.maxcol)
393 self.file.write('\n')
394 self.col = 0
395 self.atbreak = 0
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000396
397 def send_literal_data(self, data):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000398 self.file.write(data)
Eric S. Raymondb08b2d32001-02-09 11:10:16 +0000399 i = data.rfind('\n')
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000400 if i >= 0:
401 self.col = 0
402 data = data[i+1:]
Eric S. Raymondb08b2d32001-02-09 11:10:16 +0000403 data = data.expandtabs()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000404 self.col = self.col + len(data)
405 self.atbreak = 0
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000406
407 def send_flowing_data(self, data):
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000408 if not data: return
Walter Dörwald65230a22002-06-03 15:58:32 +0000409 atbreak = self.atbreak or data[0].isspace()
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000410 col = self.col
411 maxcol = self.maxcol
412 write = self.file.write
Eric S. Raymondb08b2d32001-02-09 11:10:16 +0000413 for word in data.split():
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000414 if atbreak:
415 if col + len(word) >= maxcol:
416 write('\n')
417 col = 0
418 else:
419 write(' ')
420 col = col + 1
421 write(word)
422 col = col + len(word)
423 atbreak = 1
424 self.col = col
Walter Dörwald65230a22002-06-03 15:58:32 +0000425 self.atbreak = data[-1].isspace()
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000426
427
428def test(file = None):
429 w = DumbWriter()
430 f = AbstractFormatter(w)
Raymond Hettinger094662a2002-06-01 01:29:16 +0000431 if file is not None:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000432 fp = open(file)
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000433 elif sys.argv[1:]:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000434 fp = open(sys.argv[1])
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000435 else:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000436 fp = sys.stdin
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000437 while 1:
Guido van Rossum45e2fbc1998-03-26 21:13:24 +0000438 line = fp.readline()
439 if not line:
440 break
441 if line == '\n':
442 f.end_paragraph(1)
443 else:
444 f.add_flowing_data(line)
Guido van Rossuma0eab1d1995-08-07 20:07:36 +0000445 f.end_paragraph(0)
446
447
448if __name__ == '__main__':
449 test()