]> git.proxmox.com Git - mirror_edk2.git/blame - AppPkg/Applications/Python/Python-2.7.10/Lib/formatter.py
EmbeddedPkg: Extend NvVarStoreFormattedLib LIBRARY_CLASS
[mirror_edk2.git] / AppPkg / Applications / Python / Python-2.7.10 / Lib / formatter.py
CommitLineData
3257aa99
DM
1"""Generic output formatting.\r
2\r
3Formatter objects transform an abstract flow of formatting events into\r
4specific output events on writer objects. Formatters manage several stack\r
5structures to allow various properties of a writer object to be changed and\r
6restored; writers need not be able to handle relative changes nor any sort\r
7of ``change back'' operation. Specific writer properties which may be\r
8controlled via formatter objects are horizontal alignment, font, and left\r
9margin indentations. A mechanism is provided which supports providing\r
10arbitrary, non-exclusive style settings to a writer as well. Additional\r
11interfaces facilitate formatting events which are not reversible, such as\r
12paragraph separation.\r
13\r
14Writer objects encapsulate device interfaces. Abstract devices, such as\r
15file formats, are supported as well as physical devices. The provided\r
16implementations all work with abstract devices. The interface makes\r
17available mechanisms for setting the properties which formatter objects\r
18manage and inserting data into the output.\r
19"""\r
20\r
21import sys\r
22\r
23\r
24AS_IS = None\r
25\r
26\r
27class NullFormatter:\r
28 """A formatter which does nothing.\r
29\r
30 If the writer parameter is omitted, a NullWriter instance is created.\r
31 No methods of the writer are called by NullFormatter instances.\r
32\r
33 Implementations should inherit from this class if implementing a writer\r
34 interface but don't need to inherit any implementation.\r
35\r
36 """\r
37\r
38 def __init__(self, writer=None):\r
39 if writer is None:\r
40 writer = NullWriter()\r
41 self.writer = writer\r
42 def end_paragraph(self, blankline): pass\r
43 def add_line_break(self): pass\r
44 def add_hor_rule(self, *args, **kw): pass\r
45 def add_label_data(self, format, counter, blankline=None): pass\r
46 def add_flowing_data(self, data): pass\r
47 def add_literal_data(self, data): pass\r
48 def flush_softspace(self): pass\r
49 def push_alignment(self, align): pass\r
50 def pop_alignment(self): pass\r
51 def push_font(self, x): pass\r
52 def pop_font(self): pass\r
53 def push_margin(self, margin): pass\r
54 def pop_margin(self): pass\r
55 def set_spacing(self, spacing): pass\r
56 def push_style(self, *styles): pass\r
57 def pop_style(self, n=1): pass\r
58 def assert_line_data(self, flag=1): pass\r
59\r
60\r
61class AbstractFormatter:\r
62 """The standard formatter.\r
63\r
64 This implementation has demonstrated wide applicability to many writers,\r
65 and may be used directly in most circumstances. It has been used to\r
66 implement a full-featured World Wide Web browser.\r
67\r
68 """\r
69\r
70 # Space handling policy: blank spaces at the boundary between elements\r
71 # are handled by the outermost context. "Literal" data is not checked\r
72 # to determine context, so spaces in literal data are handled directly\r
73 # in all circumstances.\r
74\r
75 def __init__(self, writer):\r
76 self.writer = writer # Output device\r
77 self.align = None # Current alignment\r
78 self.align_stack = [] # Alignment stack\r
79 self.font_stack = [] # Font state\r
80 self.margin_stack = [] # Margin state\r
81 self.spacing = None # Vertical spacing state\r
82 self.style_stack = [] # Other state, e.g. color\r
83 self.nospace = 1 # Should leading space be suppressed\r
84 self.softspace = 0 # Should a space be inserted\r
85 self.para_end = 1 # Just ended a paragraph\r
86 self.parskip = 0 # Skipped space between paragraphs?\r
87 self.hard_break = 1 # Have a hard break\r
88 self.have_label = 0\r
89\r
90 def end_paragraph(self, blankline):\r
91 if not self.hard_break:\r
92 self.writer.send_line_break()\r
93 self.have_label = 0\r
94 if self.parskip < blankline and not self.have_label:\r
95 self.writer.send_paragraph(blankline - self.parskip)\r
96 self.parskip = blankline\r
97 self.have_label = 0\r
98 self.hard_break = self.nospace = self.para_end = 1\r
99 self.softspace = 0\r
100\r
101 def add_line_break(self):\r
102 if not (self.hard_break or self.para_end):\r
103 self.writer.send_line_break()\r
104 self.have_label = self.parskip = 0\r
105 self.hard_break = self.nospace = 1\r
106 self.softspace = 0\r
107\r
108 def add_hor_rule(self, *args, **kw):\r
109 if not self.hard_break:\r
110 self.writer.send_line_break()\r
111 self.writer.send_hor_rule(*args, **kw)\r
112 self.hard_break = self.nospace = 1\r
113 self.have_label = self.para_end = self.softspace = self.parskip = 0\r
114\r
115 def add_label_data(self, format, counter, blankline = None):\r
116 if self.have_label or not self.hard_break:\r
117 self.writer.send_line_break()\r
118 if not self.para_end:\r
119 self.writer.send_paragraph((blankline and 1) or 0)\r
120 if isinstance(format, str):\r
121 self.writer.send_label_data(self.format_counter(format, counter))\r
122 else:\r
123 self.writer.send_label_data(format)\r
124 self.nospace = self.have_label = self.hard_break = self.para_end = 1\r
125 self.softspace = self.parskip = 0\r
126\r
127 def format_counter(self, format, counter):\r
128 label = ''\r
129 for c in format:\r
130 if c == '1':\r
131 label = label + ('%d' % counter)\r
132 elif c in 'aA':\r
133 if counter > 0:\r
134 label = label + self.format_letter(c, counter)\r
135 elif c in 'iI':\r
136 if counter > 0:\r
137 label = label + self.format_roman(c, counter)\r
138 else:\r
139 label = label + c\r
140 return label\r
141\r
142 def format_letter(self, case, counter):\r
143 label = ''\r
144 while counter > 0:\r
145 counter, x = divmod(counter-1, 26)\r
146 # This makes a strong assumption that lowercase letters\r
147 # and uppercase letters form two contiguous blocks, with\r
148 # letters in order!\r
149 s = chr(ord(case) + x)\r
150 label = s + label\r
151 return label\r
152\r
153 def format_roman(self, case, counter):\r
154 ones = ['i', 'x', 'c', 'm']\r
155 fives = ['v', 'l', 'd']\r
156 label, index = '', 0\r
157 # This will die of IndexError when counter is too big\r
158 while counter > 0:\r
159 counter, x = divmod(counter, 10)\r
160 if x == 9:\r
161 label = ones[index] + ones[index+1] + label\r
162 elif x == 4:\r
163 label = ones[index] + fives[index] + label\r
164 else:\r
165 if x >= 5:\r
166 s = fives[index]\r
167 x = x-5\r
168 else:\r
169 s = ''\r
170 s = s + ones[index]*x\r
171 label = s + label\r
172 index = index + 1\r
173 if case == 'I':\r
174 return label.upper()\r
175 return label\r
176\r
177 def add_flowing_data(self, data):\r
178 if not data: return\r
179 prespace = data[:1].isspace()\r
180 postspace = data[-1:].isspace()\r
181 data = " ".join(data.split())\r
182 if self.nospace and not data:\r
183 return\r
184 elif prespace or self.softspace:\r
185 if not data:\r
186 if not self.nospace:\r
187 self.softspace = 1\r
188 self.parskip = 0\r
189 return\r
190 if not self.nospace:\r
191 data = ' ' + data\r
192 self.hard_break = self.nospace = self.para_end = \\r
193 self.parskip = self.have_label = 0\r
194 self.softspace = postspace\r
195 self.writer.send_flowing_data(data)\r
196\r
197 def add_literal_data(self, data):\r
198 if not data: return\r
199 if self.softspace:\r
200 self.writer.send_flowing_data(" ")\r
201 self.hard_break = data[-1:] == '\n'\r
202 self.nospace = self.para_end = self.softspace = \\r
203 self.parskip = self.have_label = 0\r
204 self.writer.send_literal_data(data)\r
205\r
206 def flush_softspace(self):\r
207 if self.softspace:\r
208 self.hard_break = self.para_end = self.parskip = \\r
209 self.have_label = self.softspace = 0\r
210 self.nospace = 1\r
211 self.writer.send_flowing_data(' ')\r
212\r
213 def push_alignment(self, align):\r
214 if align and align != self.align:\r
215 self.writer.new_alignment(align)\r
216 self.align = align\r
217 self.align_stack.append(align)\r
218 else:\r
219 self.align_stack.append(self.align)\r
220\r
221 def pop_alignment(self):\r
222 if self.align_stack:\r
223 del self.align_stack[-1]\r
224 if self.align_stack:\r
225 self.align = align = self.align_stack[-1]\r
226 self.writer.new_alignment(align)\r
227 else:\r
228 self.align = None\r
229 self.writer.new_alignment(None)\r
230\r
231 def push_font(self, font):\r
232 size, i, b, tt = font\r
233 if self.softspace:\r
234 self.hard_break = self.para_end = self.softspace = 0\r
235 self.nospace = 1\r
236 self.writer.send_flowing_data(' ')\r
237 if self.font_stack:\r
238 csize, ci, cb, ctt = self.font_stack[-1]\r
239 if size is AS_IS: size = csize\r
240 if i is AS_IS: i = ci\r
241 if b is AS_IS: b = cb\r
242 if tt is AS_IS: tt = ctt\r
243 font = (size, i, b, tt)\r
244 self.font_stack.append(font)\r
245 self.writer.new_font(font)\r
246\r
247 def pop_font(self):\r
248 if self.font_stack:\r
249 del self.font_stack[-1]\r
250 if self.font_stack:\r
251 font = self.font_stack[-1]\r
252 else:\r
253 font = None\r
254 self.writer.new_font(font)\r
255\r
256 def push_margin(self, margin):\r
257 self.margin_stack.append(margin)\r
258 fstack = filter(None, self.margin_stack)\r
259 if not margin and fstack:\r
260 margin = fstack[-1]\r
261 self.writer.new_margin(margin, len(fstack))\r
262\r
263 def pop_margin(self):\r
264 if self.margin_stack:\r
265 del self.margin_stack[-1]\r
266 fstack = filter(None, self.margin_stack)\r
267 if fstack:\r
268 margin = fstack[-1]\r
269 else:\r
270 margin = None\r
271 self.writer.new_margin(margin, len(fstack))\r
272\r
273 def set_spacing(self, spacing):\r
274 self.spacing = spacing\r
275 self.writer.new_spacing(spacing)\r
276\r
277 def push_style(self, *styles):\r
278 if self.softspace:\r
279 self.hard_break = self.para_end = self.softspace = 0\r
280 self.nospace = 1\r
281 self.writer.send_flowing_data(' ')\r
282 for style in styles:\r
283 self.style_stack.append(style)\r
284 self.writer.new_styles(tuple(self.style_stack))\r
285\r
286 def pop_style(self, n=1):\r
287 del self.style_stack[-n:]\r
288 self.writer.new_styles(tuple(self.style_stack))\r
289\r
290 def assert_line_data(self, flag=1):\r
291 self.nospace = self.hard_break = not flag\r
292 self.para_end = self.parskip = self.have_label = 0\r
293\r
294\r
295class NullWriter:\r
296 """Minimal writer interface to use in testing & inheritance.\r
297\r
298 A writer which only provides the interface definition; no actions are\r
299 taken on any methods. This should be the base class for all writers\r
300 which do not need to inherit any implementation methods.\r
301\r
302 """\r
303 def __init__(self): pass\r
304 def flush(self): pass\r
305 def new_alignment(self, align): pass\r
306 def new_font(self, font): pass\r
307 def new_margin(self, margin, level): pass\r
308 def new_spacing(self, spacing): pass\r
309 def new_styles(self, styles): pass\r
310 def send_paragraph(self, blankline): pass\r
311 def send_line_break(self): pass\r
312 def send_hor_rule(self, *args, **kw): pass\r
313 def send_label_data(self, data): pass\r
314 def send_flowing_data(self, data): pass\r
315 def send_literal_data(self, data): pass\r
316\r
317\r
318class AbstractWriter(NullWriter):\r
319 """A writer which can be used in debugging formatters, but not much else.\r
320\r
321 Each method simply announces itself by printing its name and\r
322 arguments on standard output.\r
323\r
324 """\r
325\r
326 def new_alignment(self, align):\r
327 print "new_alignment(%r)" % (align,)\r
328\r
329 def new_font(self, font):\r
330 print "new_font(%r)" % (font,)\r
331\r
332 def new_margin(self, margin, level):\r
333 print "new_margin(%r, %d)" % (margin, level)\r
334\r
335 def new_spacing(self, spacing):\r
336 print "new_spacing(%r)" % (spacing,)\r
337\r
338 def new_styles(self, styles):\r
339 print "new_styles(%r)" % (styles,)\r
340\r
341 def send_paragraph(self, blankline):\r
342 print "send_paragraph(%r)" % (blankline,)\r
343\r
344 def send_line_break(self):\r
345 print "send_line_break()"\r
346\r
347 def send_hor_rule(self, *args, **kw):\r
348 print "send_hor_rule()"\r
349\r
350 def send_label_data(self, data):\r
351 print "send_label_data(%r)" % (data,)\r
352\r
353 def send_flowing_data(self, data):\r
354 print "send_flowing_data(%r)" % (data,)\r
355\r
356 def send_literal_data(self, data):\r
357 print "send_literal_data(%r)" % (data,)\r
358\r
359\r
360class DumbWriter(NullWriter):\r
361 """Simple writer class which writes output on the file object passed in\r
362 as the file parameter or, if file is omitted, on standard output. The\r
363 output is simply word-wrapped to the number of columns specified by\r
364 the maxcol parameter. This class is suitable for reflowing a sequence\r
365 of paragraphs.\r
366\r
367 """\r
368\r
369 def __init__(self, file=None, maxcol=72):\r
370 self.file = file or sys.stdout\r
371 self.maxcol = maxcol\r
372 NullWriter.__init__(self)\r
373 self.reset()\r
374\r
375 def reset(self):\r
376 self.col = 0\r
377 self.atbreak = 0\r
378\r
379 def send_paragraph(self, blankline):\r
380 self.file.write('\n'*blankline)\r
381 self.col = 0\r
382 self.atbreak = 0\r
383\r
384 def send_line_break(self):\r
385 self.file.write('\n')\r
386 self.col = 0\r
387 self.atbreak = 0\r
388\r
389 def send_hor_rule(self, *args, **kw):\r
390 self.file.write('\n')\r
391 self.file.write('-'*self.maxcol)\r
392 self.file.write('\n')\r
393 self.col = 0\r
394 self.atbreak = 0\r
395\r
396 def send_literal_data(self, data):\r
397 self.file.write(data)\r
398 i = data.rfind('\n')\r
399 if i >= 0:\r
400 self.col = 0\r
401 data = data[i+1:]\r
402 data = data.expandtabs()\r
403 self.col = self.col + len(data)\r
404 self.atbreak = 0\r
405\r
406 def send_flowing_data(self, data):\r
407 if not data: return\r
408 atbreak = self.atbreak or data[0].isspace()\r
409 col = self.col\r
410 maxcol = self.maxcol\r
411 write = self.file.write\r
412 for word in data.split():\r
413 if atbreak:\r
414 if col + len(word) >= maxcol:\r
415 write('\n')\r
416 col = 0\r
417 else:\r
418 write(' ')\r
419 col = col + 1\r
420 write(word)\r
421 col = col + len(word)\r
422 atbreak = 1\r
423 self.col = col\r
424 self.atbreak = data[-1].isspace()\r
425\r
426\r
427def test(file = None):\r
428 w = DumbWriter()\r
429 f = AbstractFormatter(w)\r
430 if file is not None:\r
431 fp = open(file)\r
432 elif sys.argv[1:]:\r
433 fp = open(sys.argv[1])\r
434 else:\r
435 fp = sys.stdin\r
436 for line in fp:\r
437 if line == '\n':\r
438 f.end_paragraph(1)\r
439 else:\r
440 f.add_flowing_data(line)\r
441 f.end_paragraph(0)\r
442\r
443\r
444if __name__ == '__main__':\r
445 test()\r