blob: a1c0ebd44ae73da7df75c56a3cdf42cd5e2de13c [file] [log] [blame]
Guido van Rossum26a9d371995-03-15 11:26:05 +00001#! /usr/local/bin/python
2
3# Convert GNU texinfo files into HTML, one file per node.
4# Based on Texinfo 2.14.
Guido van Rossum06f42891995-08-28 03:01:00 +00005# Usage: texi2html [-d] [-d] [-c] inputfile outputdirectory
Guido van Rossum26a9d371995-03-15 11:26:05 +00006# The input file must be a complete texinfo file, e.g. emacs.texi.
7# This creates many files (one per info node) in the output directory,
8# overwriting existing files of the same name. All files created have
9# ".html" as their extension.
10
11
12# XXX To do:
13# - handle @comment*** correctly
14# - handle @xref {some words} correctly
15# - handle @ftable correctly (items aren't indexed?)
16# - handle @itemx properly
17# - handle @exdent properly
18# - add links directly to the proper line from indices
19# - check against the definitive list of @-cmds; we still miss (among others):
Guido van Rossum26a9d371995-03-15 11:26:05 +000020# - @defindex (hard)
21# - @c(omment) in the middle of a line (rarely used)
22# - @this* (not really needed, only used in headers anyway)
23# - @today{} (ever used outside title page?)
24
Guido van Rossum06f42891995-08-28 03:01:00 +000025# More consistent handling of chapters/sections/etc.
26# Lots of documentation
27# Many more options:
28# -top designate top node
29# -links customize which types of links are included
30# -split split at chapters or sections instead of nodes
31# -name Allow different types of filename handling. Non unix systems
32# will have problems with long node names
33# ...
34# Support the most recent texinfo version and take a good look at HTML 3.0
35# More debugging output (customizable) and more fexible error handling
36# How about icons ?
Guido van Rossum26a9d371995-03-15 11:26:05 +000037
38import os
39import regex
40import regsub
41import string
42
43MAGIC = '\\input texinfo'
44
45cmprog = regex.compile('^@\([a-z]+\)\([ \t]\|$\)') # Command (line-oriented)
46blprog = regex.compile('^[ \t]*$') # Blank line
47kwprog = regex.compile('@[a-z]+') # Keyword (embedded, usually with {} args)
48spprog = regex.compile('[\n@{}&<>]') # Special characters in running text
49miprog = regex.compile( \
50 '^\* \([^:]*\):\(:\|[ \t]*\([^\t,\n.]+\)\([^ \t\n]*\)\)[ \t\n]*')
51 # menu item (Yuck!)
52
Guido van Rossum06f42891995-08-28 03:01:00 +000053
54class Node:
55 __doc__ = """
56 Some of the parser's functionality is separated into this class.
57
58 A Node accumulates its contents, takes care of links to other Nodes
59 and saves itself when it is finished and all links are resolved. """
60
61 def __init__ (self, dir, name, topname, title, next, prev, up):
62 self.dirname = dir
63 self.name = name
64 if topname:
65 self.topname = topname
66 else:
67 self.topname = name
68 self.title = title
69 self.next = next
70 self.prev = prev
71 self.up = up
72 self.lines = []
73 self.type = 0
74 self.cont = ''
75
76 def write (self, *lines):
77 for line in lines:
78 self.lines.append (line)
79
80 def flush (self):
81 fp = open (self.dirname + '/' + makefile(self.name), 'w')
82 fp.write (self.prologue)
83 fp.write (self.text)
84 fp.write (self.epilogue)
85 fp.close ()
86
87
88 def link(self, label, nodename):
89 if nodename:
90 if string.lower(nodename) == '(dir)':
91 addr = '../dir.html'
92 else:
93 addr = makefile(nodename)
94 self.write(label, ': <A HREF="', addr, '" TYPE="', \
95 label, '">', nodename, '</A> \n')
96
97
98 def finalize(self):
99 length = len (self.lines)
100 self.text = string.joinfields (self.lines, '')
101 self.lines = []
102 self.write ('<BR> <HR>\n')
103 if self.cont != self.next:
104 self.link('Cont', self.cont)
105 self.link('Next', self.next)
106 self.link('Prev', self.prev)
107 self.link('Up', self.up)
108 if self.name <> self.topname:
109 self.link('Top', self.topname)
110 self.write ('<BR> <HR> <P>\n')
111 links = string.joinfields (self.lines, '')
112 self.lines = []
113
114 self.prologue = \
115 '<!DOCTYPE HTML PUBLIC "-//W3O//DTD W3 HTML 2.0//EN">\n' + \
116 '<!- Converted with texi2html and Python>\n' + \
117 '<P>\n<HEAD>\n' + \
118 '<TITLE>' + self.title + '</TITLE>\n' + \
119 '</HEAD>\n<BODY>\n<P>\n' + \
120 links
121
122 if length > 20:
123 self.epilogue = links + '</BODY>\n'
124 else:
125 self.epilogue = '</BODY>\n'
126
127
Guido van Rossum26a9d371995-03-15 11:26:05 +0000128class TexinfoParser:
129
130 # Initialize an instance
131 def __init__(self):
132 self.unknown = {} # statistics about unknown @-commands
Guido van Rossuma12bbff1995-05-03 14:17:36 +0000133 self.filenames = {} # Check for identical filenames
Guido van Rossum26a9d371995-03-15 11:26:05 +0000134 self.debugging = 0 # larger values produce more output
135 self.nodefp = None # open file we're writing to
Guido van Rossuma12bbff1995-05-03 14:17:36 +0000136 self.nodelineno = 0 # Linenumber relative to node
137 self.links = None # Links from current node
Guido van Rossum26a9d371995-03-15 11:26:05 +0000138 self.savetext = None # If not None, save text head instead
Guido van Rossum06f42891995-08-28 03:01:00 +0000139 self.savestack = [] # If not None, save text head instead
Guido van Rossum26a9d371995-03-15 11:26:05 +0000140 self.dirname = 'tmp' # directory where files are created
141 self.includedir = '.' # directory to search @include files
142 self.nodename = '' # name of current node
143 self.topname = '' # name of top node (first node seen)
144 self.title = '' # title of this whole Texinfo tree
145 self.resetindex() # Reset all indices
146 self.contents = [] # Reset table of contents
147 self.numbering = [] # Reset section numbering counters
148 self.nofill = 0 # Normal operation: fill paragraphs
Guido van Rossum06f42891995-08-28 03:01:00 +0000149 self.values={'html': 1} # Names that should be parsed in ifset
Guido van Rossuma12bbff1995-05-03 14:17:36 +0000150 self.stackinfo={} # Keep track of state in the stack
Guido van Rossum26a9d371995-03-15 11:26:05 +0000151 # XXX The following should be reset per node?!
152 self.footnotes = [] # Reset list of footnotes
153 self.itemarg = None # Reset command used by @item
154 self.itemnumber = None # Reset number for @item in @enumerate
155 self.itemindex = None # Reset item index name
Guido van Rossum06f42891995-08-28 03:01:00 +0000156 self.node = None
157 self.nodestack = []
158 self.cont = 0
159 self.includedepth = 0
Guido van Rossum26a9d371995-03-15 11:26:05 +0000160 # Set (output) directory name
161 def setdirname(self, dirname):
162 self.dirname = dirname
163
164 # Set include directory name
165 def setincludedir(self, includedir):
166 self.includedir = includedir
167
168 # Parse the contents of an entire file
169 def parse(self, fp):
170 line = fp.readline()
171 lineno = 1
172 while line and (line[0] == '%' or blprog.match(line) >= 0):
173 line = fp.readline()
174 lineno = lineno + 1
175 if line[:len(MAGIC)] <> MAGIC:
176 raise SyntaxError, 'file does not begin with '+`MAGIC`
177 self.parserest(fp, lineno)
178
179 # Parse the contents of a file, not expecting a MAGIC header
180 def parserest(self, fp, initial_lineno):
181 lineno = initial_lineno
182 self.done = 0
183 self.skip = 0
184 self.stack = []
185 accu = []
186 while not self.done:
187 line = fp.readline()
Guido van Rossuma12bbff1995-05-03 14:17:36 +0000188 self.nodelineno = self.nodelineno + 1
Guido van Rossum26a9d371995-03-15 11:26:05 +0000189 if not line:
190 if accu:
191 if not self.skip: self.process(accu)
192 accu = []
193 if initial_lineno > 0:
194 print '*** EOF before @bye'
195 break
196 lineno = lineno + 1
197 if cmprog.match(line) >= 0:
198 a, b = cmprog.regs[1]
199 cmd = line[a:b]
200 if cmd in ('noindent', 'refill'):
201 accu.append(line)
202 else:
203 if accu:
204 if not self.skip:
205 self.process(accu)
206 accu = []
207 self.command(line)
Guido van Rossuma12bbff1995-05-03 14:17:36 +0000208 elif blprog.match(line) >= 0 and \
209 'format' not in self.stack and \
210 'example' not in self.stack:
Guido van Rossum26a9d371995-03-15 11:26:05 +0000211 if accu:
212 if not self.skip:
213 self.process(accu)
214 self.write('<P>\n')
Guido van Rossuma12bbff1995-05-03 14:17:36 +0000215 accu = []
Guido van Rossum26a9d371995-03-15 11:26:05 +0000216 else:
217 # Append the line including trailing \n!
218 accu.append(line)
219 #
220 if self.skip:
221 print '*** Still skipping at the end'
222 if self.stack:
223 print '*** Stack not empty at the end'
224 print '***', self.stack
Guido van Rossum06f42891995-08-28 03:01:00 +0000225 if self.includedepth == 0:
226 while self.nodestack:
227 self.nodestack[-1].finalize ()
228 self.nodestack[-1].flush ()
229 del self.nodestack [-1]
Guido van Rossum26a9d371995-03-15 11:26:05 +0000230
231 # Start saving text in a buffer instead of writing it to a file
232 def startsaving(self):
233 if self.savetext <> None:
Guido van Rossum06f42891995-08-28 03:01:00 +0000234 self.savestack.append (self.savetext)
235 # print '*** Recursively saving text, expect trouble'
Guido van Rossum26a9d371995-03-15 11:26:05 +0000236 self.savetext = ''
237
238 # Return the text saved so far and start writing to file again
239 def collectsavings(self):
240 savetext = self.savetext
Guido van Rossum06f42891995-08-28 03:01:00 +0000241 if len (self.savestack) > 0:
242 self.savetext = self.savestack[-1]
243 del self.savestack[-1]
244 else:
245 self.savetext = None
Guido van Rossum26a9d371995-03-15 11:26:05 +0000246 return savetext or ''
247
248 # Write text to file, or save it in a buffer, or ignore it
249 def write(self, *args):
Guido van Rossum06f42891995-08-28 03:01:00 +0000250 try:
251 text = string.joinfields(args, '')
252 except:
253 print args
254 raise TypeError
Guido van Rossum26a9d371995-03-15 11:26:05 +0000255 if self.savetext <> None:
256 self.savetext = self.savetext + text
257 elif self.nodefp:
258 self.nodefp.write(text)
Guido van Rossum06f42891995-08-28 03:01:00 +0000259 elif self.node:
260 self.node.write (text)
Guido van Rossum26a9d371995-03-15 11:26:05 +0000261 # Complete the current node -- write footnotes and close file
262 def endnode(self):
263 if self.savetext <> None:
264 print '*** Still saving text at end of node'
265 dummy = self.collectsavings()
266 if self.footnotes:
267 self.writefootnotes()
268 if self.nodefp:
Guido van Rossuma12bbff1995-05-03 14:17:36 +0000269 if self.nodelineno > 20:
270 self.write ('<HR>\n')
271 [name, next, prev, up] = self.nodelinks[:4]
272 self.link('Next', next)
273 self.link('Prev', prev)
274 self.link('Up', up)
275 if self.nodename <> self.topname:
276 self.link('Top', self.topname)
277 self.write ('<HR>\n')
278 self.write('</BODY>\n')
Guido van Rossum26a9d371995-03-15 11:26:05 +0000279 self.nodefp.close()
Guido van Rossum06f42891995-08-28 03:01:00 +0000280 self.nodefp = None
281 elif self.node:
282 if not self.cont and \
283 (not self.node.type or \
284 (self.node.next and self.node.prev and self.node.up)):
285 self.node.finalize ()
286 self.node.flush ()
287 else:
288 self.nodestack.append (self.node)
289 self.node = None
Guido van Rossum26a9d371995-03-15 11:26:05 +0000290 self.nodename = ''
291
292 # Process a list of lines, expanding embedded @-commands
293 # This mostly distinguishes between menus and normal text
294 def process(self, accu):
295 if self.debugging > 1:
296 print self.skip, self.stack,
297 if accu: print accu[0][:30],
298 if accu[0][30:] or accu[1:]: print '...',
299 print
300 if self.stack and self.stack[-1] == 'menu':
301 # XXX should be done differently
302 for line in accu:
303 if miprog.match(line) < 0:
304 line = string.strip(line) + '\n'
305 self.expand(line)
306 continue
307 (bgn, end), (a, b), (c, d), (e, f), (g, h) = \
308 miprog.regs[:5]
309 label = line[a:b]
310 nodename = line[c:d]
311 if nodename[0] == ':': nodename = label
312 else: nodename = line[e:f]
313 punct = line[g:h]
314 self.write('<DT><A HREF="', \
315 makefile(nodename), \
316 '" TYPE=Menu>', nodename, \
317 '</A>', punct, '\n<DD>')
318 self.expand(line[end:])
319 else:
320 text = string.joinfields(accu, '')
321 self.expand(text)
322
323 # Write a string, expanding embedded @-commands
324 def expand(self, text):
325 stack = []
326 i = 0
327 n = len(text)
328 while i < n:
329 start = i
330 i = spprog.search(text, i)
331 if i < 0:
332 self.write(text[start:])
333 break
334 self.write(text[start:i])
335 c = text[i]
336 i = i+1
337 if c == '\n':
338 if self.nofill > 0:
339 self.write('<P>\n')
340 else:
341 self.write('\n')
342 continue
343 if c == '<':
344 self.write('&lt;')
345 continue
346 if c == '>':
347 self.write('&gt;')
348 continue
349 if c == '&':
350 self.write('&amp;')
351 continue
352 if c == '{':
353 stack.append('')
354 continue
355 if c == '}':
356 if not stack:
357 print '*** Unmatched }'
358 self.write('}')
359 continue
360 cmd = stack[-1]
361 del stack[-1]
362 try:
363 method = getattr(self, 'close_' + cmd)
364 except AttributeError:
365 self.unknown_close(cmd)
366 continue
367 method()
368 continue
369 if c <> '@':
370 # Cannot happen unless spprog is changed
371 raise RuntimeError, 'unexpected funny '+`c`
372 start = i
373 while i < n and text[i] in string.letters: i = i+1
374 if i == start:
375 # @ plus non-letter: literal next character
376 i = i+1
377 c = text[start:i]
378 if c == ':':
379 # `@:' means no extra space after
380 # preceding `.', `?', `!' or `:'
381 pass
382 else:
383 # `@.' means a sentence-ending period;
384 # `@@', `@{', `@}' quote `@', `{', `}'
385 self.write(c)
386 continue
387 cmd = text[start:i]
388 if i < n and text[i] == '{':
389 i = i+1
390 stack.append(cmd)
391 try:
392 method = getattr(self, 'open_' + cmd)
393 except AttributeError:
394 self.unknown_open(cmd)
395 continue
396 method()
397 continue
398 try:
399 method = getattr(self, 'handle_' + cmd)
400 except AttributeError:
401 self.unknown_handle(cmd)
402 continue
403 method()
404 if stack:
405 print '*** Stack not empty at para:', stack
406
407 # --- Handle unknown embedded @-commands ---
408
409 def unknown_open(self, cmd):
410 print '*** No open func for @' + cmd + '{...}'
411 cmd = cmd + '{'
412 self.write('@', cmd)
413 if not self.unknown.has_key(cmd):
414 self.unknown[cmd] = 1
415 else:
416 self.unknown[cmd] = self.unknown[cmd] + 1
417
418 def unknown_close(self, cmd):
419 print '*** No close func for @' + cmd + '{...}'
420 cmd = '}' + cmd
421 self.write('}')
422 if not self.unknown.has_key(cmd):
423 self.unknown[cmd] = 1
424 else:
425 self.unknown[cmd] = self.unknown[cmd] + 1
426
427 def unknown_handle(self, cmd):
428 print '*** No handler for @' + cmd
429 self.write('@', cmd)
430 if not self.unknown.has_key(cmd):
431 self.unknown[cmd] = 1
432 else:
433 self.unknown[cmd] = self.unknown[cmd] + 1
434
435 # XXX The following sections should be ordered as the texinfo docs
436
437 # --- Embedded @-commands without {} argument list --
438
439 def handle_noindent(self): pass
440
441 def handle_refill(self): pass
442
443 # --- Include file handling ---
444
445 def do_include(self, args):
446 file = args
447 file = os.path.join(self.includedir, file)
448 try:
449 fp = open(file, 'r')
450 except IOError, msg:
451 print '*** Can\'t open include file', `file`
452 return
453 if self.debugging:
454 print '--> file', `file`
455 save_done = self.done
456 save_skip = self.skip
457 save_stack = self.stack
Guido van Rossum06f42891995-08-28 03:01:00 +0000458 self.includedepth = self.includedepth + 1
Guido van Rossum26a9d371995-03-15 11:26:05 +0000459 self.parserest(fp, 0)
Guido van Rossum06f42891995-08-28 03:01:00 +0000460 self.includedepth = self.includedepth - 1
Guido van Rossum26a9d371995-03-15 11:26:05 +0000461 fp.close()
462 self.done = save_done
463 self.skip = save_skip
464 self.stack = save_stack
465 if self.debugging:
466 print '<-- file', `file`
467
468 # --- Special Insertions ---
469
470 def open_dmn(self): pass
471 def close_dmn(self): pass
472
473 def open_dots(self): self.write('...')
474 def close_dots(self): pass
475
Guido van Rossuma12bbff1995-05-03 14:17:36 +0000476 def open_bullet(self): pass
Guido van Rossum26a9d371995-03-15 11:26:05 +0000477 def close_bullet(self): pass
478
479 def open_TeX(self): self.write('TeX')
480 def close_TeX(self): pass
481
Guido van Rossuma12bbff1995-05-03 14:17:36 +0000482 def handle_copyright(self): self.write('(C)')
Guido van Rossum06f42891995-08-28 03:01:00 +0000483 def open_copyright(self): self.write('(C)')
484 def close_copyright(self): pass
485
Guido van Rossum26a9d371995-03-15 11:26:05 +0000486 def open_minus(self): self.write('-')
487 def close_minus(self): pass
488
489 # --- Special Glyphs for Examples ---
490
491 def open_result(self): self.write('=&gt;')
492 def close_result(self): pass
493
494 def open_expansion(self): self.write('==&gt;')
495 def close_expansion(self): pass
496
497 def open_print(self): self.write('-|')
498 def close_print(self): pass
499
500 def open_error(self): self.write('error--&gt;')
501 def close_error(self): pass
502
503 def open_equiv(self): self.write('==')
504 def close_equiv(self): pass
505
506 def open_point(self): self.write('-!-')
507 def close_point(self): pass
508
509 # --- Cross References ---
510
511 def open_pxref(self):
512 self.write('see ')
513 self.startsaving()
514 def close_pxref(self):
515 self.makeref()
516
517 def open_xref(self):
518 self.write('See ')
519 self.startsaving()
520 def close_xref(self):
521 self.makeref()
522
523 def open_ref(self):
524 self.startsaving()
525 def close_ref(self):
526 self.makeref()
527
528 def open_inforef(self):
529 self.write('See info file ')
530 self.startsaving()
531 def close_inforef(self):
532 text = self.collectsavings()
533 args = string.splitfields(text, ',')
534 n = len(args)
535 for i in range(n):
536 args[i] = string.strip(args[i])
537 while len(args) < 3: args.append('')
538 node = args[0]
539 file = args[2]
540 self.write('`', file, '\', node `', node, '\'')
541
542 def makeref(self):
543 text = self.collectsavings()
544 args = string.splitfields(text, ',')
545 n = len(args)
546 for i in range(n):
547 args[i] = string.strip(args[i])
548 while len(args) < 5: args.append('')
549 nodename = label = args[0]
550 if args[2]: label = args[2]
551 file = args[3]
552 title = args[4]
553 href = makefile(nodename)
554 if file:
555 href = '../' + file + '/' + href
556 self.write('<A HREF="', href, '">', label, '</A>')
557
558 # --- Marking Words and Phrases ---
559
560 # --- Other @xxx{...} commands ---
561
562 def open_(self): pass # Used by {text enclosed in braces}
563 def close_(self): pass
564
565 open_asis = open_
566 close_asis = close_
567
568 def open_cite(self): self.write('<CITE>')
569 def close_cite(self): self.write('</CITE>')
570
571 def open_code(self): self.write('<CODE>')
572 def close_code(self): self.write('</CODE>')
573
574 open_t = open_code
575 close_t = close_code
576
577 def open_dfn(self): self.write('<DFN>')
578 def close_dfn(self): self.write('</DFN>')
579
580 def open_emph(self): self.write('<I>')
581 def close_emph(self): self.write('</I>')
582
583 open_i = open_emph
584 close_i = close_emph
585
586 def open_footnote(self):
Guido van Rossum06f42891995-08-28 03:01:00 +0000587 # if self.savetext <> None:
588 # print '*** Recursive footnote -- expect weirdness'
Guido van Rossum26a9d371995-03-15 11:26:05 +0000589 id = len(self.footnotes) + 1
590 self.write('<A NAME="footnoteref', `id`, \
591 '" HREF="#footnotetext', `id`, '">(', `id`, ')</A>')
Guido van Rossum06f42891995-08-28 03:01:00 +0000592 # self.savetext = ''
593 self.startsaving ()
Guido van Rossum26a9d371995-03-15 11:26:05 +0000594
595 def close_footnote(self):
596 id = len(self.footnotes) + 1
Guido van Rossum06f42891995-08-28 03:01:00 +0000597 # self.footnotes.append(`id`, self.savetext)
598 self.footnotes.append(`id`, self.collectsavings())
599 # self.savetext = None
Guido van Rossum26a9d371995-03-15 11:26:05 +0000600
601 def writefootnotes(self):
602 self.write('<H2>---------- Footnotes ----------</H2>\n')
603 for id, text in self.footnotes:
604 self.write('<A NAME="footnotetext', id, \
605 '" HREF="#footnoteref', id, '">(', \
606 id, ')</A>\n', text, '<P>\n')
607 self.footnotes = []
608
609 def open_file(self): self.write('<FILE>')
610 def close_file(self): self.write('</FILE>')
611
612 def open_kbd(self): self.write('<KBD>')
613 def close_kbd(self): self.write('</KBD>')
614
615 def open_key(self): self.write('<KEY>')
616 def close_key(self): self.write('</KEY>')
617
618 def open_r(self): self.write('<R>')
619 def close_r(self): self.write('</R>')
620
621 def open_samp(self): self.write('`<SAMP>')
622 def close_samp(self): self.write('</SAMP>\'')
623
624 def open_sc(self): self.write('<SMALLCAPS>')
625 def close_sc(self): self.write('</SMALLCAPS>')
626
627 def open_strong(self): self.write('<B>')
628 def close_strong(self): self.write('</B>')
629
630 open_b = open_strong
631 close_b = close_strong
632
633 def open_var(self): self.write('<VAR>')
634 def close_var(self): self.write('</VAR>')
635
636 def open_w(self): self.write('<NOBREAK>')
637 def close_w(self): self.write('</NOBREAK>')
638
639 open_titlefont = open_
640 close_titlefont = close_
641
Guido van Rossuma12bbff1995-05-03 14:17:36 +0000642 def open_small(self): pass
643 def close_small(self): pass
644
Guido van Rossum26a9d371995-03-15 11:26:05 +0000645 def command(self, line):
646 a, b = cmprog.regs[1]
647 cmd = line[a:b]
648 args = string.strip(line[b:])
649 if self.debugging > 1:
650 print self.skip, self.stack, '@' + cmd, args
651 try:
652 func = getattr(self, 'do_' + cmd)
653 except AttributeError:
654 try:
655 func = getattr(self, 'bgn_' + cmd)
656 except AttributeError:
Guido van Rossum06f42891995-08-28 03:01:00 +0000657 # don't complain if we are skipping anyway
658 if not self.skip:
659 self.unknown_cmd(cmd, args)
Guido van Rossum26a9d371995-03-15 11:26:05 +0000660 return
661 self.stack.append(cmd)
662 func(args)
663 return
664 if not self.skip or cmd == 'end':
665 func(args)
666
667 def unknown_cmd(self, cmd, args):
668 print '*** unknown', '@' + cmd, args
669 if not self.unknown.has_key(cmd):
670 self.unknown[cmd] = 1
671 else:
672 self.unknown[cmd] = self.unknown[cmd] + 1
673
674 def do_end(self, args):
675 words = string.split(args)
676 if not words:
677 print '*** @end w/o args'
678 else:
679 cmd = words[0]
680 if not self.stack or self.stack[-1] <> cmd:
681 print '*** @end', cmd, 'unexpected'
682 else:
683 del self.stack[-1]
684 try:
685 func = getattr(self, 'end_' + cmd)
686 except AttributeError:
687 self.unknown_end(cmd)
688 return
689 func()
690
691 def unknown_end(self, cmd):
692 cmd = 'end ' + cmd
693 print '*** unknown', '@' + cmd
694 if not self.unknown.has_key(cmd):
695 self.unknown[cmd] = 1
696 else:
697 self.unknown[cmd] = self.unknown[cmd] + 1
698
699 # --- Comments ---
700
701 def do_comment(self, args): pass
702 do_c = do_comment
703
704 # --- Conditional processing ---
705
706 def bgn_ifinfo(self, args): pass
707 def end_ifinfo(self): pass
708
709 def bgn_iftex(self, args): self.skip = self.skip + 1
710 def end_iftex(self): self.skip = self.skip - 1
711
712 def bgn_ignore(self, args): self.skip = self.skip + 1
713 def end_ignore(self): self.skip = self.skip - 1
714
715 def bgn_tex(self, args): self.skip = self.skip + 1
716 def end_tex(self): self.skip = self.skip - 1
717
Guido van Rossum06f42891995-08-28 03:01:00 +0000718 def do_set(self, args):
719 fields = string.splitfields (args, ' ')
720 key = fields[0]
721 if len(fields) == 1:
722 value = 1
723 else:
724 value = string.joinfields (fields[1:], ' ')
725 self.values[key]=value
726 print self.values
Guido van Rossuma12bbff1995-05-03 14:17:36 +0000727
Guido van Rossum06f42891995-08-28 03:01:00 +0000728 def do_clear(self, args):
729 self.values[args] = None
Guido van Rossuma12bbff1995-05-03 14:17:36 +0000730
731 def bgn_ifset(self, args):
Guido van Rossum06f42891995-08-28 03:01:00 +0000732 if args not in self.values.keys() \
733 or self.values[args] is None:
Guido van Rossuma12bbff1995-05-03 14:17:36 +0000734 self.skip = self.skip + 1
735 self.stackinfo[len(self.stack)] = 1
736 else:
737 self.stackinfo[len(self.stack)] = 0
738 def end_ifset(self):
739 print self.stack
740 print self.stackinfo
741 if self.stackinfo[len(self.stack) + 1]:
742 self.skip = self.skip - 1
743 del self.stackinfo[len(self.stack) + 1]
744
745 def bgn_ifclear(self, args):
Guido van Rossum06f42891995-08-28 03:01:00 +0000746 if args in self.values.keys() \
747 and self.values[args] is not None:
Guido van Rossuma12bbff1995-05-03 14:17:36 +0000748 self.skip = self.skip + 1
749 self.stackinfo[len(self.stack)] = 1
750 else:
751 self.stackinfo[len(self.stack)] = 0
752
753 end_ifclear = end_ifset
Guido van Rossum06f42891995-08-28 03:01:00 +0000754
755 def open_value(self):
756 self.startsaving()
757
758 def close_value(self):
759 key = self.collectsavings ()
760 if key in self.values.keys():
761 self.write (self.values[key])
762 else:
763 print '*** Undefined value: ', key
764
Guido van Rossum26a9d371995-03-15 11:26:05 +0000765 # --- Beginning a file ---
766
767 do_finalout = do_comment
768 do_setchapternewpage = do_comment
769 do_setfilename = do_comment
770
771 def do_settitle(self, args):
Guido van Rossum06f42891995-08-28 03:01:00 +0000772 print args
773 self.startsaving()
774 self.expand (args)
775 self.title = self.collectsavings ()
776 print self.title
Guido van Rossuma12bbff1995-05-03 14:17:36 +0000777 def do_parskip(self, args): pass
778
Guido van Rossum26a9d371995-03-15 11:26:05 +0000779 # --- Ending a file ---
780
781 def do_bye(self, args):
Guido van Rossum06f42891995-08-28 03:01:00 +0000782 self.endnode ()
Guido van Rossum26a9d371995-03-15 11:26:05 +0000783 self.done = 1
784
785 # --- Title page ---
786
787 def bgn_titlepage(self, args): self.skip = self.skip + 1
788 def end_titlepage(self): self.skip = self.skip - 1
Guido van Rossum06f42891995-08-28 03:01:00 +0000789 def do_shorttitlepage(self, args): pass
790
Guido van Rossum26a9d371995-03-15 11:26:05 +0000791 def do_center(self, args):
792 # Actually not used outside title page...
Guido van Rossuma12bbff1995-05-03 14:17:36 +0000793 self.write('<H1>')
794 self.expand (args)
795 self.write ('</H1>\n')
Guido van Rossum26a9d371995-03-15 11:26:05 +0000796 do_title = do_center
797 do_subtitle = do_center
798 do_author = do_center
799
800 do_vskip = do_comment
801 do_vfill = do_comment
802 do_smallbook = do_comment
803
804 do_paragraphindent = do_comment
805 do_setchapternewpage = do_comment
806 do_headings = do_comment
807 do_footnotestyle = do_comment
808
809 do_evenheading = do_comment
810 do_evenfooting = do_comment
811 do_oddheading = do_comment
812 do_oddfooting = do_comment
813 do_everyheading = do_comment
814 do_everyfooting = do_comment
815
816 # --- Nodes ---
817
818 def do_node(self, args):
Guido van Rossuma12bbff1995-05-03 14:17:36 +0000819 self.endnode()
820 self.nodelineno = 0
Guido van Rossum26a9d371995-03-15 11:26:05 +0000821 parts = string.splitfields(args, ',')
822 while len(parts) < 4: parts.append('')
823 for i in range(4): parts[i] = string.strip(parts[i])
Guido van Rossuma12bbff1995-05-03 14:17:36 +0000824 self.nodelinks = parts
Guido van Rossum26a9d371995-03-15 11:26:05 +0000825 [name, next, prev, up] = parts[:4]
Guido van Rossum26a9d371995-03-15 11:26:05 +0000826 file = self.dirname + '/' + makefile(name)
Guido van Rossuma12bbff1995-05-03 14:17:36 +0000827 if self.filenames.has_key(file):
828 print '*** Filename already in use: ', file
829 else:
830 if self.debugging: print '--- writing', file
831 self.filenames[file] = 1
Guido van Rossum06f42891995-08-28 03:01:00 +0000832 # self.nodefp = open(file, 'w')
Guido van Rossum26a9d371995-03-15 11:26:05 +0000833 self.nodename = name
Guido van Rossum06f42891995-08-28 03:01:00 +0000834 if self.cont and self.nodestack:
835 self.nodestack[-1].cont = self.nodename
Guido van Rossum26a9d371995-03-15 11:26:05 +0000836 if not self.topname: self.topname = name
837 title = name
838 if self.title: title = title + ' -- ' + self.title
Guido van Rossuma12bbff1995-05-03 14:17:36 +0000839 # No idea what this means, but this is what latex2html writes
Guido van Rossum06f42891995-08-28 03:01:00 +0000840 # self.write('<!DOCTYPE HTML PUBLIC "-//W3O//DTD W3 HTML 2.0//EN">\n')
841 # self.write('<!- Converted with texi2html and Python>\n')
842 # self.write ('<P>\n<HEAD>\n')
843 # self.write('<TITLE>', title, '</TITLE>\n')
844 # self.write ('</HEAD>\n<BODY>\n<P>\n<BR> <HR>\n')
845 # self.link('Next', next)
846 # self.link('Prev', prev)
847 # self.link('Up', up)
848 # if self.nodename <> self.topname:
849 # self.link('Top', self.topname)
850 # self.write ('<BR> <HR> <P>\n')
851 self.node = Node (self.dirname, self.nodename, self.topname, \
852 title, next, prev, up)
853
Guido van Rossum26a9d371995-03-15 11:26:05 +0000854 def link(self, label, nodename):
855 if nodename:
856 if string.lower(nodename) == '(dir)':
857 addr = '../dir.html'
858 else:
859 addr = makefile(nodename)
860 self.write(label, ': <A HREF="', addr, '" TYPE="', \
861 label, '">', nodename, '</A> \n')
862
863 # --- Sectioning commands ---
864
Guido van Rossum06f42891995-08-28 03:01:00 +0000865 def popstack (self, type):
866 if (self.node):
867 self.node.type = type
868 while self.nodestack:
869 if self.nodestack[-1].type > type:
870 self.nodestack[-1].finalize ()
871 self.nodestack[-1].flush ()
872 del self.nodestack [-1]
873 elif self.nodestack[-1].type == type:
874 if not self.nodestack[-1].next:
875 self.nodestack[-1].next = self.node.name
876 if not self.node.prev:
877 self.node.prev = self.nodestack[-1].name
878 self.nodestack[-1].finalize ()
879 self.nodestack[-1].flush ()
880 del self.nodestack [-1]
881 else:
882 if type > 1 and not self.node.up:
883 self.node.up = self.nodestack[-1].name
884 break
885
Guido van Rossum26a9d371995-03-15 11:26:05 +0000886 def do_chapter(self, args):
887 self.heading('H1', args, 0)
Guido van Rossum06f42891995-08-28 03:01:00 +0000888 self.popstack (1)
889
Guido van Rossum26a9d371995-03-15 11:26:05 +0000890 def do_unnumbered(self, args):
891 self.heading('H1', args, -1)
Guido van Rossum06f42891995-08-28 03:01:00 +0000892 self.popstack (1)
Guido van Rossum26a9d371995-03-15 11:26:05 +0000893 def do_appendix(self, args):
894 self.heading('H1', args, -1)
Guido van Rossum06f42891995-08-28 03:01:00 +0000895 self.popstack (1)
Guido van Rossum26a9d371995-03-15 11:26:05 +0000896 def do_top(self, args):
897 self.heading('H1', args, -1)
898 def do_chapheading(self, args):
899 self.heading('H1', args, -1)
900 def do_majorheading(self, args):
901 self.heading('H1', args, -1)
902
903 def do_section(self, args):
904 self.heading('H1', args, 1)
Guido van Rossum06f42891995-08-28 03:01:00 +0000905 self.popstack (2)
906
Guido van Rossum26a9d371995-03-15 11:26:05 +0000907 def do_unnumberedsec(self, args):
908 self.heading('H1', args, -1)
Guido van Rossum06f42891995-08-28 03:01:00 +0000909 self.popstack (2)
Guido van Rossum26a9d371995-03-15 11:26:05 +0000910 def do_appendixsec(self, args):
911 self.heading('H1', args, -1)
Guido van Rossum06f42891995-08-28 03:01:00 +0000912 self.popstack (2)
Guido van Rossum26a9d371995-03-15 11:26:05 +0000913 do_appendixsection = do_appendixsec
914 def do_heading(self, args):
915 self.heading('H1', args, -1)
916
917 def do_subsection(self, args):
918 self.heading('H2', args, 2)
Guido van Rossum06f42891995-08-28 03:01:00 +0000919 self.popstack (3)
Guido van Rossum26a9d371995-03-15 11:26:05 +0000920 def do_unnumberedsubsec(self, args):
921 self.heading('H2', args, -1)
Guido van Rossum06f42891995-08-28 03:01:00 +0000922 self.popstack (3)
Guido van Rossum26a9d371995-03-15 11:26:05 +0000923 def do_appendixsubsec(self, args):
924 self.heading('H2', args, -1)
Guido van Rossum06f42891995-08-28 03:01:00 +0000925 self.popstack (3)
Guido van Rossum26a9d371995-03-15 11:26:05 +0000926 def do_subheading(self, args):
927 self.heading('H2', args, -1)
928
929 def do_subsubsection(self, args):
930 self.heading('H3', args, 3)
Guido van Rossum06f42891995-08-28 03:01:00 +0000931 self.popstack (4)
Guido van Rossum26a9d371995-03-15 11:26:05 +0000932 def do_unnumberedsubsubsec(self, args):
933 self.heading('H3', args, -1)
Guido van Rossum06f42891995-08-28 03:01:00 +0000934 self.popstack (4)
Guido van Rossum26a9d371995-03-15 11:26:05 +0000935 def do_appendixsubsubsec(self, args):
936 self.heading('H3', args, -1)
Guido van Rossum06f42891995-08-28 03:01:00 +0000937 self.popstack (4)
Guido van Rossum26a9d371995-03-15 11:26:05 +0000938 def do_subsubheading(self, args):
939 self.heading('H3', args, -1)
940
941 def heading(self, type, args, level):
942 if level >= 0:
943 while len(self.numbering) <= level:
944 self.numbering.append(0)
945 del self.numbering[level+1:]
946 self.numbering[level] = self.numbering[level] + 1
947 x = ''
948 for i in self.numbering:
949 x = x + `i` + '.'
950 args = x + ' ' + args
951 self.contents.append(level, args, self.nodename)
952 self.write('<', type, '>')
953 self.expand(args)
954 self.write('</', type, '>\n')
955 if self.debugging:
956 print '---', args
957
958 def do_contents(self, args):
Guido van Rossum06f42891995-08-28 03:01:00 +0000959 # pass
960 self.listcontents('Table of Contents', 999)
Guido van Rossum26a9d371995-03-15 11:26:05 +0000961
962 def do_shortcontents(self, args):
963 pass
964 # self.listcontents('Short Contents', 0)
965 do_summarycontents = do_shortcontents
966
967 def listcontents(self, title, maxlevel):
968 self.write('<H1>', title, '</H1>\n<UL COMPACT>\n')
969 for level, title, node in self.contents:
970 if level <= maxlevel:
971 self.write('<LI>', '. '*level, '<A HREF="', \
972 makefile(node), '">')
973 self.expand(title)
974 self.write('</A> ', node, '\n')
975 self.write('</UL>\n')
976
977 # --- Page lay-out ---
978
979 # These commands are only meaningful in printed text
980
981 def do_page(self, args): pass
982
983 def do_need(self, args): pass
984
985 def bgn_group(self, args): pass
986 def end_group(self): pass
987
988 # --- Line lay-out ---
989
990 def do_sp(self, args):
991 # Insert <args> blank lines
992 if args:
993 try:
994 n = string.atoi(args)
995 except string.atoi_error:
996 n = 1
997 else:
998 n = 1
999 self.write('<P>\n'*max(n, 0))
1000
Guido van Rossuma12bbff1995-05-03 14:17:36 +00001001 def do_hline(self, args):
1002 self.write ('<HR>')
1003
Guido van Rossum26a9d371995-03-15 11:26:05 +00001004 # --- Function and variable definitions ---
1005
1006 def bgn_deffn(self, args):
Guido van Rossum06f42891995-08-28 03:01:00 +00001007 self.write('<DL>')
1008 self.do_deffnx (args)
Guido van Rossum26a9d371995-03-15 11:26:05 +00001009
1010 def end_deffn(self):
1011 self.write('</DL>\n')
1012
Guido van Rossuma12bbff1995-05-03 14:17:36 +00001013 def do_deffnx(self, args):
1014 self.write('<DT>')
1015 words = splitwords(args, 2)
1016 [category, name], rest = words[:2], words[2:]
1017 self.expand('@b{' + name + '}')
1018 for word in rest: self.expand(' ' + makevar(word))
1019 self.expand(' -- ' + category)
1020 self.write('<DD>\n')
1021 self.index('fn', name)
1022
Guido van Rossum26a9d371995-03-15 11:26:05 +00001023 def bgn_defun(self, args): self.bgn_deffn('Function ' + args)
1024 end_defun = end_deffn
Guido van Rossum06f42891995-08-28 03:01:00 +00001025 def do_defunx(self, args): self.do_deffnx('Function ' + args)
Guido van Rossum26a9d371995-03-15 11:26:05 +00001026
1027 def bgn_defmac(self, args): self.bgn_deffn('Macro ' + args)
1028 end_defmac = end_deffn
Guido van Rossum06f42891995-08-28 03:01:00 +00001029 def do_defmacx(self, args): self.do_deffnx('Macro ' + args)
Guido van Rossum26a9d371995-03-15 11:26:05 +00001030
1031 def bgn_defspec(self, args): self.bgn_deffn('{Special Form} ' + args)
1032 end_defspec = end_deffn
Guido van Rossum06f42891995-08-28 03:01:00 +00001033 def do_defspecx(self, args): self.do_deffnx('{Special Form} ' + args)
Guido van Rossum26a9d371995-03-15 11:26:05 +00001034
1035 def bgn_defvr(self, args):
Guido van Rossum06f42891995-08-28 03:01:00 +00001036 self.write('<DL>')
1037 self.do_defvrx (args)
1038
1039 end_defvr = end_deffn
1040
1041 def do_defvrx(self, args):
1042 self.write('<DT>')
Guido van Rossum26a9d371995-03-15 11:26:05 +00001043 words = splitwords(args, 2)
1044 [category, name], rest = words[:2], words[2:]
1045 self.expand('@code{' + name + '}')
1046 # If there are too many arguments, show them
1047 for word in rest: self.expand(' ' + word)
1048 self.expand(' -- ' + category)
1049 self.write('<DD>\n')
1050 self.index('vr', name)
1051
Guido van Rossum26a9d371995-03-15 11:26:05 +00001052 def bgn_defvar(self, args): self.bgn_defvr('Variable ' + args)
1053 end_defvar = end_defvr
Guido van Rossum06f42891995-08-28 03:01:00 +00001054 def do_defvarx(self, args): self.do_defvrx('Variable ' + args)
Guido van Rossum26a9d371995-03-15 11:26:05 +00001055
1056 def bgn_defopt(self, args): self.bgn_defvr('{User Option} ' + args)
1057 end_defopt = end_defvr
Guido van Rossum06f42891995-08-28 03:01:00 +00001058 def do_defoptx(self, args): self.do_defvrx('{User Option} ' + args)
Guido van Rossum26a9d371995-03-15 11:26:05 +00001059
1060 # --- Ditto for typed languages ---
1061
1062 def bgn_deftypefn(self, args):
Guido van Rossum06f42891995-08-28 03:01:00 +00001063 self.write('<DL>')
1064 self.do_deftypefnx (args)
1065
1066 end_deftypefn = end_deffn
1067
1068 def do_deftypefnx(self, args):
1069 self.write('<DT>')
Guido van Rossum26a9d371995-03-15 11:26:05 +00001070 words = splitwords(args, 3)
1071 [category, datatype, name], rest = words[:3], words[3:]
1072 self.expand('@code{' + datatype + '} @b{' + name + '}')
1073 for word in rest: self.expand(' ' + makevar(word))
1074 self.expand(' -- ' + category)
1075 self.write('<DD>\n')
1076 self.index('fn', name)
1077
Guido van Rossum26a9d371995-03-15 11:26:05 +00001078
1079 def bgn_deftypefun(self, args): self.bgn_deftypefn('Function ' + args)
1080 end_deftypefun = end_deftypefn
Guido van Rossum06f42891995-08-28 03:01:00 +00001081 def do_deftypefunx(self, args): self.do_deftypefnx('Function ' + args)
Guido van Rossum26a9d371995-03-15 11:26:05 +00001082
1083 def bgn_deftypevr(self, args):
Guido van Rossum06f42891995-08-28 03:01:00 +00001084 self.write('<DL>')
1085 self.do_deftypevrx (args)
1086
1087 end_deftypevr = end_deftypefn
1088
1089 def do_deftypevrx(self, args):
1090 self.write('<DT>')
Guido van Rossum26a9d371995-03-15 11:26:05 +00001091 words = splitwords(args, 3)
1092 [category, datatype, name], rest = words[:3], words[3:]
Guido van Rossum26a9d371995-03-15 11:26:05 +00001093 self.expand('@code{' + datatype + '} @b{' + name + '}')
1094 # If there are too many arguments, show them
1095 for word in rest: self.expand(' ' + word)
1096 self.expand(' -- ' + category)
1097 self.write('<DD>\n')
1098 self.index('fn', name)
1099
Guido van Rossum26a9d371995-03-15 11:26:05 +00001100 def bgn_deftypevar(self, args):
1101 self.bgn_deftypevr('Variable ' + args)
1102 end_deftypevar = end_deftypevr
Guido van Rossum06f42891995-08-28 03:01:00 +00001103 def do_deftypevarx(self, args):
1104 self.do_deftypevrx('Variable ' + args)
Guido van Rossum26a9d371995-03-15 11:26:05 +00001105
1106 # --- Ditto for object-oriented languages ---
1107
1108 def bgn_defcv(self, args):
Guido van Rossum06f42891995-08-28 03:01:00 +00001109 self.write('<DL>')
1110 self.do_defcvx(args)
1111
1112 end_defcv = end_deftypevr
1113
1114 def do_defcvx(self, args):
1115 self.write('<DT>')
Guido van Rossum26a9d371995-03-15 11:26:05 +00001116 words = splitwords(args, 3)
1117 [category, classname, name], rest = words[:3], words[3:]
Guido van Rossum26a9d371995-03-15 11:26:05 +00001118 self.expand('@b{' + name + '}')
1119 # If there are too many arguments, show them
1120 for word in rest: self.expand(' ' + word)
1121 self.expand(' -- ' + category + ' of ' + classname)
1122 self.write('<DD>\n')
1123 self.index('vr', name + ' @r{of ' + classname + '}')
1124
Guido van Rossum26a9d371995-03-15 11:26:05 +00001125 def bgn_defivar(self, args):
1126 self.bgn_defcv('{Instance Variable} ' + args)
1127 end_defivar = end_defcv
Guido van Rossum06f42891995-08-28 03:01:00 +00001128 def do_defivarx(self, args):
1129 self.do_defcvx('{Instance Variable} ' + args)
Guido van Rossum26a9d371995-03-15 11:26:05 +00001130
1131 def bgn_defop(self, args):
Guido van Rossum06f42891995-08-28 03:01:00 +00001132 self.write('<DL>')
1133 self.do_defopx (args)
1134
1135 end_defop = end_defcv
1136
1137 def do_defopx(self, args):
1138 self.write('<DT>')
Guido van Rossum26a9d371995-03-15 11:26:05 +00001139 words = splitwords(args, 3)
1140 [category, classname, name], rest = words[:3], words[3:]
1141 self.expand('@b{' + name + '}')
1142 for word in rest: self.expand(' ' + makevar(word))
1143 self.expand(' -- ' + category + ' on ' + classname)
1144 self.write('<DD>\n')
1145 self.index('fn', name + ' @r{on ' + classname + '}')
1146
Guido van Rossum26a9d371995-03-15 11:26:05 +00001147 def bgn_defmethod(self, args):
1148 self.bgn_defop('Method ' + args)
1149 end_defmethod = end_defop
Guido van Rossum06f42891995-08-28 03:01:00 +00001150 def do_defmethodx(self, args):
1151 self.do_defopx('Method ' + args)
Guido van Rossum26a9d371995-03-15 11:26:05 +00001152
1153 # --- Ditto for data types ---
1154
1155 def bgn_deftp(self, args):
Guido van Rossum06f42891995-08-28 03:01:00 +00001156 self.write('<DL>')
1157 self.do_deftpx(args)
1158
1159 end_deftp = end_defcv
1160
1161 def do_deftpx(self, args):
1162 self.write('<DT>')
Guido van Rossum26a9d371995-03-15 11:26:05 +00001163 words = splitwords(args, 2)
1164 [category, name], rest = words[:2], words[2:]
1165 self.expand('@b{' + name + '}')
1166 for word in rest: self.expand(' ' + word)
1167 self.expand(' -- ' + category)
1168 self.write('<DD>\n')
1169 self.index('tp', name)
1170
Guido van Rossum26a9d371995-03-15 11:26:05 +00001171 # --- Making Lists and Tables
1172
1173 def bgn_enumerate(self, args):
Guido van Rossuma12bbff1995-05-03 14:17:36 +00001174 if not args:
1175 self.write('<OL>\n')
1176 self.stackinfo[len(self.stack)] = '</OL>\n'
1177 else:
1178 self.itemnumber = args
1179 self.write('<UL>\n')
1180 self.stackinfo[len(self.stack)] = '</UL>\n'
Guido van Rossum26a9d371995-03-15 11:26:05 +00001181 def end_enumerate(self):
1182 self.itemnumber = None
Guido van Rossuma12bbff1995-05-03 14:17:36 +00001183 self.write(self.stackinfo[len(self.stack) + 1])
1184 del self.stackinfo[len(self.stack) + 1]
Guido van Rossum26a9d371995-03-15 11:26:05 +00001185
1186 def bgn_itemize(self, args):
1187 self.itemarg = args
1188 self.write('<UL>\n')
1189 def end_itemize(self):
1190 self.itemarg = None
1191 self.write('</UL>\n')
1192
1193 def bgn_table(self, args):
1194 self.itemarg = args
1195 self.write('<DL>\n')
1196 def end_table(self):
1197 self.itemarg = None
1198 self.write('</DL>\n')
1199
1200 def bgn_ftable(self, args):
1201 self.itemindex = 'fn'
1202 self.bgn_table(args)
1203 def end_ftable(self):
1204 self.itemindex = None
1205 self.end_table()
1206
1207 def do_item(self, args):
1208 if self.itemindex: self.index(self.itemindex, args)
1209 if self.itemarg:
1210 if self.itemarg[0] == '@' and self.itemarg[1:2] and \
1211 self.itemarg[1] in string.letters:
1212 args = self.itemarg + '{' + args + '}'
1213 else:
1214 # some other character, e.g. '-'
1215 args = self.itemarg + ' ' + args
1216 if self.itemnumber <> None:
1217 args = self.itemnumber + '. ' + args
1218 self.itemnumber = increment(self.itemnumber)
1219 if self.stack and self.stack[-1] == 'table':
1220 self.write('<DT>')
1221 self.expand(args)
1222 self.write('<DD>')
1223 else:
1224 self.write('<LI>')
1225 self.expand(args)
1226 self.write(' ')
1227 do_itemx = do_item # XXX Should suppress leading blank line
1228
1229 # --- Enumerations, displays, quotations ---
1230 # XXX Most of these should increase the indentation somehow
1231
1232 def bgn_quotation(self, args): self.write('<P>')
1233 def end_quotation(self): self.write('<P>\n')
1234
1235 def bgn_example(self, args):
1236 self.nofill = self.nofill + 1
Guido van Rossuma12bbff1995-05-03 14:17:36 +00001237 self.write('<PRE><CODE>')
Guido van Rossum26a9d371995-03-15 11:26:05 +00001238 def end_example(self):
Guido van Rossuma12bbff1995-05-03 14:17:36 +00001239 self.write('</CODE></PRE>')
Guido van Rossum26a9d371995-03-15 11:26:05 +00001240 self.nofill = self.nofill - 1
1241
1242 bgn_lisp = bgn_example # Synonym when contents are executable lisp code
1243 end_lisp = end_example
1244
1245 bgn_smallexample = bgn_example # XXX Should use smaller font
1246 end_smallexample = end_example
1247
1248 bgn_smalllisp = bgn_lisp # Ditto
1249 end_smalllisp = end_lisp
1250
1251 def bgn_display(self, args):
1252 self.nofill = self.nofill + 1
Guido van Rossuma12bbff1995-05-03 14:17:36 +00001253 self.write('<PRE>\n')
Guido van Rossum26a9d371995-03-15 11:26:05 +00001254 def end_display(self):
Guido van Rossuma12bbff1995-05-03 14:17:36 +00001255 self.write('</PRE>\n')
Guido van Rossum26a9d371995-03-15 11:26:05 +00001256 self.nofill = self.nofill - 1
1257
1258 def bgn_format(self, args):
1259 self.nofill = self.nofill + 1
Guido van Rossuma12bbff1995-05-03 14:17:36 +00001260 self.write('<PRE><CODE>\n')
Guido van Rossum26a9d371995-03-15 11:26:05 +00001261 def end_format(self):
Guido van Rossuma12bbff1995-05-03 14:17:36 +00001262 self.write('</CODE></PRE>\n')
Guido van Rossum26a9d371995-03-15 11:26:05 +00001263 self.nofill = self.nofill - 1
1264
1265 def do_exdent(self, args): self.expand(args + '\n')
1266 # XXX Should really mess with indentation
1267
1268 def bgn_flushleft(self, args):
1269 self.nofill = self.nofill + 1
Guido van Rossuma12bbff1995-05-03 14:17:36 +00001270 self.write('<PRE>\n')
Guido van Rossum26a9d371995-03-15 11:26:05 +00001271 def end_flushleft(self):
Guido van Rossuma12bbff1995-05-03 14:17:36 +00001272 self.write('</PRE>\n')
Guido van Rossum26a9d371995-03-15 11:26:05 +00001273 self.nofill = self.nofill - 1
1274
1275 def bgn_flushright(self, args):
1276 self.nofill = self.nofill + 1
1277 self.write('<ADDRESS COMPACT>\n')
1278 def end_flushright(self):
1279 self.write('</ADDRESS>\n')
1280 self.nofill = self.nofill - 1
1281
1282 def bgn_menu(self, args): self.write('<H2>Menu</H2><DL COMPACT>\n')
1283 def end_menu(self): self.write('</DL>\n')
1284
1285 def bgn_cartouche(self, args): pass
1286 def end_cartouche(self): pass
1287
1288 # --- Indices ---
1289
1290 def resetindex(self):
1291 self.noncodeindices = ['cp']
1292 self.indextitle = {}
1293 self.indextitle['cp'] = 'Concept'
1294 self.indextitle['fn'] = 'Function'
1295 self.indextitle['ky'] = 'Keyword'
1296 self.indextitle['pg'] = 'Program'
1297 self.indextitle['tp'] = 'Type'
1298 self.indextitle['vr'] = 'Variable'
1299 #
1300 self.whichindex = {}
1301 for name in self.indextitle.keys():
1302 self.whichindex[name] = []
1303
1304 def user_index(self, name, args):
1305 if self.whichindex.has_key(name):
1306 self.index(name, args)
1307 else:
1308 print '*** No index named', `name`
1309
1310 def do_cindex(self, args): self.index('cp', args)
1311 def do_findex(self, args): self.index('fn', args)
1312 def do_kindex(self, args): self.index('ky', args)
1313 def do_pindex(self, args): self.index('pg', args)
1314 def do_tindex(self, args): self.index('tp', args)
1315 def do_vindex(self, args): self.index('vr', args)
1316
1317 def index(self, name, args):
1318 self.whichindex[name].append(args, self.nodename)
1319
1320 def do_synindex(self, args):
1321 words = string.split(args)
1322 if len(words) <> 2:
1323 print '*** bad @synindex', args
1324 return
1325 [old, new] = words
1326 if not self.whichindex.has_key(old) or \
1327 not self.whichindex.has_key(new):
1328 print '*** bad key(s) in @synindex', args
1329 return
1330 if old <> new and \
1331 self.whichindex[old] is not self.whichindex[new]:
1332 inew = self.whichindex[new]
1333 inew[len(inew):] = self.whichindex[old]
1334 self.whichindex[old] = inew
1335 do_syncodeindex = do_synindex # XXX Should use code font
1336
1337 def do_printindex(self, args):
1338 words = string.split(args)
1339 for name in words:
1340 if self.whichindex.has_key(name):
1341 self.prindex(name)
1342 else:
1343 print '*** No index named', `name`
1344
1345 def prindex(self, name):
1346 iscodeindex = (name not in self.noncodeindices)
1347 index = self.whichindex[name]
1348 if not index: return
1349 if self.debugging:
1350 print '--- Generating', self.indextitle[name], 'index'
1351 # The node already provides a title
1352 index1 = []
1353 junkprog = regex.compile('^\(@[a-z]+\)?{')
1354 for key, node in index:
1355 sortkey = string.lower(key)
1356 # Remove leading `@cmd{' from sort key
1357 # -- don't bother about the matching `}'
1358 oldsortkey = sortkey
1359 while 1:
1360 i = junkprog.match(sortkey)
1361 if i < 0: break
1362 sortkey = sortkey[i:]
1363 index1.append(sortkey, key, node)
1364 del index[:]
1365 index1.sort()
1366 self.write('<DL COMPACT>\n')
1367 for sortkey, key, node in index1:
1368 if self.debugging > 1: print key, ':', node
1369 self.write('<DT>')
1370 if iscodeindex: key = '@code{' + key + '}'
1371 self.expand(key)
1372 self.write('<DD><A HREF="', makefile(node), \
1373 '">', node, '</A>\n')
1374 self.write('</DL>\n')
1375
1376 # --- Final error reports ---
1377
1378 def report(self):
1379 if self.unknown:
1380 print '--- Unrecognized commands ---'
1381 cmds = self.unknown.keys()
1382 cmds.sort()
1383 for cmd in cmds:
1384 print string.ljust(cmd, 20), self.unknown[cmd]
1385
1386
1387# Put @var{} around alphabetic substrings
1388def makevar(str):
Guido van Rossuma12bbff1995-05-03 14:17:36 +00001389 return '@var{'+str+'}'
Guido van Rossum26a9d371995-03-15 11:26:05 +00001390
1391
1392# Split a string in "words" according to findwordend
1393def splitwords(str, minlength):
1394 words = []
1395 i = 0
1396 n = len(str)
1397 while i < n:
1398 while i < n and str[i] in ' \t\n': i = i+1
1399 if i >= n: break
1400 start = i
1401 i = findwordend(str, i, n)
1402 words.append(str[start:i])
1403 while len(words) < minlength: words.append('')
1404 return words
1405
1406
1407# Find the end of a "word", matching braces and interpreting @@ @{ @}
1408fwprog = regex.compile('[@{} ]')
1409def findwordend(str, i, n):
1410 level = 0
1411 while i < n:
1412 i = fwprog.search(str, i)
1413 if i < 0: break
1414 c = str[i]; i = i+1
1415 if c == '@': i = i+1 # Next character is not special
1416 elif c == '{': level = level+1
1417 elif c == '}': level = level-1
1418 elif c == ' ' and level <= 0: return i-1
1419 return n
1420
1421
1422# Convert a node name into a file name
1423def makefile(nodename):
Guido van Rossuma12bbff1995-05-03 14:17:36 +00001424 return fixfunnychars(nodename) + '.html'
Guido van Rossum26a9d371995-03-15 11:26:05 +00001425
1426
1427# Characters that are perfectly safe in filenames and hyperlinks
Guido van Rossum06f42891995-08-28 03:01:00 +00001428goodchars = string.letters + string.digits + '!@-=+.'
Guido van Rossum26a9d371995-03-15 11:26:05 +00001429
Guido van Rossum06f42891995-08-28 03:01:00 +00001430# Replace characters that aren't perfectly safe by dashes
1431# Underscores are bad since Cern HTTPD treats them as delimiters for
1432# encoding times, so you get mismatches if you compress your files:
1433# a.html.gz will map to a_b.html.gz
Guido van Rossum26a9d371995-03-15 11:26:05 +00001434def fixfunnychars(addr):
1435 i = 0
1436 while i < len(addr):
1437 c = addr[i]
1438 if c not in goodchars:
Guido van Rossum06f42891995-08-28 03:01:00 +00001439 c = '-'
Guido van Rossum26a9d371995-03-15 11:26:05 +00001440 addr = addr[:i] + c + addr[i+1:]
1441 i = i + len(c)
1442 return addr
1443
1444
1445# Increment a string used as an enumeration
1446def increment(s):
1447 if not s:
1448 return '1'
1449 for sequence in string.digits, string.lowercase, string.uppercase:
1450 lastc = s[-1]
1451 if lastc in sequence:
1452 i = string.index(sequence, lastc) + 1
1453 if i >= len(sequence):
1454 if len(s) == 1:
1455 s = sequence[0]*2
1456 if s == '00':
1457 s = '10'
1458 else:
1459 s = increment(s[:-1]) + sequence[0]
1460 else:
1461 s = s[:-1] + sequence[i]
1462 return s
1463 return s # Don't increment
1464
1465
1466def test():
1467 import sys
1468 parser = TexinfoParser()
1469 while sys.argv[1:2] == ['-d']:
1470 parser.debugging = parser.debugging + 1
1471 del sys.argv[1:2]
Guido van Rossum06f42891995-08-28 03:01:00 +00001472 if sys.argv[1] == '-c':
1473 parser.cont = 1
1474 del sys.argv[1]
Guido van Rossum26a9d371995-03-15 11:26:05 +00001475 if len(sys.argv) <> 3:
Guido van Rossum06f42891995-08-28 03:01:00 +00001476 print 'usage: texi2html [-d] [-d] [-c] inputfile outputdirectory'
Guido van Rossum26a9d371995-03-15 11:26:05 +00001477 sys.exit(2)
1478 file = sys.argv[1]
1479 parser.setdirname(sys.argv[2])
1480 if file == '-':
1481 fp = sys.stdin
1482 else:
1483 parser.setincludedir(os.path.dirname(file))
1484 try:
1485 fp = open(file, 'r')
1486 except IOError, msg:
1487 print file, ':', msg
1488 sys.exit(1)
1489 parser.parse(fp)
1490 fp.close()
1491 parser.report()
1492
1493
1494test()
Guido van Rossum06f42891995-08-28 03:01:00 +00001495
1496# Emacs local variables
1497#
1498# Local Variables:
1499# py-indent-offset: 8
1500# End: