You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2078 lines
68 KiB

28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
28 years ago
  1. #! /usr/bin/env python
  2. # Convert GNU texinfo files into HTML, one file per node.
  3. # Based on Texinfo 2.14.
  4. # Usage: texi2html [-d] [-d] [-c] inputfile outputdirectory
  5. # The input file must be a complete texinfo file, e.g. emacs.texi.
  6. # This creates many files (one per info node) in the output directory,
  7. # overwriting existing files of the same name. All files created have
  8. # ".html" as their extension.
  9. # XXX To do:
  10. # - handle @comment*** correctly
  11. # - handle @xref {some words} correctly
  12. # - handle @ftable correctly (items aren't indexed?)
  13. # - handle @itemx properly
  14. # - handle @exdent properly
  15. # - add links directly to the proper line from indices
  16. # - check against the definitive list of @-cmds; we still miss (among others):
  17. # - @defindex (hard)
  18. # - @c(omment) in the middle of a line (rarely used)
  19. # - @this* (not really needed, only used in headers anyway)
  20. # - @today{} (ever used outside title page?)
  21. # More consistent handling of chapters/sections/etc.
  22. # Lots of documentation
  23. # Many more options:
  24. # -top designate top node
  25. # -links customize which types of links are included
  26. # -split split at chapters or sections instead of nodes
  27. # -name Allow different types of filename handling. Non unix systems
  28. # will have problems with long node names
  29. # ...
  30. # Support the most recent texinfo version and take a good look at HTML 3.0
  31. # More debugging output (customizable) and more flexible error handling
  32. # How about icons ?
  33. # rpyron 2002-05-07
  34. # Robert Pyron <rpyron@alum.mit.edu>
  35. # 1. BUGFIX: In function makefile(), strip blanks from the nodename.
  36. # This is necessary to match the behavior of parser.makeref() and
  37. # parser.do_node().
  38. # 2. BUGFIX fixed KeyError in end_ifset (well, I may have just made
  39. # it go away, rather than fix it)
  40. # 3. BUGFIX allow @menu and menu items inside @ifset or @ifclear
  41. # 4. Support added for:
  42. # @uref URL reference
  43. # @image image file reference (see note below)
  44. # @multitable output an HTML table
  45. # @vtable
  46. # 5. Partial support for accents, to match MAKEINFO output
  47. # 6. I added a new command-line option, '-H basename', to specify
  48. # HTML Help output. This will cause three files to be created
  49. # in the current directory:
  50. # `basename`.hhp HTML Help Workshop project file
  51. # `basename`.hhc Contents file for the project
  52. # `basename`.hhk Index file for the project
  53. # When fed into HTML Help Workshop, the resulting file will be
  54. # named `basename`.chm.
  55. # 7. A new class, HTMLHelp, to accomplish item 6.
  56. # 8. Various calls to HTMLHelp functions.
  57. # A NOTE ON IMAGES: Just as 'outputdirectory' must exist before
  58. # running this program, all referenced images must already exist
  59. # in outputdirectory.
  60. import os
  61. import sys
  62. import string
  63. import re
  64. MAGIC = '\\input texinfo'
  65. cmprog = re.compile('^@([a-z]+)([ \t]|$)') # Command (line-oriented)
  66. blprog = re.compile('^[ \t]*$') # Blank line
  67. kwprog = re.compile('@[a-z]+') # Keyword (embedded, usually
  68. # with {} args)
  69. spprog = re.compile('[\n@{}&<>]') # Special characters in
  70. # running text
  71. #
  72. # menu item (Yuck!)
  73. miprog = re.compile('^\* ([^:]*):(:|[ \t]*([^\t,\n.]+)([^ \t\n]*))[ \t\n]*')
  74. # 0 1 1 2 3 34 42 0
  75. # ----- ---------- ---------
  76. # -|-----------------------------
  77. # -----------------------------------------------------
  78. class HTMLNode:
  79. """Some of the parser's functionality is separated into this class.
  80. A Node accumulates its contents, takes care of links to other Nodes
  81. and saves itself when it is finished and all links are resolved.
  82. """
  83. DOCTYPE = '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">'
  84. type = 0
  85. cont = ''
  86. epilogue = '</BODY></HTML>\n'
  87. def __init__(self, dir, name, topname, title, next, prev, up):
  88. self.dirname = dir
  89. self.name = name
  90. if topname:
  91. self.topname = topname
  92. else:
  93. self.topname = name
  94. self.title = title
  95. self.next = next
  96. self.prev = prev
  97. self.up = up
  98. self.lines = []
  99. def write(self, *lines):
  100. map(self.lines.append, lines)
  101. def flush(self):
  102. fp = open(self.dirname + '/' + makefile(self.name), 'w')
  103. fp.write(self.prologue)
  104. fp.write(self.text)
  105. fp.write(self.epilogue)
  106. fp.close()
  107. def link(self, label, nodename, rel=None, rev=None):
  108. if nodename:
  109. if nodename.lower() == '(dir)':
  110. addr = '../dir.html'
  111. title = ''
  112. else:
  113. addr = makefile(nodename)
  114. title = ' TITLE="%s"' % nodename
  115. self.write(label, ': <A HREF="', addr, '"', \
  116. rel and (' REL=' + rel) or "", \
  117. rev and (' REV=' + rev) or "", \
  118. title, '>', nodename, '</A> \n')
  119. def finalize(self):
  120. length = len(self.lines)
  121. self.text = ''.join(self.lines)
  122. self.lines = []
  123. self.open_links()
  124. self.output_links()
  125. self.close_links()
  126. links = ''.join(self.lines)
  127. self.lines = []
  128. self.prologue = (
  129. self.DOCTYPE +
  130. '\n<HTML><HEAD>\n'
  131. ' <!-- Converted with texi2html and Python -->\n'
  132. ' <TITLE>' + self.title + '</TITLE>\n'
  133. ' <LINK REL=Next HREF="'
  134. + makefile(self.next) + '" TITLE="' + self.next + '">\n'
  135. ' <LINK REL=Previous HREF="'
  136. + makefile(self.prev) + '" TITLE="' + self.prev + '">\n'
  137. ' <LINK REL=Up HREF="'
  138. + makefile(self.up) + '" TITLE="' + self.up + '">\n'
  139. '</HEAD><BODY>\n' +
  140. links)
  141. if length > 20:
  142. self.epilogue = '<P>\n%s</BODY></HTML>\n' % links
  143. def open_links(self):
  144. self.write('<HR>\n')
  145. def close_links(self):
  146. self.write('<HR>\n')
  147. def output_links(self):
  148. if self.cont != self.next:
  149. self.link(' Cont', self.cont)
  150. self.link(' Next', self.next, rel='Next')
  151. self.link(' Prev', self.prev, rel='Previous')
  152. self.link(' Up', self.up, rel='Up')
  153. if self.name <> self.topname:
  154. self.link(' Top', self.topname)
  155. class HTML3Node(HTMLNode):
  156. DOCTYPE = '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML Level 3//EN//3.0">'
  157. def open_links(self):
  158. self.write('<DIV CLASS=Navigation>\n <HR>\n')
  159. def close_links(self):
  160. self.write(' <HR>\n</DIV>\n')
  161. class TexinfoParser:
  162. COPYRIGHT_SYMBOL = "&copy;"
  163. FN_ID_PATTERN = "(%(id)s)"
  164. FN_SOURCE_PATTERN = '<A NAME=footnoteref%(id)s' \
  165. ' HREF="#footnotetext%(id)s">' \
  166. + FN_ID_PATTERN + '</A>'
  167. FN_TARGET_PATTERN = '<A NAME=footnotetext%(id)s' \
  168. ' HREF="#footnoteref%(id)s">' \
  169. + FN_ID_PATTERN + '</A>\n%(text)s<P>\n'
  170. FN_HEADER = '\n<P>\n<HR NOSHADE SIZE=1 WIDTH=200>\n' \
  171. '<STRONG><EM>Footnotes</EM></STRONG>\n<P>'
  172. Node = HTMLNode
  173. # Initialize an instance
  174. def __init__(self):
  175. self.unknown = {} # statistics about unknown @-commands
  176. self.filenames = {} # Check for identical filenames
  177. self.debugging = 0 # larger values produce more output
  178. self.print_headers = 0 # always print headers?
  179. self.nodefp = None # open file we're writing to
  180. self.nodelineno = 0 # Linenumber relative to node
  181. self.links = None # Links from current node
  182. self.savetext = None # If not None, save text head instead
  183. self.savestack = [] # If not None, save text head instead
  184. self.htmlhelp = None # html help data
  185. self.dirname = 'tmp' # directory where files are created
  186. self.includedir = '.' # directory to search @include files
  187. self.nodename = '' # name of current node
  188. self.topname = '' # name of top node (first node seen)
  189. self.title = '' # title of this whole Texinfo tree
  190. self.resetindex() # Reset all indices
  191. self.contents = [] # Reset table of contents
  192. self.numbering = [] # Reset section numbering counters
  193. self.nofill = 0 # Normal operation: fill paragraphs
  194. self.values={'html': 1} # Names that should be parsed in ifset
  195. self.stackinfo={} # Keep track of state in the stack
  196. # XXX The following should be reset per node?!
  197. self.footnotes = [] # Reset list of footnotes
  198. self.itemarg = None # Reset command used by @item
  199. self.itemnumber = None # Reset number for @item in @enumerate
  200. self.itemindex = None # Reset item index name
  201. self.node = None
  202. self.nodestack = []
  203. self.cont = 0
  204. self.includedepth = 0
  205. # Set htmlhelp helper class
  206. def sethtmlhelp(self, htmlhelp):
  207. self.htmlhelp = htmlhelp
  208. # Set (output) directory name
  209. def setdirname(self, dirname):
  210. self.dirname = dirname
  211. # Set include directory name
  212. def setincludedir(self, includedir):
  213. self.includedir = includedir
  214. # Parse the contents of an entire file
  215. def parse(self, fp):
  216. line = fp.readline()
  217. lineno = 1
  218. while line and (line[0] == '%' or blprog.match(line)):
  219. line = fp.readline()
  220. lineno = lineno + 1
  221. if line[:len(MAGIC)] <> MAGIC:
  222. raise SyntaxError, 'file does not begin with %r' % (MAGIC,)
  223. self.parserest(fp, lineno)
  224. # Parse the contents of a file, not expecting a MAGIC header
  225. def parserest(self, fp, initial_lineno):
  226. lineno = initial_lineno
  227. self.done = 0
  228. self.skip = 0
  229. self.stack = []
  230. accu = []
  231. while not self.done:
  232. line = fp.readline()
  233. self.nodelineno = self.nodelineno + 1
  234. if not line:
  235. if accu:
  236. if not self.skip: self.process(accu)
  237. accu = []
  238. if initial_lineno > 0:
  239. print '*** EOF before @bye'
  240. break
  241. lineno = lineno + 1
  242. mo = cmprog.match(line)
  243. if mo:
  244. a, b = mo.span(1)
  245. cmd = line[a:b]
  246. if cmd in ('noindent', 'refill'):
  247. accu.append(line)
  248. else:
  249. if accu:
  250. if not self.skip:
  251. self.process(accu)
  252. accu = []
  253. self.command(line, mo)
  254. elif blprog.match(line) and \
  255. 'format' not in self.stack and \
  256. 'example' not in self.stack:
  257. if accu:
  258. if not self.skip:
  259. self.process(accu)
  260. if self.nofill:
  261. self.write('\n')
  262. else:
  263. self.write('<P>\n')
  264. accu = []
  265. else:
  266. # Append the line including trailing \n!
  267. accu.append(line)
  268. #
  269. if self.skip:
  270. print '*** Still skipping at the end'
  271. if self.stack:
  272. print '*** Stack not empty at the end'
  273. print '***', self.stack
  274. if self.includedepth == 0:
  275. while self.nodestack:
  276. self.nodestack[-1].finalize()
  277. self.nodestack[-1].flush()
  278. del self.nodestack[-1]
  279. # Start saving text in a buffer instead of writing it to a file
  280. def startsaving(self):
  281. if self.savetext <> None:
  282. self.savestack.append(self.savetext)
  283. # print '*** Recursively saving text, expect trouble'
  284. self.savetext = ''
  285. # Return the text saved so far and start writing to file again
  286. def collectsavings(self):
  287. savetext = self.savetext
  288. if len(self.savestack) > 0:
  289. self.savetext = self.savestack[-1]
  290. del self.savestack[-1]
  291. else:
  292. self.savetext = None
  293. return savetext or ''
  294. # Write text to file, or save it in a buffer, or ignore it
  295. def write(self, *args):
  296. try:
  297. text = ''.join(args)
  298. except:
  299. print args
  300. raise TypeError
  301. if self.savetext <> None:
  302. self.savetext = self.savetext + text
  303. elif self.nodefp:
  304. self.nodefp.write(text)
  305. elif self.node:
  306. self.node.write(text)
  307. # Complete the current node -- write footnotes and close file
  308. def endnode(self):
  309. if self.savetext <> None:
  310. print '*** Still saving text at end of node'
  311. dummy = self.collectsavings()
  312. if self.footnotes:
  313. self.writefootnotes()
  314. if self.nodefp:
  315. if self.nodelineno > 20:
  316. self.write('<HR>\n')
  317. [name, next, prev, up] = self.nodelinks[:4]
  318. self.link('Next', next)
  319. self.link('Prev', prev)
  320. self.link('Up', up)
  321. if self.nodename <> self.topname:
  322. self.link('Top', self.topname)
  323. self.write('<HR>\n')
  324. self.write('</BODY>\n')
  325. self.nodefp.close()
  326. self.nodefp = None
  327. elif self.node:
  328. if not self.cont and \
  329. (not self.node.type or \
  330. (self.node.next and self.node.prev and self.node.up)):
  331. self.node.finalize()
  332. self.node.flush()
  333. else:
  334. self.nodestack.append(self.node)
  335. self.node = None
  336. self.nodename = ''
  337. # Process a list of lines, expanding embedded @-commands
  338. # This mostly distinguishes between menus and normal text
  339. def process(self, accu):
  340. if self.debugging > 1:
  341. print '!'*self.debugging, 'process:', self.skip, self.stack,
  342. if accu: print accu[0][:30],
  343. if accu[0][30:] or accu[1:]: print '...',
  344. print
  345. if self.inmenu():
  346. # XXX should be done differently
  347. for line in accu:
  348. mo = miprog.match(line)
  349. if not mo:
  350. line = line.strip() + '\n'
  351. self.expand(line)
  352. continue
  353. bgn, end = mo.span(0)
  354. a, b = mo.span(1)
  355. c, d = mo.span(2)
  356. e, f = mo.span(3)
  357. g, h = mo.span(4)
  358. label = line[a:b]
  359. nodename = line[c:d]
  360. if nodename[0] == ':': nodename = label
  361. else: nodename = line[e:f]
  362. punct = line[g:h]
  363. self.write(' <LI><A HREF="',
  364. makefile(nodename),
  365. '">', nodename,
  366. '</A>', punct, '\n')
  367. self.htmlhelp.menuitem(nodename)
  368. self.expand(line[end:])
  369. else:
  370. text = ''.join(accu)
  371. self.expand(text)
  372. # find 'menu' (we might be inside 'ifset' or 'ifclear')
  373. def inmenu(self):
  374. #if 'menu' in self.stack:
  375. # print 'inmenu :', self.skip, self.stack, self.stackinfo
  376. stack = self.stack
  377. while stack and stack[-1] in ('ifset','ifclear'):
  378. try:
  379. if self.stackinfo[len(stack)]:
  380. return 0
  381. except KeyError:
  382. pass
  383. stack = stack[:-1]
  384. return (stack and stack[-1] == 'menu')
  385. # Write a string, expanding embedded @-commands
  386. def expand(self, text):
  387. stack = []
  388. i = 0
  389. n = len(text)
  390. while i < n:
  391. start = i
  392. mo = spprog.search(text, i)
  393. if mo:
  394. i = mo.start()
  395. else:
  396. self.write(text[start:])
  397. break
  398. self.write(text[start:i])
  399. c = text[i]
  400. i = i+1
  401. if c == '\n':
  402. self.write('\n')
  403. continue
  404. if c == '<':
  405. self.write('&lt;')
  406. continue
  407. if c == '>':
  408. self.write('&gt;')
  409. continue
  410. if c == '&':
  411. self.write('&amp;')
  412. continue
  413. if c == '{':
  414. stack.append('')
  415. continue
  416. if c == '}':
  417. if not stack:
  418. print '*** Unmatched }'
  419. self.write('}')
  420. continue
  421. cmd = stack[-1]
  422. del stack[-1]
  423. try:
  424. method = getattr(self, 'close_' + cmd)
  425. except AttributeError:
  426. self.unknown_close(cmd)
  427. continue
  428. method()
  429. continue
  430. if c <> '@':
  431. # Cannot happen unless spprog is changed
  432. raise RuntimeError, 'unexpected funny %r' % c
  433. start = i
  434. while i < n and text[i] in string.ascii_letters: i = i+1
  435. if i == start:
  436. # @ plus non-letter: literal next character
  437. i = i+1
  438. c = text[start:i]
  439. if c == ':':
  440. # `@:' means no extra space after
  441. # preceding `.', `?', `!' or `:'
  442. pass
  443. else:
  444. # `@.' means a sentence-ending period;
  445. # `@@', `@{', `@}' quote `@', `{', `}'
  446. self.write(c)
  447. continue
  448. cmd = text[start:i]
  449. if i < n and text[i] == '{':
  450. i = i+1
  451. stack.append(cmd)
  452. try:
  453. method = getattr(self, 'open_' + cmd)
  454. except AttributeError:
  455. self.unknown_open(cmd)
  456. continue
  457. method()
  458. continue
  459. try:
  460. method = getattr(self, 'handle_' + cmd)
  461. except AttributeError:
  462. self.unknown_handle(cmd)
  463. continue
  464. method()
  465. if stack:
  466. print '*** Stack not empty at para:', stack
  467. # --- Handle unknown embedded @-commands ---
  468. def unknown_open(self, cmd):
  469. print '*** No open func for @' + cmd + '{...}'
  470. cmd = cmd + '{'
  471. self.write('@', cmd)
  472. if not self.unknown.has_key(cmd):
  473. self.unknown[cmd] = 1
  474. else:
  475. self.unknown[cmd] = self.unknown[cmd] + 1
  476. def unknown_close(self, cmd):
  477. print '*** No close func for @' + cmd + '{...}'
  478. cmd = '}' + cmd
  479. self.write('}')
  480. if not self.unknown.has_key(cmd):
  481. self.unknown[cmd] = 1
  482. else:
  483. self.unknown[cmd] = self.unknown[cmd] + 1
  484. def unknown_handle(self, cmd):
  485. print '*** No handler for @' + cmd
  486. self.write('@', cmd)
  487. if not self.unknown.has_key(cmd):
  488. self.unknown[cmd] = 1
  489. else:
  490. self.unknown[cmd] = self.unknown[cmd] + 1
  491. # XXX The following sections should be ordered as the texinfo docs
  492. # --- Embedded @-commands without {} argument list --
  493. def handle_noindent(self): pass
  494. def handle_refill(self): pass
  495. # --- Include file handling ---
  496. def do_include(self, args):
  497. file = args
  498. file = os.path.join(self.includedir, file)
  499. try:
  500. fp = open(file, 'r')
  501. except IOError, msg:
  502. print '*** Can\'t open include file', repr(file)
  503. return
  504. print '!'*self.debugging, '--> file', repr(file)
  505. save_done = self.done
  506. save_skip = self.skip
  507. save_stack = self.stack
  508. self.includedepth = self.includedepth + 1
  509. self.parserest(fp, 0)
  510. self.includedepth = self.includedepth - 1
  511. fp.close()
  512. self.done = save_done
  513. self.skip = save_skip
  514. self.stack = save_stack
  515. print '!'*self.debugging, '<-- file', repr(file)
  516. # --- Special Insertions ---
  517. def open_dmn(self): pass
  518. def close_dmn(self): pass
  519. def open_dots(self): self.write('...')
  520. def close_dots(self): pass
  521. def open_bullet(self): pass
  522. def close_bullet(self): pass
  523. def open_TeX(self): self.write('TeX')
  524. def close_TeX(self): pass
  525. def handle_copyright(self): self.write(self.COPYRIGHT_SYMBOL)
  526. def open_copyright(self): self.write(self.COPYRIGHT_SYMBOL)
  527. def close_copyright(self): pass
  528. def open_minus(self): self.write('-')
  529. def close_minus(self): pass
  530. # --- Accents ---
  531. # rpyron 2002-05-07
  532. # I would like to do at least as well as makeinfo when
  533. # it is producing HTML output:
  534. #
  535. # input output
  536. # @"o @"o umlaut accent
  537. # @'o 'o acute accent
  538. # @,{c} @,{c} cedilla accent
  539. # @=o @=o macron/overbar accent
  540. # @^o @^o circumflex accent
  541. # @`o `o grave accent
  542. # @~o @~o tilde accent
  543. # @dotaccent{o} @dotaccent{o} overdot accent
  544. # @H{o} @H{o} long Hungarian umlaut
  545. # @ringaccent{o} @ringaccent{o} ring accent
  546. # @tieaccent{oo} @tieaccent{oo} tie-after accent
  547. # @u{o} @u{o} breve accent
  548. # @ubaraccent{o} @ubaraccent{o} underbar accent
  549. # @udotaccent{o} @udotaccent{o} underdot accent
  550. # @v{o} @v{o} hacek or check accent
  551. # @exclamdown{} &#161; upside-down !
  552. # @questiondown{} &#191; upside-down ?
  553. # @aa{},@AA{} &#229;,&#197; a,A with circle
  554. # @ae{},@AE{} &#230;,&#198; ae,AE ligatures
  555. # @dotless{i} @dotless{i} dotless i
  556. # @dotless{j} @dotless{j} dotless j
  557. # @l{},@L{} l/,L/ suppressed-L,l
  558. # @o{},@O{} &#248;,&#216; O,o with slash
  559. # @oe{},@OE{} oe,OE oe,OE ligatures
  560. # @ss{} &#223; es-zet or sharp S
  561. #
  562. # The following character codes and approximations have been
  563. # copied from makeinfo's HTML output.
  564. def open_exclamdown(self): self.write('&#161;') # upside-down !
  565. def close_exclamdown(self): pass
  566. def open_questiondown(self): self.write('&#191;') # upside-down ?
  567. def close_questiondown(self): pass
  568. def open_aa(self): self.write('&#229;') # a with circle
  569. def close_aa(self): pass
  570. def open_AA(self): self.write('&#197;') # A with circle
  571. def close_AA(self): pass
  572. def open_ae(self): self.write('&#230;') # ae ligatures
  573. def close_ae(self): pass
  574. def open_AE(self): self.write('&#198;') # AE ligatures
  575. def close_AE(self): pass
  576. def open_o(self): self.write('&#248;') # o with slash
  577. def close_o(self): pass
  578. def open_O(self): self.write('&#216;') # O with slash
  579. def close_O(self): pass
  580. def open_ss(self): self.write('&#223;') # es-zet or sharp S
  581. def close_ss(self): pass
  582. def open_oe(self): self.write('oe') # oe ligatures
  583. def close_oe(self): pass
  584. def open_OE(self): self.write('OE') # OE ligatures
  585. def close_OE(self): pass
  586. def open_l(self): self.write('l/') # suppressed-l
  587. def close_l(self): pass
  588. def open_L(self): self.write('L/') # suppressed-L
  589. def close_L(self): pass
  590. # --- Special Glyphs for Examples ---
  591. def open_result(self): self.write('=&gt;')
  592. def close_result(self): pass
  593. def open_expansion(self): self.write('==&gt;')
  594. def close_expansion(self): pass
  595. def open_print(self): self.write('-|')
  596. def close_print(self): pass
  597. def open_error(self): self.write('error--&gt;')
  598. def close_error(self): pass
  599. def open_equiv(self): self.write('==')
  600. def close_equiv(self): pass
  601. def open_point(self): self.write('-!-')
  602. def close_point(self): pass
  603. # --- Cross References ---
  604. def open_pxref(self):
  605. self.write('see ')
  606. self.startsaving()
  607. def close_pxref(self):
  608. self.makeref()
  609. def open_xref(self):
  610. self.write('See ')
  611. self.startsaving()
  612. def close_xref(self):
  613. self.makeref()
  614. def open_ref(self):
  615. self.startsaving()
  616. def close_ref(self):
  617. self.makeref()
  618. def open_inforef(self):
  619. self.write('See info file ')
  620. self.startsaving()
  621. def close_inforef(self):
  622. text = self.collectsavings()
  623. args = [s.strip() for s in text.split(',')]
  624. while len(args) < 3: args.append('')
  625. node = args[0]
  626. file = args[2]
  627. self.write('`', file, '\', node `', node, '\'')
  628. def makeref(self):
  629. text = self.collectsavings()
  630. args = [s.strip() for s in text.split(',')]
  631. while len(args) < 5: args.append('')
  632. nodename = label = args[0]
  633. if args[2]: label = args[2]
  634. file = args[3]
  635. title = args[4]
  636. href = makefile(nodename)
  637. if file:
  638. href = '../' + file + '/' + href
  639. self.write('<A HREF="', href, '">', label, '</A>')
  640. # rpyron 2002-05-07 uref support
  641. def open_uref(self):
  642. self.startsaving()
  643. def close_uref(self):
  644. text = self.collectsavings()
  645. args = [s.strip() for s in text.split(',')]
  646. while len(args) < 2: args.append('')
  647. href = args[0]
  648. label = args[1]
  649. if not label: label = href
  650. self.write('<A HREF="', href, '">', label, '</A>')
  651. # rpyron 2002-05-07 image support
  652. # GNU makeinfo producing HTML output tries `filename.png'; if
  653. # that does not exist, it tries `filename.jpg'. If that does
  654. # not exist either, it complains. GNU makeinfo does not handle
  655. # GIF files; however, I include GIF support here because
  656. # MySQL documentation uses GIF files.
  657. def open_image(self):
  658. self.startsaving()
  659. def close_image(self):
  660. self.makeimage()
  661. def makeimage(self):
  662. text = self.collectsavings()
  663. args = [s.strip() for s in text.split(',')]
  664. while len(args) < 5: args.append('')
  665. filename = args[0]
  666. width = args[1]
  667. height = args[2]
  668. alt = args[3]
  669. ext = args[4]
  670. # The HTML output will have a reference to the image
  671. # that is relative to the HTML output directory,
  672. # which is what 'filename' gives us. However, we need
  673. # to find it relative to our own current directory,
  674. # so we construct 'imagename'.
  675. imagelocation = self.dirname + '/' + filename
  676. if os.path.exists(imagelocation+'.png'):
  677. filename += '.png'
  678. elif os.path.exists(imagelocation+'.jpg'):
  679. filename += '.jpg'
  680. elif os.path.exists(imagelocation+'.gif'): # MySQL uses GIF files
  681. filename += '.gif'
  682. else:
  683. print "*** Cannot find image " + imagelocation
  684. #TODO: what is 'ext'?
  685. self.write('<IMG SRC="', filename, '"', \
  686. width and (' WIDTH="' + width + '"') or "", \
  687. height and (' HEIGHT="' + height + '"') or "", \
  688. alt and (' ALT="' + alt + '"') or "", \
  689. '/>' )
  690. self.htmlhelp.addimage(imagelocation)
  691. # --- Marking Words and Phrases ---
  692. # --- Other @xxx{...} commands ---
  693. def open_(self): pass # Used by {text enclosed in braces}
  694. def close_(self): pass
  695. open_asis = open_
  696. close_asis = close_
  697. def open_cite(self): self.write('<CITE>')
  698. def close_cite(self): self.write('</CITE>')
  699. def open_code(self): self.write('<CODE>')
  700. def close_code(self): self.write('</CODE>')
  701. def open_t(self): self.write('<TT>')
  702. def close_t(self): self.write('</TT>')
  703. def open_dfn(self): self.write('<DFN>')
  704. def close_dfn(self): self.write('</DFN>')
  705. def open_emph(self): self.write('<EM>')
  706. def close_emph(self): self.write('</EM>')
  707. def open_i(self): self.write('<I>')
  708. def close_i(self): self.write('</I>')
  709. def open_footnote(self):
  710. # if self.savetext <> None:
  711. # print '*** Recursive footnote -- expect weirdness'
  712. id = len(self.footnotes) + 1
  713. self.write(self.FN_SOURCE_PATTERN % {'id': repr(id)})
  714. self.startsaving()
  715. def close_footnote(self):
  716. id = len(self.footnotes) + 1
  717. self.footnotes.append((id, self.collectsavings()))
  718. def writefootnotes(self):
  719. self.write(self.FN_HEADER)
  720. for id, text in self.footnotes:
  721. self.write(self.FN_TARGET_PATTERN
  722. % {'id': repr(id), 'text': text})
  723. self.footnotes = []
  724. def open_file(self): self.write('<CODE>')
  725. def close_file(self): self.write('</CODE>')
  726. def open_kbd(self): self.write('<KBD>')
  727. def close_kbd(self): self.write('</KBD>')
  728. def open_key(self): self.write('<KEY>')
  729. def close_key(self): self.write('</KEY>')
  730. def open_r(self): self.write('<R>')
  731. def close_r(self): self.write('</R>')
  732. def open_samp(self): self.write('`<SAMP>')
  733. def close_samp(self): self.write('</SAMP>\'')
  734. def open_sc(self): self.write('<SMALLCAPS>')
  735. def close_sc(self): self.write('</SMALLCAPS>')
  736. def open_strong(self): self.write('<STRONG>')
  737. def close_strong(self): self.write('</STRONG>')
  738. def open_b(self): self.write('<B>')
  739. def close_b(self): self.write('</B>')
  740. def open_var(self): self.write('<VAR>')
  741. def close_var(self): self.write('</VAR>')
  742. def open_w(self): self.write('<NOBREAK>')
  743. def close_w(self): self.write('</NOBREAK>')
  744. def open_url(self): self.startsaving()
  745. def close_url(self):
  746. text = self.collectsavings()
  747. self.write('<A HREF="', text, '">', text, '</A>')
  748. def open_email(self): self.startsaving()
  749. def close_email(self):
  750. text = self.collectsavings()
  751. self.write('<A HREF="mailto:', text, '">', text, '</A>')
  752. open_titlefont = open_
  753. close_titlefont = close_
  754. def open_small(self): pass
  755. def close_small(self): pass
  756. def command(self, line, mo):
  757. a, b = mo.span(1)
  758. cmd = line[a:b]
  759. args = line[b:].strip()
  760. if self.debugging > 1:
  761. print '!'*self.debugging, 'command:', self.skip, self.stack, \
  762. '@' + cmd, args
  763. try:
  764. func = getattr(self, 'do_' + cmd)
  765. except AttributeError:
  766. try:
  767. func = getattr(self, 'bgn_' + cmd)
  768. except AttributeError:
  769. # don't complain if we are skipping anyway
  770. if not self.skip:
  771. self.unknown_cmd(cmd, args)
  772. return
  773. self.stack.append(cmd)
  774. func(args)
  775. return
  776. if not self.skip or cmd == 'end':
  777. func(args)
  778. def unknown_cmd(self, cmd, args):
  779. print '*** unknown', '@' + cmd, args
  780. if not self.unknown.has_key(cmd):
  781. self.unknown[cmd] = 1
  782. else:
  783. self.unknown[cmd] = self.unknown[cmd] + 1
  784. def do_end(self, args):
  785. words = args.split()
  786. if not words:
  787. print '*** @end w/o args'
  788. else:
  789. cmd = words[0]
  790. if not self.stack or self.stack[-1] <> cmd:
  791. print '*** @end', cmd, 'unexpected'
  792. else:
  793. del self.stack[-1]
  794. try:
  795. func = getattr(self, 'end_' + cmd)
  796. except AttributeError:
  797. self.unknown_end(cmd)
  798. return
  799. func()
  800. def unknown_end(self, cmd):
  801. cmd = 'end ' + cmd
  802. print '*** unknown', '@' + cmd
  803. if not self.unknown.has_key(cmd):
  804. self.unknown[cmd] = 1
  805. else:
  806. self.unknown[cmd] = self.unknown[cmd] + 1
  807. # --- Comments ---
  808. def do_comment(self, args): pass
  809. do_c = do_comment
  810. # --- Conditional processing ---
  811. def bgn_ifinfo(self, args): pass
  812. def end_ifinfo(self): pass
  813. def bgn_iftex(self, args): self.skip = self.skip + 1
  814. def end_iftex(self): self.skip = self.skip - 1
  815. def bgn_ignore(self, args): self.skip = self.skip + 1
  816. def end_ignore(self): self.skip = self.skip - 1
  817. def bgn_tex(self, args): self.skip = self.skip + 1
  818. def end_tex(self): self.skip = self.skip - 1
  819. def do_set(self, args):
  820. fields = args.split(' ')
  821. key = fields[0]
  822. if len(fields) == 1:
  823. value = 1
  824. else:
  825. value = ' '.join(fields[1:])
  826. self.values[key] = value
  827. def do_clear(self, args):
  828. self.values[args] = None
  829. def bgn_ifset(self, args):
  830. if args not in self.values.keys() \
  831. or self.values[args] is None:
  832. self.skip = self.skip + 1
  833. self.stackinfo[len(self.stack)] = 1
  834. else:
  835. self.stackinfo[len(self.stack)] = 0
  836. def end_ifset(self):
  837. try:
  838. if self.stackinfo[len(self.stack) + 1]:
  839. self.skip = self.skip - 1
  840. del self.stackinfo[len(self.stack) + 1]
  841. except KeyError:
  842. print '*** end_ifset: KeyError :', len(self.stack) + 1
  843. def bgn_ifclear(self, args):
  844. if args in self.values.keys() \
  845. and self.values[args] is not None:
  846. self.skip = self.skip + 1
  847. self.stackinfo[len(self.stack)] = 1
  848. else:
  849. self.stackinfo[len(self.stack)] = 0
  850. def end_ifclear(self):
  851. try:
  852. if self.stackinfo[len(self.stack) + 1]:
  853. self.skip = self.skip - 1
  854. del self.stackinfo[len(self.stack) + 1]
  855. except KeyError:
  856. print '*** end_ifclear: KeyError :', len(self.stack) + 1
  857. def open_value(self):
  858. self.startsaving()
  859. def close_value(self):
  860. key = self.collectsavings()
  861. if key in self.values.keys():
  862. self.write(self.values[key])
  863. else:
  864. print '*** Undefined value: ', key
  865. # --- Beginning a file ---
  866. do_finalout = do_comment
  867. do_setchapternewpage = do_comment
  868. do_setfilename = do_comment
  869. def do_settitle(self, args):
  870. self.startsaving()
  871. self.expand(args)
  872. self.title = self.collectsavings()
  873. def do_parskip(self, args): pass
  874. # --- Ending a file ---
  875. def do_bye(self, args):
  876. self.endnode()
  877. self.done = 1
  878. # --- Title page ---
  879. def bgn_titlepage(self, args): self.skip = self.skip + 1
  880. def end_titlepage(self): self.skip = self.skip - 1
  881. def do_shorttitlepage(self, args): pass
  882. def do_center(self, args):
  883. # Actually not used outside title page...
  884. self.write('<H1>')
  885. self.expand(args)
  886. self.write('</H1>\n')
  887. do_title = do_center
  888. do_subtitle = do_center
  889. do_author = do_center
  890. do_vskip = do_comment
  891. do_vfill = do_comment
  892. do_smallbook = do_comment
  893. do_paragraphindent = do_comment
  894. do_setchapternewpage = do_comment
  895. do_headings = do_comment
  896. do_footnotestyle = do_comment
  897. do_evenheading = do_comment
  898. do_evenfooting = do_comment
  899. do_oddheading = do_comment
  900. do_oddfooting = do_comment
  901. do_everyheading = do_comment
  902. do_everyfooting = do_comment
  903. # --- Nodes ---
  904. def do_node(self, args):
  905. self.endnode()
  906. self.nodelineno = 0
  907. parts = [s.strip() for s in args.split(',')]
  908. while len(parts) < 4: parts.append('')
  909. self.nodelinks = parts
  910. [name, next, prev, up] = parts[:4]
  911. file = self.dirname + '/' + makefile(name)
  912. if self.filenames.has_key(file):
  913. print '*** Filename already in use: ', file
  914. else:
  915. if self.debugging: print '!'*self.debugging, '--- writing', file
  916. self.filenames[file] = 1
  917. # self.nodefp = open(file, 'w')
  918. self.nodename = name
  919. if self.cont and self.nodestack:
  920. self.nodestack[-1].cont = self.nodename
  921. if not self.topname: self.topname = name
  922. title = name
  923. if self.title: title = title + ' -- ' + self.title
  924. self.node = self.Node(self.dirname, self.nodename, self.topname,
  925. title, next, prev, up)
  926. self.htmlhelp.addnode(self.nodename,next,prev,up,file)
  927. def link(self, label, nodename):
  928. if nodename:
  929. if nodename.lower() == '(dir)':
  930. addr = '../dir.html'
  931. else:
  932. addr = makefile(nodename)
  933. self.write(label, ': <A HREF="', addr, '" TYPE="',
  934. label, '">', nodename, '</A> \n')
  935. # --- Sectioning commands ---
  936. def popstack(self, type):
  937. if (self.node):
  938. self.node.type = type
  939. while self.nodestack:
  940. if self.nodestack[-1].type > type:
  941. self.nodestack[-1].finalize()
  942. self.nodestack[-1].flush()
  943. del self.nodestack[-1]
  944. elif self.nodestack[-1].type == type:
  945. if not self.nodestack[-1].next:
  946. self.nodestack[-1].next = self.node.name
  947. if not self.node.prev:
  948. self.node.prev = self.nodestack[-1].name
  949. self.nodestack[-1].finalize()
  950. self.nodestack[-1].flush()
  951. del self.nodestack[-1]
  952. else:
  953. if type > 1 and not self.node.up:
  954. self.node.up = self.nodestack[-1].name
  955. break
  956. def do_chapter(self, args):
  957. self.heading('H1', args, 0)
  958. self.popstack(1)
  959. def do_unnumbered(self, args):
  960. self.heading('H1', args, -1)
  961. self.popstack(1)
  962. def do_appendix(self, args):
  963. self.heading('H1', args, -1)
  964. self.popstack(1)
  965. def do_top(self, args):
  966. self.heading('H1', args, -1)
  967. def do_chapheading(self, args):
  968. self.heading('H1', args, -1)
  969. def do_majorheading(self, args):
  970. self.heading('H1', args, -1)
  971. def do_section(self, args):
  972. self.heading('H1', args, 1)
  973. self.popstack(2)
  974. def do_unnumberedsec(self, args):
  975. self.heading('H1', args, -1)
  976. self.popstack(2)
  977. def do_appendixsec(self, args):
  978. self.heading('H1', args, -1)
  979. self.popstack(2)
  980. do_appendixsection = do_appendixsec
  981. def do_heading(self, args):
  982. self.heading('H1', args, -1)
  983. def do_subsection(self, args):
  984. self.heading('H2', args, 2)
  985. self.popstack(3)
  986. def do_unnumberedsubsec(self, args):
  987. self.heading('H2', args, -1)
  988. self.popstack(3)
  989. def do_appendixsubsec(self, args):
  990. self.heading('H2', args, -1)
  991. self.popstack(3)
  992. def do_subheading(self, args):
  993. self.heading('H2', args, -1)
  994. def do_subsubsection(self, args):
  995. self.heading('H3', args, 3)
  996. self.popstack(4)
  997. def do_unnumberedsubsubsec(self, args):
  998. self.heading('H3', args, -1)
  999. self.popstack(4)
  1000. def do_appendixsubsubsec(self, args):
  1001. self.heading('H3', args, -1)
  1002. self.popstack(4)
  1003. def do_subsubheading(self, args):
  1004. self.heading('H3', args, -1)
  1005. def heading(self, type, args, level):
  1006. if level >= 0:
  1007. while len(self.numbering) <= level:
  1008. self.numbering.append(0)
  1009. del self.numbering[level+1:]
  1010. self.numbering[level] = self.numbering[level] + 1
  1011. x = ''
  1012. for i in self.numbering:
  1013. x = x + repr(i) + '.'
  1014. args = x + ' ' + args
  1015. self.contents.append((level, args, self.nodename))
  1016. self.write('<', type, '>')
  1017. self.expand(args)
  1018. self.write('</', type, '>\n')
  1019. if self.debugging or self.print_headers:
  1020. print '---', args
  1021. def do_contents(self, args):
  1022. # pass
  1023. self.listcontents('Table of Contents', 999)
  1024. def do_shortcontents(self, args):
  1025. pass
  1026. # self.listcontents('Short Contents', 0)
  1027. do_summarycontents = do_shortcontents
  1028. def listcontents(self, title, maxlevel):
  1029. self.write('<H1>', title, '</H1>\n<UL COMPACT PLAIN>\n')
  1030. prevlevels = [0]
  1031. for level, title, node in self.contents:
  1032. if level > maxlevel:
  1033. continue
  1034. if level > prevlevels[-1]:
  1035. # can only advance one level at a time
  1036. self.write(' '*prevlevels[-1], '<UL PLAIN>\n')
  1037. prevlevels.append(level)
  1038. elif level < prevlevels[-1]:
  1039. # might drop back multiple levels
  1040. while level < prevlevels[-1]:
  1041. del prevlevels[-1]
  1042. self.write(' '*prevlevels[-1],
  1043. '</UL>\n')
  1044. self.write(' '*level, '<LI> <A HREF="',
  1045. makefile(node), '">')
  1046. self.expand(title)
  1047. self.write('</A>\n')
  1048. self.write('</UL>\n' * len(prevlevels))
  1049. # --- Page lay-out ---
  1050. # These commands are only meaningful in printed text
  1051. def do_page(self, args): pass
  1052. def do_need(self, args): pass
  1053. def bgn_group(self, args): pass
  1054. def end_group(self): pass
  1055. # --- Line lay-out ---
  1056. def do_sp(self, args):
  1057. if self.nofill:
  1058. self.write('\n')
  1059. else:
  1060. self.write('<P>\n')
  1061. def do_hline(self, args):
  1062. self.write('<HR>')
  1063. # --- Function and variable definitions ---
  1064. def bgn_deffn(self, args):
  1065. self.write('<DL>')
  1066. self.do_deffnx(args)
  1067. def end_deffn(self):
  1068. self.write('</DL>\n')
  1069. def do_deffnx(self, args):
  1070. self.write('<DT>')
  1071. words = splitwords(args, 2)
  1072. [category, name], rest = words[:2], words[2:]
  1073. self.expand('@b{%s}' % name)
  1074. for word in rest: self.expand(' ' + makevar(word))
  1075. #self.expand(' -- ' + category)
  1076. self.write('\n<DD>')
  1077. self.index('fn', name)
  1078. def bgn_defun(self, args): self.bgn_deffn('Function ' + args)
  1079. end_defun = end_deffn
  1080. def do_defunx(self, args): self.do_deffnx('Function ' + args)
  1081. def bgn_defmac(self, args): self.bgn_deffn('Macro ' + args)
  1082. end_defmac = end_deffn
  1083. def do_defmacx(self, args): self.do_deffnx('Macro ' + args)
  1084. def bgn_defspec(self, args): self.bgn_deffn('{Special Form} ' + args)
  1085. end_defspec = end_deffn
  1086. def do_defspecx(self, args): self.do_deffnx('{Special Form} ' + args)
  1087. def bgn_defvr(self, args):
  1088. self.write('<DL>')
  1089. self.do_defvrx(args)
  1090. end_defvr = end_deffn
  1091. def do_defvrx(self, args):
  1092. self.write('<DT>')
  1093. words = splitwords(args, 2)
  1094. [category, name], rest = words[:2], words[2:]
  1095. self.expand('@code{%s}' % name)
  1096. # If there are too many arguments, show them
  1097. for word in rest: self.expand(' ' + word)
  1098. #self.expand(' -- ' + category)
  1099. self.write('\n<DD>')
  1100. self.index('vr', name)
  1101. def bgn_defvar(self, args): self.bgn_defvr('Variable ' + args)
  1102. end_defvar = end_defvr
  1103. def do_defvarx(self, args): self.do_defvrx('Variable ' + args)
  1104. def bgn_defopt(self, args): self.bgn_defvr('{User Option} ' + args)
  1105. end_defopt = end_defvr
  1106. def do_defoptx(self, args): self.do_defvrx('{User Option} ' + args)
  1107. # --- Ditto for typed languages ---
  1108. def bgn_deftypefn(self, args):
  1109. self.write('<DL>')
  1110. self.do_deftypefnx(args)
  1111. end_deftypefn = end_deffn
  1112. def do_deftypefnx(self, args):
  1113. self.write('<DT>')
  1114. words = splitwords(args, 3)
  1115. [category, datatype, name], rest = words[:3], words[3:]
  1116. self.expand('@code{%s} @b{%s}' % (datatype, name))
  1117. for word in rest: self.expand(' ' + makevar(word))
  1118. #self.expand(' -- ' + category)
  1119. self.write('\n<DD>')
  1120. self.index('fn', name)
  1121. def bgn_deftypefun(self, args): self.bgn_deftypefn('Function ' + args)
  1122. end_deftypefun = end_deftypefn
  1123. def do_deftypefunx(self, args): self.do_deftypefnx('Function ' + args)
  1124. def bgn_deftypevr(self, args):
  1125. self.write('<DL>')
  1126. self.do_deftypevrx(args)
  1127. end_deftypevr = end_deftypefn
  1128. def do_deftypevrx(self, args):
  1129. self.write('<DT>')
  1130. words = splitwords(args, 3)
  1131. [category, datatype, name], rest = words[:3], words[3:]
  1132. self.expand('@code{%s} @b{%s}' % (datatype, name))
  1133. # If there are too many arguments, show them
  1134. for word in rest: self.expand(' ' + word)
  1135. #self.expand(' -- ' + category)
  1136. self.write('\n<DD>')
  1137. self.index('fn', name)
  1138. def bgn_deftypevar(self, args):
  1139. self.bgn_deftypevr('Variable ' + args)
  1140. end_deftypevar = end_deftypevr
  1141. def do_deftypevarx(self, args):
  1142. self.do_deftypevrx('Variable ' + args)
  1143. # --- Ditto for object-oriented languages ---
  1144. def bgn_defcv(self, args):
  1145. self.write('<DL>')
  1146. self.do_defcvx(args)
  1147. end_defcv = end_deftypevr
  1148. def do_defcvx(self, args):
  1149. self.write('<DT>')
  1150. words = splitwords(args, 3)
  1151. [category, classname, name], rest = words[:3], words[3:]
  1152. self.expand('@b{%s}' % name)
  1153. # If there are too many arguments, show them
  1154. for word in rest: self.expand(' ' + word)
  1155. #self.expand(' -- %s of @code{%s}' % (category, classname))
  1156. self.write('\n<DD>')
  1157. self.index('vr', '%s @r{on %s}' % (name, classname))
  1158. def bgn_defivar(self, args):
  1159. self.bgn_defcv('{Instance Variable} ' + args)
  1160. end_defivar = end_defcv
  1161. def do_defivarx(self, args):
  1162. self.do_defcvx('{Instance Variable} ' + args)
  1163. def bgn_defop(self, args):
  1164. self.write('<DL>')
  1165. self.do_defopx(args)
  1166. end_defop = end_defcv
  1167. def do_defopx(self, args):
  1168. self.write('<DT>')
  1169. words = splitwords(args, 3)
  1170. [category, classname, name], rest = words[:3], words[3:]
  1171. self.expand('@b{%s}' % name)
  1172. for word in rest: self.expand(' ' + makevar(word))
  1173. #self.expand(' -- %s of @code{%s}' % (category, classname))
  1174. self.write('\n<DD>')
  1175. self.index('fn', '%s @r{on %s}' % (name, classname))
  1176. def bgn_defmethod(self, args):
  1177. self.bgn_defop('Method ' + args)
  1178. end_defmethod = end_defop
  1179. def do_defmethodx(self, args):
  1180. self.do_defopx('Method ' + args)
  1181. # --- Ditto for data types ---
  1182. def bgn_deftp(self, args):
  1183. self.write('<DL>')
  1184. self.do_deftpx(args)
  1185. end_deftp = end_defcv
  1186. def do_deftpx(self, args):
  1187. self.write('<DT>')
  1188. words = splitwords(args, 2)
  1189. [category, name], rest = words[:2], words[2:]
  1190. self.expand('@b{%s}' % name)
  1191. for word in rest: self.expand(' ' + word)
  1192. #self.expand(' -- ' + category)
  1193. self.write('\n<DD>')
  1194. self.index('tp', name)
  1195. # --- Making Lists and Tables
  1196. def bgn_enumerate(self, args):
  1197. if not args:
  1198. self.write('<OL>\n')
  1199. self.stackinfo[len(self.stack)] = '</OL>\n'
  1200. else:
  1201. self.itemnumber = args
  1202. self.write('<UL>\n')
  1203. self.stackinfo[len(self.stack)] = '</UL>\n'
  1204. def end_enumerate(self):
  1205. self.itemnumber = None
  1206. self.write(self.stackinfo[len(self.stack) + 1])
  1207. del self.stackinfo[len(self.stack) + 1]
  1208. def bgn_itemize(self, args):
  1209. self.itemarg = args
  1210. self.write('<UL>\n')
  1211. def end_itemize(self):
  1212. self.itemarg = None
  1213. self.write('</UL>\n')
  1214. def bgn_table(self, args):
  1215. self.itemarg = args
  1216. self.write('<DL>\n')
  1217. def end_table(self):
  1218. self.itemarg = None
  1219. self.write('</DL>\n')
  1220. def bgn_ftable(self, args):
  1221. self.itemindex = 'fn'
  1222. self.bgn_table(args)
  1223. def end_ftable(self):
  1224. self.itemindex = None
  1225. self.end_table()
  1226. def bgn_vtable(self, args):
  1227. self.itemindex = 'vr'
  1228. self.bgn_table(args)
  1229. def end_vtable(self):
  1230. self.itemindex = None
  1231. self.end_table()
  1232. def do_item(self, args):
  1233. if self.itemindex: self.index(self.itemindex, args)
  1234. if self.itemarg:
  1235. if self.itemarg[0] == '@' and self.itemarg[1] and \
  1236. self.itemarg[1] in string.ascii_letters:
  1237. args = self.itemarg + '{' + args + '}'
  1238. else:
  1239. # some other character, e.g. '-'
  1240. args = self.itemarg + ' ' + args
  1241. if self.itemnumber <> None:
  1242. args = self.itemnumber + '. ' + args
  1243. self.itemnumber = increment(self.itemnumber)
  1244. if self.stack and self.stack[-1] == 'table':
  1245. self.write('<DT>')
  1246. self.expand(args)
  1247. self.write('\n<DD>')
  1248. elif self.stack and self.stack[-1] == 'multitable':
  1249. self.write('<TR><TD>')
  1250. self.expand(args)
  1251. self.write('</TD>\n</TR>\n')
  1252. else:
  1253. self.write('<LI>')
  1254. self.expand(args)
  1255. self.write(' ')
  1256. do_itemx = do_item # XXX Should suppress leading blank line
  1257. # rpyron 2002-05-07 multitable support
  1258. def bgn_multitable(self, args):
  1259. self.itemarg = None # should be handled by columnfractions
  1260. self.write('<TABLE BORDER="">\n')
  1261. def end_multitable(self):
  1262. self.itemarg = None
  1263. self.write('</TABLE>\n<BR>\n')
  1264. def handle_columnfractions(self):
  1265. # It would be better to handle this, but for now it's in the way...
  1266. self.itemarg = None
  1267. def handle_tab(self):
  1268. self.write('</TD>\n <TD>')
  1269. # --- Enumerations, displays, quotations ---
  1270. # XXX Most of these should increase the indentation somehow
  1271. def bgn_quotation(self, args): self.write('<BLOCKQUOTE>')
  1272. def end_quotation(self): self.write('</BLOCKQUOTE>\n')
  1273. def bgn_example(self, args):
  1274. self.nofill = self.nofill + 1
  1275. self.write('<PRE>')
  1276. def end_example(self):
  1277. self.write('</PRE>\n')
  1278. self.nofill = self.nofill - 1
  1279. bgn_lisp = bgn_example # Synonym when contents are executable lisp code
  1280. end_lisp = end_example
  1281. bgn_smallexample = bgn_example # XXX Should use smaller font
  1282. end_smallexample = end_example
  1283. bgn_smalllisp = bgn_lisp # Ditto
  1284. end_smalllisp = end_lisp
  1285. bgn_display = bgn_example
  1286. end_display = end_example
  1287. bgn_format = bgn_display
  1288. end_format = end_display
  1289. def do_exdent(self, args): self.expand(args + '\n')
  1290. # XXX Should really mess with indentation
  1291. def bgn_flushleft(self, args):
  1292. self.nofill = self.nofill + 1
  1293. self.write('<PRE>\n')
  1294. def end_flushleft(self):
  1295. self.write('</PRE>\n')
  1296. self.nofill = self.nofill - 1
  1297. def bgn_flushright(self, args):
  1298. self.nofill = self.nofill + 1
  1299. self.write('<ADDRESS COMPACT>\n')
  1300. def end_flushright(self):
  1301. self.write('</ADDRESS>\n')
  1302. self.nofill = self.nofill - 1
  1303. def bgn_menu(self, args):
  1304. self.write('<DIR>\n')
  1305. self.write(' <STRONG><EM>Menu</EM></STRONG><P>\n')
  1306. self.htmlhelp.beginmenu()
  1307. def end_menu(self):
  1308. self.write('</DIR>\n')
  1309. self.htmlhelp.endmenu()
  1310. def bgn_cartouche(self, args): pass
  1311. def end_cartouche(self): pass
  1312. # --- Indices ---
  1313. def resetindex(self):
  1314. self.noncodeindices = ['cp']
  1315. self.indextitle = {}
  1316. self.indextitle['cp'] = 'Concept'
  1317. self.indextitle['fn'] = 'Function'
  1318. self.indextitle['ky'] = 'Keyword'
  1319. self.indextitle['pg'] = 'Program'
  1320. self.indextitle['tp'] = 'Type'
  1321. self.indextitle['vr'] = 'Variable'
  1322. #
  1323. self.whichindex = {}
  1324. for name in self.indextitle.keys():
  1325. self.whichindex[name] = []
  1326. def user_index(self, name, args):
  1327. if self.whichindex.has_key(name):
  1328. self.index(name, args)
  1329. else:
  1330. print '*** No index named', repr(name)
  1331. def do_cindex(self, args): self.index('cp', args)
  1332. def do_findex(self, args): self.index('fn', args)
  1333. def do_kindex(self, args): self.index('ky', args)
  1334. def do_pindex(self, args): self.index('pg', args)
  1335. def do_tindex(self, args): self.index('tp', args)
  1336. def do_vindex(self, args): self.index('vr', args)
  1337. def index(self, name, args):
  1338. self.whichindex[name].append((args, self.nodename))
  1339. self.htmlhelp.index(args, self.nodename)
  1340. def do_synindex(self, args):
  1341. words = args.split()
  1342. if len(words) <> 2:
  1343. print '*** bad @synindex', args
  1344. return
  1345. [old, new] = words
  1346. if not self.whichindex.has_key(old) or \
  1347. not self.whichindex.has_key(new):
  1348. print '*** bad key(s) in @synindex', args
  1349. return
  1350. if old <> new and \
  1351. self.whichindex[old] is not self.whichindex[new]:
  1352. inew = self.whichindex[new]
  1353. inew[len(inew):] = self.whichindex[old]
  1354. self.whichindex[old] = inew
  1355. do_syncodeindex = do_synindex # XXX Should use code font
  1356. def do_printindex(self, args):
  1357. words = args.split()
  1358. for name in words:
  1359. if self.whichindex.has_key(name):
  1360. self.prindex(name)
  1361. else:
  1362. print '*** No index named', repr(name)
  1363. def prindex(self, name):
  1364. iscodeindex = (name not in self.noncodeindices)
  1365. index = self.whichindex[name]
  1366. if not index: return
  1367. if self.debugging:
  1368. print '!'*self.debugging, '--- Generating', \
  1369. self.indextitle[name], 'index'
  1370. # The node already provides a title
  1371. index1 = []
  1372. junkprog = re.compile('^(@[a-z]+)?{')
  1373. for key, node in index:
  1374. sortkey = key.lower()
  1375. # Remove leading `@cmd{' from sort key
  1376. # -- don't bother about the matching `}'
  1377. oldsortkey = sortkey
  1378. while 1:
  1379. mo = junkprog.match(sortkey)
  1380. if not mo:
  1381. break
  1382. i = mo.end()
  1383. sortkey = sortkey[i:]
  1384. index1.append((sortkey, key, node))
  1385. del index[:]
  1386. index1.sort()
  1387. self.write('<DL COMPACT>\n')
  1388. prevkey = prevnode = None
  1389. for sortkey, key, node in index1:
  1390. if (key, node) == (prevkey, prevnode):
  1391. continue
  1392. if self.debugging > 1: print '!'*self.debugging, key, ':', node
  1393. self.write('<DT>')
  1394. if iscodeindex: key = '@code{' + key + '}'
  1395. if key != prevkey:
  1396. self.expand(key)
  1397. self.write('\n<DD><A HREF="%s">%s</A>\n' % (makefile(node), node))
  1398. prevkey, prevnode = key, node
  1399. self.write('</DL>\n')
  1400. # --- Final error reports ---
  1401. def report(self):
  1402. if self.unknown:
  1403. print '--- Unrecognized commands ---'
  1404. cmds = self.unknown.keys()
  1405. cmds.sort()
  1406. for cmd in cmds:
  1407. print cmd.ljust(20), self.unknown[cmd]
  1408. class TexinfoParserHTML3(TexinfoParser):
  1409. COPYRIGHT_SYMBOL = "&copy;"
  1410. FN_ID_PATTERN = "[%(id)s]"
  1411. FN_SOURCE_PATTERN = '<A ID=footnoteref%(id)s ' \
  1412. 'HREF="#footnotetext%(id)s">' + FN_ID_PATTERN + '</A>'
  1413. FN_TARGET_PATTERN = '<FN ID=footnotetext%(id)s>\n' \
  1414. '<P><A HREF="#footnoteref%(id)s">' + FN_ID_PATTERN \
  1415. + '</A>\n%(text)s</P></FN>\n'
  1416. FN_HEADER = '<DIV CLASS=footnotes>\n <HR NOSHADE WIDTH=200>\n' \
  1417. ' <STRONG><EM>Footnotes</EM></STRONG>\n <P>\n'
  1418. Node = HTML3Node
  1419. def bgn_quotation(self, args): self.write('<BQ>')
  1420. def end_quotation(self): self.write('</BQ>\n')
  1421. def bgn_example(self, args):
  1422. # this use of <CODE> would not be legal in HTML 2.0,
  1423. # but is in more recent DTDs.
  1424. self.nofill = self.nofill + 1
  1425. self.write('<PRE CLASS=example><CODE>')
  1426. def end_example(self):
  1427. self.write("</CODE></PRE>\n")
  1428. self.nofill = self.nofill - 1
  1429. def bgn_flushleft(self, args):
  1430. self.nofill = self.nofill + 1
  1431. self.write('<PRE CLASS=flushleft>\n')
  1432. def bgn_flushright(self, args):
  1433. self.nofill = self.nofill + 1
  1434. self.write('<DIV ALIGN=right CLASS=flushright><ADDRESS COMPACT>\n')
  1435. def end_flushright(self):
  1436. self.write('</ADDRESS></DIV>\n')
  1437. self.nofill = self.nofill - 1
  1438. def bgn_menu(self, args):
  1439. self.write('<UL PLAIN CLASS=menu>\n')
  1440. self.write(' <LH>Menu</LH>\n')
  1441. def end_menu(self):
  1442. self.write('</UL>\n')
  1443. # rpyron 2002-05-07
  1444. class HTMLHelp:
  1445. """
  1446. This class encapsulates support for HTML Help. Node names,
  1447. file names, menu items, index items, and image file names are
  1448. accumulated until a call to finalize(). At that time, three
  1449. output files are created in the current directory:
  1450. `helpbase`.hhp is a HTML Help Workshop project file.
  1451. It contains various information, some of
  1452. which I do not understand; I just copied
  1453. the default project info from a fresh
  1454. installation.
  1455. `helpbase`.hhc is the Contents file for the project.
  1456. `helpbase`.hhk is the Index file for the project.
  1457. When these files are used as input to HTML Help Workshop,
  1458. the resulting file will be named:
  1459. `helpbase`.chm
  1460. If none of the defaults in `helpbase`.hhp are changed,
  1461. the .CHM file will have Contents, Index, Search, and
  1462. Favorites tabs.
  1463. """
  1464. codeprog = re.compile('@code{(.*?)}')
  1465. def __init__(self,helpbase,dirname):
  1466. self.helpbase = helpbase
  1467. self.dirname = dirname
  1468. self.projectfile = None
  1469. self.contentfile = None
  1470. self.indexfile = None
  1471. self.nodelist = []
  1472. self.nodenames = {} # nodename : index
  1473. self.nodeindex = {}
  1474. self.filenames = {} # filename : filename
  1475. self.indexlist = [] # (args,nodename) == (key,location)
  1476. self.current = ''
  1477. self.menudict = {}
  1478. self.dumped = {}
  1479. def addnode(self,name,next,prev,up,filename):
  1480. node = (name,next,prev,up,filename)
  1481. # add this file to dict
  1482. # retrieve list with self.filenames.values()
  1483. self.filenames[filename] = filename
  1484. # add this node to nodelist
  1485. self.nodeindex[name] = len(self.nodelist)
  1486. self.nodelist.append(node)
  1487. # set 'current' for menu items
  1488. self.current = name
  1489. self.menudict[self.current] = []
  1490. def menuitem(self,nodename):
  1491. menu = self.menudict[self.current]
  1492. menu.append(nodename)
  1493. def addimage(self,imagename):
  1494. self.filenames[imagename] = imagename
  1495. def index(self, args, nodename):
  1496. self.indexlist.append((args,nodename))
  1497. def beginmenu(self):
  1498. pass
  1499. def endmenu(self):
  1500. pass
  1501. def finalize(self):
  1502. if not self.helpbase:
  1503. return
  1504. # generate interesting filenames
  1505. resultfile = self.helpbase + '.chm'
  1506. projectfile = self.helpbase + '.hhp'
  1507. contentfile = self.helpbase + '.hhc'
  1508. indexfile = self.helpbase + '.hhk'
  1509. # generate a reasonable title
  1510. title = self.helpbase
  1511. # get the default topic file
  1512. (topname,topnext,topprev,topup,topfile) = self.nodelist[0]
  1513. defaulttopic = topfile
  1514. # PROJECT FILE
  1515. try:
  1516. fp = open(projectfile,'w')
  1517. print>>fp, '[OPTIONS]'
  1518. print>>fp, 'Auto Index=Yes'
  1519. print>>fp, 'Binary TOC=No'
  1520. print>>fp, 'Binary Index=Yes'
  1521. print>>fp, 'Compatibility=1.1'
  1522. print>>fp, 'Compiled file=' + resultfile + ''
  1523. print>>fp, 'Contents file=' + contentfile + ''
  1524. print>>fp, 'Default topic=' + defaulttopic + ''
  1525. print>>fp, 'Error log file=ErrorLog.log'
  1526. print>>fp, 'Index file=' + indexfile + ''
  1527. print>>fp, 'Title=' + title + ''
  1528. print>>fp, 'Display compile progress=Yes'
  1529. print>>fp, 'Full-text search=Yes'
  1530. print>>fp, 'Default window=main'
  1531. print>>fp, ''
  1532. print>>fp, '[WINDOWS]'
  1533. print>>fp, ('main=,"' + contentfile + '","' + indexfile
  1534. + '","","",,,,,0x23520,222,0x1046,[10,10,780,560],'
  1535. '0xB0000,,,,,,0')
  1536. print>>fp, ''
  1537. print>>fp, '[FILES]'
  1538. print>>fp, ''
  1539. self.dumpfiles(fp)
  1540. fp.close()
  1541. except IOError, msg:
  1542. print projectfile, ':', msg
  1543. sys.exit(1)
  1544. # CONTENT FILE
  1545. try:
  1546. fp = open(contentfile,'w')
  1547. print>>fp, '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">'
  1548. print>>fp, '<!-- This file defines the table of contents -->'
  1549. print>>fp, '<HTML>'
  1550. print>>fp, '<HEAD>'
  1551. print>>fp, ('<meta name="GENERATOR"'
  1552. 'content="Microsoft&reg; HTML Help Workshop 4.1">')
  1553. print>>fp, '<!-- Sitemap 1.0 -->'
  1554. print>>fp, '</HEAD>'
  1555. print>>fp, '<BODY>'
  1556. print>>fp, ' <OBJECT type="text/site properties">'
  1557. print>>fp, ' <param name="Window Styles" value="0x800025">'
  1558. print>>fp, ' <param name="comment" value="title:">'
  1559. print>>fp, ' <param name="comment" value="base:">'
  1560. print>>fp, ' </OBJECT>'
  1561. self.dumpnodes(fp)
  1562. print>>fp, '</BODY>'
  1563. print>>fp, '</HTML>'
  1564. fp.close()
  1565. except IOError, msg:
  1566. print contentfile, ':', msg
  1567. sys.exit(1)
  1568. # INDEX FILE
  1569. try:
  1570. fp = open(indexfile ,'w')
  1571. print>>fp, '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">'
  1572. print>>fp, '<!-- This file defines the index -->'
  1573. print>>fp, '<HTML>'
  1574. print>>fp, '<HEAD>'
  1575. print>>fp, ('<meta name="GENERATOR"'
  1576. 'content="Microsoft&reg; HTML Help Workshop 4.1">')
  1577. print>>fp, '<!-- Sitemap 1.0 -->'
  1578. print>>fp, '</HEAD>'
  1579. print>>fp, '<BODY>'
  1580. print>>fp, '<OBJECT type="text/site properties">'
  1581. print>>fp, '</OBJECT>'
  1582. self.dumpindex(fp)
  1583. print>>fp, '</BODY>'
  1584. print>>fp, '</HTML>'
  1585. fp.close()
  1586. except IOError, msg:
  1587. print indexfile , ':', msg
  1588. sys.exit(1)
  1589. def dumpfiles(self, outfile=sys.stdout):
  1590. filelist = self.filenames.values()
  1591. filelist.sort()
  1592. for filename in filelist:
  1593. print>>outfile, filename
  1594. def dumpnodes(self, outfile=sys.stdout):
  1595. self.dumped = {}
  1596. if self.nodelist:
  1597. nodename, dummy, dummy, dummy, dummy = self.nodelist[0]
  1598. self.topnode = nodename
  1599. print>>outfile, '<UL>'
  1600. for node in self.nodelist:
  1601. self.dumpnode(node,0,outfile)
  1602. print>>outfile, '</UL>'
  1603. def dumpnode(self, node, indent=0, outfile=sys.stdout):
  1604. if node:
  1605. # Retrieve info for this node
  1606. (nodename,next,prev,up,filename) = node
  1607. self.current = nodename
  1608. # Have we been dumped already?
  1609. if self.dumped.has_key(nodename):
  1610. return
  1611. self.dumped[nodename] = 1
  1612. # Print info for this node
  1613. print>>outfile, ' '*indent,
  1614. print>>outfile, '<LI><OBJECT type="text/sitemap">',
  1615. print>>outfile, '<param name="Name" value="' + nodename +'">',
  1616. print>>outfile, '<param name="Local" value="'+ filename +'">',
  1617. print>>outfile, '</OBJECT>'
  1618. # Does this node have menu items?
  1619. try:
  1620. menu = self.menudict[nodename]
  1621. self.dumpmenu(menu,indent+2,outfile)
  1622. except KeyError:
  1623. pass
  1624. def dumpmenu(self, menu, indent=0, outfile=sys.stdout):
  1625. if menu:
  1626. currentnode = self.current
  1627. if currentnode != self.topnode: # XXX this is a hack
  1628. print>>outfile, ' '*indent + '<UL>'
  1629. indent += 2
  1630. for item in menu:
  1631. menunode = self.getnode(item)
  1632. self.dumpnode(menunode,indent,outfile)
  1633. if currentnode != self.topnode: # XXX this is a hack
  1634. print>>outfile, ' '*indent + '</UL>'
  1635. indent -= 2
  1636. def getnode(self, nodename):
  1637. try:
  1638. index = self.nodeindex[nodename]
  1639. return self.nodelist[index]
  1640. except KeyError:
  1641. return None
  1642. except IndexError:
  1643. return None
  1644. # (args,nodename) == (key,location)
  1645. def dumpindex(self, outfile=sys.stdout):
  1646. print>>outfile, '<UL>'
  1647. for (key,location) in self.indexlist:
  1648. key = self.codeexpand(key)
  1649. location = makefile(location)
  1650. location = self.dirname + '/' + location
  1651. print>>outfile, '<LI><OBJECT type="text/sitemap">',
  1652. print>>outfile, '<param name="Name" value="' + key + '">',
  1653. print>>outfile, '<param name="Local" value="' + location + '">',
  1654. print>>outfile, '</OBJECT>'
  1655. print>>outfile, '</UL>'
  1656. def codeexpand(self, line):
  1657. co = self.codeprog.match(line)
  1658. if not co:
  1659. return line
  1660. bgn, end = co.span(0)
  1661. a, b = co.span(1)
  1662. line = line[:bgn] + line[a:b] + line[end:]
  1663. return line
  1664. # Put @var{} around alphabetic substrings
  1665. def makevar(str):
  1666. return '@var{'+str+'}'
  1667. # Split a string in "words" according to findwordend
  1668. def splitwords(str, minlength):
  1669. words = []
  1670. i = 0
  1671. n = len(str)
  1672. while i < n:
  1673. while i < n and str[i] in ' \t\n': i = i+1
  1674. if i >= n: break
  1675. start = i
  1676. i = findwordend(str, i, n)
  1677. words.append(str[start:i])
  1678. while len(words) < minlength: words.append('')
  1679. return words
  1680. # Find the end of a "word", matching braces and interpreting @@ @{ @}
  1681. fwprog = re.compile('[@{} ]')
  1682. def findwordend(str, i, n):
  1683. level = 0
  1684. while i < n:
  1685. mo = fwprog.search(str, i)
  1686. if not mo:
  1687. break
  1688. i = mo.start()
  1689. c = str[i]; i = i+1
  1690. if c == '@': i = i+1 # Next character is not special
  1691. elif c == '{': level = level+1
  1692. elif c == '}': level = level-1
  1693. elif c == ' ' and level <= 0: return i-1
  1694. return n
  1695. # Convert a node name into a file name
  1696. def makefile(nodename):
  1697. nodename = nodename.strip()
  1698. return fixfunnychars(nodename) + '.html'
  1699. # Characters that are perfectly safe in filenames and hyperlinks
  1700. goodchars = string.ascii_letters + string.digits + '!@-=+.'
  1701. # Replace characters that aren't perfectly safe by dashes
  1702. # Underscores are bad since Cern HTTPD treats them as delimiters for
  1703. # encoding times, so you get mismatches if you compress your files:
  1704. # a.html.gz will map to a_b.html.gz
  1705. def fixfunnychars(addr):
  1706. i = 0
  1707. while i < len(addr):
  1708. c = addr[i]
  1709. if c not in goodchars:
  1710. c = '-'
  1711. addr = addr[:i] + c + addr[i+1:]
  1712. i = i + len(c)
  1713. return addr
  1714. # Increment a string used as an enumeration
  1715. def increment(s):
  1716. if not s:
  1717. return '1'
  1718. for sequence in string.digits, string.lowercase, string.uppercase:
  1719. lastc = s[-1]
  1720. if lastc in sequence:
  1721. i = sequence.index(lastc) + 1
  1722. if i >= len(sequence):
  1723. if len(s) == 1:
  1724. s = sequence[0]*2
  1725. if s == '00':
  1726. s = '10'
  1727. else:
  1728. s = increment(s[:-1]) + sequence[0]
  1729. else:
  1730. s = s[:-1] + sequence[i]
  1731. return s
  1732. return s # Don't increment
  1733. def test():
  1734. import sys
  1735. debugging = 0
  1736. print_headers = 0
  1737. cont = 0
  1738. html3 = 0
  1739. htmlhelp = ''
  1740. while sys.argv[1] == ['-d']:
  1741. debugging = debugging + 1
  1742. del sys.argv[1]
  1743. if sys.argv[1] == '-p':
  1744. print_headers = 1
  1745. del sys.argv[1]
  1746. if sys.argv[1] == '-c':
  1747. cont = 1
  1748. del sys.argv[1]
  1749. if sys.argv[1] == '-3':
  1750. html3 = 1
  1751. del sys.argv[1]
  1752. if sys.argv[1] == '-H':
  1753. helpbase = sys.argv[2]
  1754. del sys.argv[1:3]
  1755. if len(sys.argv) <> 3:
  1756. print 'usage: texi2hh [-d [-d]] [-p] [-c] [-3] [-H htmlhelp]', \
  1757. 'inputfile outputdirectory'
  1758. sys.exit(2)
  1759. if html3:
  1760. parser = TexinfoParserHTML3()
  1761. else:
  1762. parser = TexinfoParser()
  1763. parser.cont = cont
  1764. parser.debugging = debugging
  1765. parser.print_headers = print_headers
  1766. file = sys.argv[1]
  1767. dirname = sys.argv[2]
  1768. parser.setdirname(dirname)
  1769. parser.setincludedir(os.path.dirname(file))
  1770. htmlhelp = HTMLHelp(helpbase, dirname)
  1771. parser.sethtmlhelp(htmlhelp)
  1772. try:
  1773. fp = open(file, 'r')
  1774. except IOError, msg:
  1775. print file, ':', msg
  1776. sys.exit(1)
  1777. parser.parse(fp)
  1778. fp.close()
  1779. parser.report()
  1780. htmlhelp.finalize()
  1781. if __name__ == "__main__":
  1782. test()