GIF89a;
# 1. BUGFIX: In function makefile(), strip blanks from the nodename. # This is necessary to match the behavior of parser.makeref() and # parser.do_node(). # 2. BUGFIX fixed KeyError in end_ifset (well, I may have just made # it go away, rather than fix it) # 3. BUGFIX allow @menu and menu items inside @ifset or @ifclear # 4. Support added for: # @uref URL reference # @image image file reference (see note below) # @multitable output an HTML table # @vtable # 5. Partial support for accents, to match MAKEINFO output # 6. I added a new command-line option, '-H basename', to specify # HTML Help output. This will cause three files to be created # in the current directory: # `basename`.hhp HTML Help Workshop project file # `basename`.hhc Contents file for the project # `basename`.hhk Index file for the project # When fed into HTML Help Workshop, the resulting file will be # named `basename`.chm. # 7. A new class, HTMLHelp, to accomplish item 6. # 8. Various calls to HTMLHelp functions. # A NOTE ON IMAGES: Just as 'outputdirectory' must exist before # running this program, all referenced images must already exist # in outputdirectory. import os import sys import string import re MAGIC = '\\input texinfo' cmprog = re.compile('^@([a-z]+)([ \t]|$)') # Command (line-oriented) blprog = re.compile('^[ \t]*$') # Blank line kwprog = re.compile('@[a-z]+') # Keyword (embedded, usually # with {} args) spprog = re.compile('[\n@{}&<>]') # Special characters in # running text # # menu item (Yuck!) miprog = re.compile('^\* ([^:]*):(:|[ \t]*([^\t,\n.]+)([^ \t\n]*))[ \t\n]*') # 0 1 1 2 3 34 42 0 # ----- ---------- --------- # -|----------------------------- # ----------------------------------------------------- class HTMLNode: """Some of the parser's functionality is separated into this class. A Node accumulates its contents, takes care of links to other Nodes and saves itself when it is finished and all links are resolved. """ DOCTYPE = '' type = 0 cont = '' epilogue = '\n' def __init__(self, dir, name, topname, title, next, prev, up): self.dirname = dir self.name = name if topname: self.topname = topname else: self.topname = name self.title = title self.next = next self.prev = prev self.up = up self.lines = [] def write(self, *lines): map(self.lines.append, lines) def flush(self): fp = open(self.dirname + '/' + makefile(self.name), 'w') fp.write(self.prologue) fp.write(self.text) fp.write(self.epilogue) fp.close() def link(self, label, nodename, rel=None, rev=None): if nodename: if nodename.lower() == '(dir)': addr = '../dir.html' title = '' else: addr = makefile(nodename) title = ' TITLE="%s"' % nodename self.write(label, ': ', nodename, ' \n') def finalize(self): length = len(self.lines) self.text = ''.join(self.lines) self.lines = [] self.open_links() self.output_links() self.close_links() links = ''.join(self.lines) self.lines = [] self.prologue = ( self.DOCTYPE + '\n
\n' ' \n' '\n%s\n' % links def open_links(self): self.write('
\n' FN_HEADER = '\n
\n
' Node = HTMLNode # Initialize an instance def __init__(self): self.unknown = {} # statistics about unknown @-commands self.filenames = {} # Check for identical filenames self.debugging = 0 # larger values produce more output self.print_headers = 0 # always print headers? self.nodefp = None # open file we're writing to self.nodelineno = 0 # Linenumber relative to node self.links = None # Links from current node self.savetext = None # If not None, save text head instead self.savestack = [] # If not None, save text head instead self.htmlhelp = None # html help data self.dirname = 'tmp' # directory where files are created self.includedir = '.' # directory to search @include files self.nodename = '' # name of current node self.topname = '' # name of top node (first node seen) self.title = '' # title of this whole Texinfo tree self.resetindex() # Reset all indices self.contents = [] # Reset table of contents self.numbering = [] # Reset section numbering counters self.nofill = 0 # Normal operation: fill paragraphs self.values={'html': 1} # Names that should be parsed in ifset self.stackinfo={} # Keep track of state in the stack # XXX The following should be reset per node?! self.footnotes = [] # Reset list of footnotes self.itemarg = None # Reset command used by @item self.itemnumber = None # Reset number for @item in @enumerate self.itemindex = None # Reset item index name self.node = None self.nodestack = [] self.cont = 0 self.includedepth = 0 # Set htmlhelp helper class def sethtmlhelp(self, htmlhelp): self.htmlhelp = htmlhelp # Set (output) directory name def setdirname(self, dirname): self.dirname = dirname # Set include directory name def setincludedir(self, includedir): self.includedir = includedir # Parse the contents of an entire file def parse(self, fp): line = fp.readline() lineno = 1 while line and (line[0] == '%' or blprog.match(line)): line = fp.readline() lineno = lineno + 1 if line[:len(MAGIC)] <> MAGIC: raise SyntaxError, 'file does not begin with %r' % (MAGIC,) self.parserest(fp, lineno) # Parse the contents of a file, not expecting a MAGIC header def parserest(self, fp, initial_lineno): lineno = initial_lineno self.done = 0 self.skip = 0 self.stack = [] accu = [] while not self.done: line = fp.readline() self.nodelineno = self.nodelineno + 1 if not line: if accu: if not self.skip: self.process(accu) accu = [] if initial_lineno > 0: print '*** EOF before @bye' break lineno = lineno + 1 mo = cmprog.match(line) if mo: a, b = mo.span(1) cmd = line[a:b] if cmd in ('noindent', 'refill'): accu.append(line) else: if accu: if not self.skip: self.process(accu) accu = [] self.command(line, mo) elif blprog.match(line) and \ 'format' not in self.stack and \ 'example' not in self.stack: if accu: if not self.skip: self.process(accu) if self.nofill: self.write('\n') else: self.write('
\n') accu = [] else: # Append the line including trailing \n! accu.append(line) # if self.skip: print '*** Still skipping at the end' if self.stack: print '*** Stack not empty at the end' print '***', self.stack if self.includedepth == 0: while self.nodestack: self.nodestack[-1].finalize() self.nodestack[-1].flush() del self.nodestack[-1] # Start saving text in a buffer instead of writing it to a file def startsaving(self): if self.savetext <> None: self.savestack.append(self.savetext) # print '*** Recursively saving text, expect trouble' self.savetext = '' # Return the text saved so far and start writing to file again def collectsavings(self): savetext = self.savetext if len(self.savestack) > 0: self.savetext = self.savestack[-1] del self.savestack[-1] else: self.savetext = None return savetext or '' # Write text to file, or save it in a buffer, or ignore it def write(self, *args): try: text = ''.join(args) except: print args raise TypeError if self.savetext <> None: self.savetext = self.savetext + text elif self.nodefp: self.nodefp.write(text) elif self.node: self.node.write(text) # Complete the current node -- write footnotes and close file def endnode(self): if self.savetext <> None: print '*** Still saving text at end of node' dummy = self.collectsavings() if self.footnotes: self.writefootnotes() if self.nodefp: if self.nodelineno > 20: self.write('