blob: 47739a6610c507378d2e3b25f9edde5fed8eb490 [file] [log] [blame]
Fred Drake30a68c71998-11-23 16:59:39 +00001#! /usr/bin/env python
2
Fred Drake0eb7b2a1999-05-19 17:37:37 +00003"""Generate ESIS events based on a LaTeX source document and
4configuration data.
5
6The conversion is not strong enough to work with arbitrary LaTeX
7documents; it has only been designed to work with the highly stylized
8markup used in the standard Python documentation. A lot of
9information about specific markup is encoded in the control table
10passed to the convert() function; changing this table can allow this
11tool to support additional LaTeX markups.
12
13The format of the table is largely undocumented; see the commented
14headers where the table is specified in main(). There is no provision
15to load an alternate table from an external file.
Fred Drake30a68c71998-11-23 16:59:39 +000016"""
Fred Drake30a68c71998-11-23 16:59:39 +000017
18import errno
Fred Drake96e4a061999-07-29 22:22:13 +000019import getopt
20import os
Fred Drake30a68c71998-11-23 16:59:39 +000021import re
Fred Drake30a68c71998-11-23 16:59:39 +000022import sys
Fred Drake381832e2001-11-30 19:30:03 +000023import xml.sax
Fred Drake691a5a72000-11-22 17:56:43 +000024import xml.sax.saxutils
Fred Drake30a68c71998-11-23 16:59:39 +000025
Fred Drake2262a802001-03-23 16:53:34 +000026from esistools import encode
27
28
Fred Draked7acf021999-01-14 17:38:12 +000029DEBUG = 0
30
31
Fred Drake96e4a061999-07-29 22:22:13 +000032class LaTeXFormatError(Exception):
Fred Drake30a68c71998-11-23 16:59:39 +000033 pass
34
35
Fred Drake96e4a061999-07-29 22:22:13 +000036class LaTeXStackError(LaTeXFormatError):
37 def __init__(self, found, stack):
38 msg = "environment close for %s doesn't match;\n stack = %s" \
39 % (found, stack)
40 self.found = found
41 self.stack = stack[:]
42 LaTeXFormatError.__init__(self, msg)
43
44
Fred Drake30a68c71998-11-23 16:59:39 +000045_begin_env_rx = re.compile(r"[\\]begin{([^}]*)}")
46_end_env_rx = re.compile(r"[\\]end{([^}]*)}")
Fred Drake0eb7b2a1999-05-19 17:37:37 +000047_begin_macro_rx = re.compile(r"[\\]([a-zA-Z]+[*]?) ?({|\s*\n?)")
Fred Drake96c00b01999-05-07 19:59:02 +000048_comment_rx = re.compile("%+ ?(.*)\n[ \t]*")
Fred Drake691a5a72000-11-22 17:56:43 +000049_text_rx = re.compile(r"[^]~%\\{}]+")
Fred Drakeb5fc0ab2001-07-06 21:01:19 +000050_optional_rx = re.compile(r"\s*[[]([^]]*)[]]", re.MULTILINE)
Fred Drakeaeea9811998-12-01 19:04:12 +000051# _parameter_rx is this complicated to allow {...} inside a parameter;
52# this is useful to match tabular layout specifications like {c|p{24pt}}
53_parameter_rx = re.compile("[ \n]*{(([^{}}]|{[^}]*})*)}")
Fred Drake30a68c71998-11-23 16:59:39 +000054_token_rx = re.compile(r"[a-zA-Z][a-zA-Z0-9.-]*$")
55_start_group_rx = re.compile("[ \n]*{")
56_start_optional_rx = re.compile("[ \n]*[[]")
57
58
Fred Drake42f52981998-11-30 14:45:24 +000059ESCAPED_CHARS = "$%#^ {}&~"
Fred Drake30a68c71998-11-23 16:59:39 +000060
61
Fred Drakef79acbd1999-05-07 21:12:21 +000062def dbgmsg(msg):
Fred Draked7acf021999-01-14 17:38:12 +000063 if DEBUG:
Fred Drakef79acbd1999-05-07 21:12:21 +000064 sys.stderr.write(msg + "\n")
65
66def pushing(name, point, depth):
Fred Drake96e4a061999-07-29 22:22:13 +000067 dbgmsg("pushing <%s> at %s" % (name, point))
Fred Draked7acf021999-01-14 17:38:12 +000068
69def popping(name, point, depth):
Fred Drake96e4a061999-07-29 22:22:13 +000070 dbgmsg("popping </%s> at %s" % (name, point))
Fred Draked7acf021999-01-14 17:38:12 +000071
72
Fred Drakedf85f0b2002-10-16 16:00:42 +000073class _Stack(list):
Fred Drake96e4a061999-07-29 22:22:13 +000074 def append(self, entry):
Fred Drakedf85f0b2002-10-16 16:00:42 +000075 if not isinstance(entry, str):
Fred Drake96e4a061999-07-29 22:22:13 +000076 raise LaTeXFormatError("cannot push non-string on stack: "
77 + `entry`)
Fred Drake2262a802001-03-23 16:53:34 +000078 #dbgmsg("%s<%s>" % (" "*len(self.data), entry))
Fred Drakedf85f0b2002-10-16 16:00:42 +000079 list.append(self, entry)
Fred Drake96e4a061999-07-29 22:22:13 +000080
81 def pop(self, index=-1):
Fred Drakedf85f0b2002-10-16 16:00:42 +000082 entry = self[index]
83 del self[index]
84 #dbgmsg("%s</%s>" % (" " * len(self), entry))
Fred Drake96e4a061999-07-29 22:22:13 +000085
86 def __delitem__(self, index):
Fred Drakedf85f0b2002-10-16 16:00:42 +000087 entry = self[index]
88 list.__delitem__(self, index)
89 #dbgmsg("%s</%s>" % (" " * len(self), entry))
Fred Drake96e4a061999-07-29 22:22:13 +000090
91
92def new_stack():
93 if DEBUG:
94 return _Stack()
Fred Drakedf85f0b2002-10-16 16:00:42 +000095 else:
96 return []
Fred Drake96e4a061999-07-29 22:22:13 +000097
98
Fred Drake4fbdf971999-08-02 14:35:25 +000099class Conversion:
100 def __init__(self, ifp, ofp, table):
101 self.write = ofp.write
102 self.ofp = ofp
Fred Drake96c00b01999-05-07 19:59:02 +0000103 self.table = table
Fred Drake00c96ae2001-11-19 05:27:40 +0000104 L = [s.rstrip() for s in ifp.readlines()]
105 L.append("")
Fred Drakedf85f0b2002-10-16 16:00:42 +0000106 self.line = "\n".join(L)
Fred Drake96c00b01999-05-07 19:59:02 +0000107 self.preamble = 1
Fred Drake96c00b01999-05-07 19:59:02 +0000108
Fred Drake96e4a061999-07-29 22:22:13 +0000109 def convert(self):
110 self.subconvert()
111
Fred Drake96e4a061999-07-29 22:22:13 +0000112 def subconvert(self, endchar=None, depth=0):
113 #
114 # Parses content, including sub-structures, until the character
115 # 'endchar' is found (with no open structures), or until the end
116 # of the input data is endchar is None.
117 #
118 stack = new_stack()
119 line = self.line
120 while line:
121 if line[0] == endchar and not stack:
122 self.line = line
123 return line
124 m = _comment_rx.match(line)
125 if m:
126 text = m.group(1)
127 if text:
128 self.write("(COMMENT\n- %s \n)COMMENT\n-\\n\n"
129 % encode(text))
130 line = line[m.end():]
131 continue
132 m = _begin_env_rx.match(line)
133 if m:
134 name = m.group(1)
135 entry = self.get_env_entry(name)
136 # re-write to use the macro handler
137 line = r"\%s %s" % (name, line[m.end():])
138 continue
139 m = _end_env_rx.match(line)
140 if m:
141 # end of environment
142 envname = m.group(1)
143 entry = self.get_entry(envname)
144 while stack and envname != stack[-1] \
145 and stack[-1] in entry.endcloses:
146 self.write(")%s\n" % stack.pop())
147 if stack and envname == stack[-1]:
148 self.write(")%s\n" % entry.outputname)
149 del stack[-1]
150 else:
151 raise LaTeXStackError(envname, stack)
152 line = line[m.end():]
153 continue
154 m = _begin_macro_rx.match(line)
155 if m:
156 # start of macro
157 macroname = m.group(1)
Fred Drake691a5a72000-11-22 17:56:43 +0000158 if macroname == "c":
159 # Ugh! This is a combining character...
160 endpos = m.end()
161 self.combining_char("c", line[endpos])
162 line = line[endpos + 1:]
163 continue
Fred Drake96e4a061999-07-29 22:22:13 +0000164 entry = self.get_entry(macroname)
165 if entry.verbatim:
166 # magic case!
Fred Drake0f9bfd32001-09-28 16:26:13 +0000167 pos = line.find("\\end{%s}" % macroname)
Fred Drake96e4a061999-07-29 22:22:13 +0000168 text = line[m.end(1):pos]
169 stack.append(entry.name)
170 self.write("(%s\n" % entry.outputname)
171 self.write("-%s\n" % encode(text))
172 self.write(")%s\n" % entry.outputname)
173 stack.pop()
174 line = line[pos + len("\\end{%s}" % macroname):]
175 continue
176 while stack and stack[-1] in entry.closes:
177 top = stack.pop()
178 topentry = self.get_entry(top)
179 if topentry.outputname:
180 self.write(")%s\n-\\n\n" % topentry.outputname)
181 #
Fred Drake9eda3ae2001-09-25 20:57:36 +0000182 if entry.outputname and entry.empty:
183 self.write("e\n")
Fred Drake96e4a061999-07-29 22:22:13 +0000184 #
Fred Drake9eda3ae2001-09-25 20:57:36 +0000185 params, optional, empty = self.start_macro(macroname)
Fred Drake96e4a061999-07-29 22:22:13 +0000186 # rip off the macroname
187 if params:
188 line = line[m.end(1):]
189 elif empty:
190 line = line[m.end(1):]
191 else:
192 line = line[m.end():]
193 opened = 0
194 implied_content = 0
195
196 # handle attribute mappings here:
197 for pentry in params:
198 if pentry.type == "attribute":
199 if pentry.optional:
200 m = _optional_rx.match(line)
Fred Drake4fbdf971999-08-02 14:35:25 +0000201 if m and entry.outputname:
Fred Drake96e4a061999-07-29 22:22:13 +0000202 line = line[m.end():]
203 self.dump_attr(pentry, m.group(1))
Fred Drake4fbdf971999-08-02 14:35:25 +0000204 elif pentry.text and entry.outputname:
Fred Drake96e4a061999-07-29 22:22:13 +0000205 # value supplied by conversion spec:
206 self.dump_attr(pentry, pentry.text)
207 else:
208 m = _parameter_rx.match(line)
209 if not m:
210 raise LaTeXFormatError(
211 "could not extract parameter %s for %s: %s"
212 % (pentry.name, macroname, `line[:100]`))
Fred Drake4fbdf971999-08-02 14:35:25 +0000213 if entry.outputname:
214 self.dump_attr(pentry, m.group(1))
Fred Drake96e4a061999-07-29 22:22:13 +0000215 line = line[m.end():]
216 elif pentry.type == "child":
217 if pentry.optional:
218 m = _optional_rx.match(line)
219 if m:
220 line = line[m.end():]
221 if entry.outputname and not opened:
222 opened = 1
223 self.write("(%s\n" % entry.outputname)
224 stack.append(macroname)
225 stack.append(pentry.name)
226 self.write("(%s\n" % pentry.name)
227 self.write("-%s\n" % encode(m.group(1)))
228 self.write(")%s\n" % pentry.name)
229 stack.pop()
230 else:
231 if entry.outputname and not opened:
232 opened = 1
233 self.write("(%s\n" % entry.outputname)
234 stack.append(entry.name)
235 self.write("(%s\n" % pentry.name)
236 stack.append(pentry.name)
237 self.line = skip_white(line)[1:]
238 line = self.subconvert(
239 "}", len(stack) + depth + 1)[1:]
240 self.write(")%s\n" % stack.pop())
241 elif pentry.type == "content":
242 if pentry.implied:
243 implied_content = 1
244 else:
245 if entry.outputname and not opened:
246 opened = 1
247 self.write("(%s\n" % entry.outputname)
248 stack.append(entry.name)
249 line = skip_white(line)
250 if line[0] != "{":
251 raise LaTeXFormatError(
252 "missing content for " + macroname)
253 self.line = line[1:]
254 line = self.subconvert("}", len(stack) + depth + 1)
255 if line and line[0] == "}":
256 line = line[1:]
Fred Drake4fbdf971999-08-02 14:35:25 +0000257 elif pentry.type == "text" and pentry.text:
258 if entry.outputname and not opened:
259 opened = 1
260 stack.append(entry.name)
261 self.write("(%s\n" % entry.outputname)
Fred Drake2262a802001-03-23 16:53:34 +0000262 #dbgmsg("--- text: %s" % `pentry.text`)
Fred Drake4fbdf971999-08-02 14:35:25 +0000263 self.write("-%s\n" % encode(pentry.text))
Fred Drakef6199ed1999-08-26 17:54:16 +0000264 elif pentry.type == "entityref":
265 self.write("&%s\n" % pentry.name)
Fred Drake96e4a061999-07-29 22:22:13 +0000266 if entry.outputname:
267 if not opened:
268 self.write("(%s\n" % entry.outputname)
269 stack.append(entry.name)
270 if not implied_content:
271 self.write(")%s\n" % entry.outputname)
272 stack.pop()
Fred Drake96e4a061999-07-29 22:22:13 +0000273 continue
274 if line[0] == endchar and not stack:
275 self.line = line[1:]
276 return self.line
277 if line[0] == "}":
278 # end of macro or group
279 macroname = stack[-1]
280 if macroname:
Fred Drake2262a802001-03-23 16:53:34 +0000281 conversion = self.table[macroname]
Fred Drake96e4a061999-07-29 22:22:13 +0000282 if conversion.outputname:
283 # otherwise, it was just a bare group
284 self.write(")%s\n" % conversion.outputname)
285 del stack[-1]
286 line = line[1:]
287 continue
Fred Drake691a5a72000-11-22 17:56:43 +0000288 if line[0] == "~":
289 # don't worry about the "tie" aspect of this command
290 line = line[1:]
291 self.write("- \n")
292 continue
Fred Drake96e4a061999-07-29 22:22:13 +0000293 if line[0] == "{":
294 stack.append("")
295 line = line[1:]
296 continue
297 if line[0] == "\\" and line[1] in ESCAPED_CHARS:
298 self.write("-%s\n" % encode(line[1]))
299 line = line[2:]
300 continue
301 if line[:2] == r"\\":
302 self.write("(BREAK\n)BREAK\n")
303 line = line[2:]
304 continue
Fred Drake691a5a72000-11-22 17:56:43 +0000305 if line[:2] == r"\_":
306 line = "_" + line[2:]
307 continue
308 if line[:2] in (r"\'", r'\"'):
309 # combining characters...
310 self.combining_char(line[1], line[2])
311 line = line[3:]
312 continue
Fred Drake96e4a061999-07-29 22:22:13 +0000313 m = _text_rx.match(line)
314 if m:
315 text = encode(m.group())
316 self.write("-%s\n" % text)
317 line = line[m.end():]
318 continue
319 # special case because of \item[]
320 # XXX can we axe this???
321 if line[0] == "]":
322 self.write("-]\n")
323 line = line[1:]
324 continue
325 # avoid infinite loops
326 extra = ""
327 if len(line) > 100:
328 extra = "..."
329 raise LaTeXFormatError("could not identify markup: %s%s"
330 % (`line[:100]`, extra))
331 while stack:
332 entry = self.get_entry(stack[-1])
333 if entry.closes:
334 self.write(")%s\n-%s\n" % (entry.outputname, encode("\n")))
335 del stack[-1]
336 else:
337 break
338 if stack:
339 raise LaTeXFormatError("elements remain on stack: "
Fred Drakedf85f0b2002-10-16 16:00:42 +0000340 + ", ".join(stack))
Fred Drake96e4a061999-07-29 22:22:13 +0000341 # otherwise we just ran out of input here...
342
Fred Drake691a5a72000-11-22 17:56:43 +0000343 # This is a really limited table of combinations, but it will have
344 # to do for now.
345 _combinations = {
346 ("c", "c"): 0x00E7,
347 ("'", "e"): 0x00E9,
348 ('"', "o"): 0x00F6,
349 }
350
351 def combining_char(self, prefix, char):
352 ordinal = self._combinations[(prefix, char)]
353 self.write("-\\%%%d;\n" % ordinal)
354
Fred Drake96e4a061999-07-29 22:22:13 +0000355 def start_macro(self, name):
356 conversion = self.get_entry(name)
357 parameters = conversion.parameters
358 optional = parameters and parameters[0].optional
Fred Drake9eda3ae2001-09-25 20:57:36 +0000359 return parameters, optional, conversion.empty
Fred Drake96e4a061999-07-29 22:22:13 +0000360
361 def get_entry(self, name):
362 entry = self.table.get(name)
363 if entry is None:
Fred Drake2262a802001-03-23 16:53:34 +0000364 dbgmsg("get_entry(%s) failing; building default entry!" % `name`)
Fred Drake96e4a061999-07-29 22:22:13 +0000365 # not defined; build a default entry:
366 entry = TableEntry(name)
367 entry.has_content = 1
368 entry.parameters.append(Parameter("content"))
369 self.table[name] = entry
370 return entry
371
372 def get_env_entry(self, name):
373 entry = self.table.get(name)
374 if entry is None:
375 # not defined; build a default entry:
376 entry = TableEntry(name, 1)
377 entry.has_content = 1
378 entry.parameters.append(Parameter("content"))
379 entry.parameters[-1].implied = 1
380 self.table[name] = entry
381 elif not entry.environment:
382 raise LaTeXFormatError(
383 name + " is defined as a macro; expected environment")
384 return entry
385
386 def dump_attr(self, pentry, value):
387 if not (pentry.name and value):
388 return
389 if _token_rx.match(value):
390 dtype = "TOKEN"
391 else:
392 dtype = "CDATA"
393 self.write("A%s %s %s\n" % (pentry.name, dtype, encode(value)))
394
395
Fred Drakeeac8abe1999-07-29 22:42:27 +0000396def convert(ifp, ofp, table):
397 c = Conversion(ifp, ofp, table)
Fred Drake96e4a061999-07-29 22:22:13 +0000398 try:
399 c.convert()
400 except IOError, (err, msg):
401 if err != errno.EPIPE:
402 raise
403
404
Fred Draked7acf021999-01-14 17:38:12 +0000405def skip_white(line):
Fred Drake96e4a061999-07-29 22:22:13 +0000406 while line and line[0] in " %\n\t\r":
Fred Drake0f9bfd32001-09-28 16:26:13 +0000407 line = line[1:].lstrip()
Fred Draked7acf021999-01-14 17:38:12 +0000408 return line
409
410
Fred Drake96e4a061999-07-29 22:22:13 +0000411
412class TableEntry:
413 def __init__(self, name, environment=0):
414 self.name = name
415 self.outputname = name
416 self.environment = environment
417 self.empty = not environment
418 self.has_content = 0
419 self.verbatim = 0
420 self.auto_close = 0
421 self.parameters = []
422 self.closes = []
423 self.endcloses = []
424
425class Parameter:
426 def __init__(self, type, name=None, optional=0):
427 self.type = type
428 self.name = name
429 self.optional = optional
430 self.text = ''
431 self.implied = 0
432
433
Fred Drake381832e2001-11-30 19:30:03 +0000434class TableHandler(xml.sax.handler.ContentHandler):
435 def __init__(self):
436 self.__table = {}
Fred Drake96e4a061999-07-29 22:22:13 +0000437 self.__buffer = ''
Fred Drake381832e2001-11-30 19:30:03 +0000438 self.__methods = {}
Fred Drake96e4a061999-07-29 22:22:13 +0000439
440 def get_table(self):
441 for entry in self.__table.values():
442 if entry.environment and not entry.has_content:
443 p = Parameter("content")
444 p.implied = 1
445 entry.parameters.append(p)
446 entry.has_content = 1
447 return self.__table
448
Fred Drake381832e2001-11-30 19:30:03 +0000449 def startElement(self, tag, attrs):
450 try:
451 start, end = self.__methods[tag]
452 except KeyError:
453 start = getattr(self, "start_" + tag, None)
454 end = getattr(self, "end_" + tag, None)
455 self.__methods[tag] = (start, end)
456 if start:
457 start(attrs)
458
459 def endElement(self, tag):
460 start, end = self.__methods[tag]
461 if end:
462 end()
463
464 def endDocument(self):
465 self.__methods.clear()
466
467 def characters(self, data):
468 self.__buffer += data
469
Fred Drake96e4a061999-07-29 22:22:13 +0000470 def start_environment(self, attrs):
471 name = attrs["name"]
472 self.__current = TableEntry(name, environment=1)
473 self.__current.verbatim = attrs.get("verbatim") == "yes"
474 if attrs.has_key("outputname"):
475 self.__current.outputname = attrs.get("outputname")
Fred Drake0f9bfd32001-09-28 16:26:13 +0000476 self.__current.endcloses = attrs.get("endcloses", "").split()
Fred Drake96e4a061999-07-29 22:22:13 +0000477 def end_environment(self):
478 self.end_macro()
479
480 def start_macro(self, attrs):
481 name = attrs["name"]
482 self.__current = TableEntry(name)
Fred Drake0f9bfd32001-09-28 16:26:13 +0000483 self.__current.closes = attrs.get("closes", "").split()
Fred Drake96e4a061999-07-29 22:22:13 +0000484 if attrs.has_key("outputname"):
485 self.__current.outputname = attrs.get("outputname")
486 def end_macro(self):
Fred Drake3c1ff5c2002-04-10 04:20:33 +0000487 name = self.__current.name
488 if self.__table.has_key(name):
489 raise ValueError("name %s already in use" % `name`)
490 self.__table[name] = self.__current
Fred Drake96e4a061999-07-29 22:22:13 +0000491 self.__current = None
492
493 def start_attribute(self, attrs):
494 name = attrs.get("name")
495 optional = attrs.get("optional") == "yes"
496 if name:
497 p = Parameter("attribute", name, optional=optional)
498 else:
499 p = Parameter("attribute", optional=optional)
500 self.__current.parameters.append(p)
501 self.__buffer = ''
502 def end_attribute(self):
503 self.__current.parameters[-1].text = self.__buffer
504
Fred Drakef6199ed1999-08-26 17:54:16 +0000505 def start_entityref(self, attrs):
506 name = attrs["name"]
507 p = Parameter("entityref", name)
508 self.__current.parameters.append(p)
509
Fred Drake96e4a061999-07-29 22:22:13 +0000510 def start_child(self, attrs):
511 name = attrs["name"]
512 p = Parameter("child", name, attrs.get("optional") == "yes")
513 self.__current.parameters.append(p)
514 self.__current.empty = 0
515
516 def start_content(self, attrs):
517 p = Parameter("content")
518 p.implied = attrs.get("implied") == "yes"
519 if self.__current.environment:
520 p.implied = 1
521 self.__current.parameters.append(p)
522 self.__current.has_content = 1
523 self.__current.empty = 0
524
525 def start_text(self, attrs):
Fred Drake4fbdf971999-08-02 14:35:25 +0000526 self.__current.empty = 0
Fred Drake96e4a061999-07-29 22:22:13 +0000527 self.__buffer = ''
528 def end_text(self):
529 p = Parameter("text")
530 p.text = self.__buffer
531 self.__current.parameters.append(p)
532
Fred Drake96e4a061999-07-29 22:22:13 +0000533
Fred Drake381832e2001-11-30 19:30:03 +0000534def load_table(fp):
535 ch = TableHandler()
536 xml.sax.parse(fp, ch)
537 return ch.get_table()
Fred Drake96e4a061999-07-29 22:22:13 +0000538
539
Fred Drake30a68c71998-11-23 16:59:39 +0000540def main():
Fred Drake96e4a061999-07-29 22:22:13 +0000541 global DEBUG
542 #
Fred Drakeeac8abe1999-07-29 22:42:27 +0000543 opts, args = getopt.getopt(sys.argv[1:], "D", ["debug"])
Fred Drake96e4a061999-07-29 22:22:13 +0000544 for opt, arg in opts:
Fred Drakeeac8abe1999-07-29 22:42:27 +0000545 if opt in ("-D", "--debug"):
Fred Drakedf85f0b2002-10-16 16:00:42 +0000546 DEBUG += 1
Fred Drake96e4a061999-07-29 22:22:13 +0000547 if len(args) == 0:
548 ifp = sys.stdin
Fred Drake30a68c71998-11-23 16:59:39 +0000549 ofp = sys.stdout
Fred Drake96e4a061999-07-29 22:22:13 +0000550 elif len(args) == 1:
Fred Draked15a0a02002-04-05 18:09:22 +0000551 ifp = open(args[0])
Fred Drake96e4a061999-07-29 22:22:13 +0000552 ofp = sys.stdout
553 elif len(args) == 2:
554 ifp = open(args[0])
555 ofp = open(args[1], "w")
Fred Drake30a68c71998-11-23 16:59:39 +0000556 else:
557 usage()
558 sys.exit(2)
Fred Drakeeac8abe1999-07-29 22:42:27 +0000559
560 table = load_table(open(os.path.join(sys.path[0], 'conversion.xml')))
561 convert(ifp, ofp, table)
Fred Drake30a68c71998-11-23 16:59:39 +0000562
563
564if __name__ == "__main__":
565 main()