[Added the pbook.py file used to generate the documentation Marco Baringer **20050813133732] { addfile ./pbook.py hunk ./pbook.py 1 +#! /usr/bin/env python + +import re +import tempfile +import os, getopt, sys, shutil, random +from os.path import splitext, basename + +class TxtFile: + def __init__(self, title, author = None, style = None, includeToc = None): + self.title = title + self.author = author + self.buffer = "" + + def reset(self): + self.buffer = "" + + def __add__(self, aStr): + self.buffer += aStr + return self + + def tempFile(self): + return tempfile.NamedTemporaryFile('w+', -1, '.txt', 'pbook') + + def writeFile(self, fileName = None): + if not fileName: + file = self.tempFile() + elif fileName == "-": + file = sys.stdout + else: + name,ext = splitext(fileName) + if ext == "": + ext = ".txt" + elif ext != ".txt": + raise "Can not write format " + ext + file = open(name + ext, "w+") + file.write(self.buffer) + file.flush() + return file + + def addEscape(self, escape, fileName, line): + return + def addHeading(self, level, heading, fileName, line): + heading = re.sub("\s+", " ", heading) + self += "++ " + heading + "\n" + def addComment(self, comment, fileName, startLine, endLine): + self += comment + def addFigure(self, figureFile, figureScale, figureName, fileName, endLine): + self += " " + figureName + " (" + figureFile + ")" + "\n" + def addCode(self, code, fileName, startLine, endLine): + code = code.rstrip() + code = re.sub("\t", " ", code) + self += "\n== %s (%s:%s) ================\n" % (basename(fileName), startLine, endLine) + self += code + self += "\n=========================================================\n\n" + +class TexFile(TxtFile): + def __init__(self, title, author = None, style = "article", includeToc = True): + TxtFile.__init__(self, title, author, style, includeToc) + self.style = style + self.includeToc = includeToc + self.bookSectioningCommands = ("chapter", "section", \ + "subsection", "subsubsection") + self.articleSectioningCommands = ("section", "subsection", \ + "subsubsection") + + def beginning(self): + return '\n\\documentclass[notitlepage,a4paper,makeidx]{' + self.style + '}\n' + \ + '\\usepackage{fancyvrb,color,palatino,makeidx}\n' + \ + "\\newif\\ifpdf\n\\ifx\\pdfoutput\\undefined\n\\pdffalse\n" + \ + "\\else\n\\pdfoutput=1\n\\pdftrue\n\\fi\n" + \ + "\\ifpdf\n\\usepackage[pdftex]{graphicx}\n" + \ + "\\else\n\\usepackage{graphicx}\n\\fi\n" + \ + '\\definecolor{gray}{gray}{0.6}\n' + \ + '\\title{' + TexFile.escapeString(self.title) + '}\n' + \ + (self.author and ('\\author{' + self.author + '}\n') or '') + \ + '\\makeindex' + \ + '\\begin{document}\n\\maketitle\n' + \ + (self.includeToc and '\\tableofcontents\n' or '') + def ending(self): + return '\\printindex\n\\end{document}\n' + def sectioningCommand(self, level): + if self.style == "article": + return self.articleSectioningCommands[min(level, len(self.articleSectioningCommands))] + elif self.style == "book": + return self.bookSectioningCommands[min(level, len(self.bookSectioningCommands))] + + def escapeString(aStr): + aStr = re.sub("\\\\", "$\\\\backslash$", aStr) + def escapeRepl(match): + if match.group(1) != '$' or \ + not (aStr[match.start():].startswith("$\\backslash$") or \ + aStr[:match.start()].endswith("$\\backslash")): + return '\\' + match.group(1) + else: + return match.group(0) + return re.sub("([#%&~$_^{}])", escapeRepl, aStr) + escapeString = staticmethod(escapeString) + + def tempFile(self): + return tempfile.NamedTemporaryFile('w+', -1, '.tex', 'pbook') + def writeFile(self, fileName = None): + if not fileName: + file = self.tempFile() + elif fileName == "-": + return self.writeTex(sys.stdout) + else: + name,ext = splitext(fileName) + if ext == "": + ext = ".pdf" + file = open(name + ext, "w+") + name,ext = splitext(file.name) + if ext == ".tex": + return self.writeTex(file) + elif ext == ".pdf": + return self.writePdf(file) + else: + raise "Can not write format " + ext + + def writeTex(self, output): + output.write(self.beginning()) + output.write(self.buffer) + output.write(self.ending()) + output.flush() + return output + + def writePdf(self, output): + tmpfile = self.tempFile() + self.writeTex(tmpfile) + (dir, name) = os.path.split(tmpfile.name) + print "cd " + dir + "; latex " + name + " && pdflatex " + name + os.system("cd " + dir + "; latex " + name + " && pdflatex " + name) + tmpfile.close() + pdfname = splitext(tmpfile.name)[0] + ".pdf" + shutil.copyfile(pdfname, output.name) + os.remove(pdfname) + return output + + def addEscape(self, escape, fileName, line): + self += escape + "\n" + def addFigure(self, figureFile, figureScale, figureName, fileName, endLine): + self += "\\begin{figure}[htbp]\n \\centering\n" + self += " \\fbox{\\includegraphics[scale=" + figureScale + "]{" + figureFile + "}}\n" + self += " \\caption{" + figureName + "}\n" + self += "\\end{figure}\n" + def addHeading(self, level, heading, fileName, line): + heading = re.sub("\s+", " ", heading) + self += "\n\n\\" + self.sectioningCommand(level) + "{" + \ + TexFile.escapeString(heading) + "}\n" + def addComment(self, comment, fileName, startLine, endLine): + comment = TexFile.escapeString(comment) + comment = re.sub("`([^`']*)'", "{\\\\tt \\1}", comment) + self += re.sub("\"([^\"]*)\"", "``\\1''", comment) + def addCode(self, code, fileName, startLine, endLine): + code = code.rstrip() + code = re.sub("\\\\end{Verbatim}", "\\\\_end{Verbatim}", code) + code = re.sub("\t", " ", code) + self += "\n\\begin{Verbatim}[fontsize=\\small,frame=leftline,framerule=0.9mm," + \ + "rulecolor=\\color{gray},framesep=5.1mm,xleftmargin=5mm,fontfamily=cmtt]\n" + self += code + self += "\n\\end{Verbatim}\n" + +class IdqTexFile(TexFile): + def __init__(self, title, author = "id Quantique", style = "article", includeToc = True): + TexFile.__init__(self, title, author, style, includeToc) + +class BknrTexFile(TexFile): + def __init__(self, title, author, style, includeToc): + TexFile.__init__(self, title, author, style, includeToc) + self.firstSection = True + def beginning(self): + return '\\chapter{' + TexFile.escapeString(self.title) + '}\n' + def ending(self): + return '' + def addComment(self, comment, fileName, startLine, endLine): + comment = TexFile.escapeString(comment) + self += re.sub("\"([^\"]*)\"", "``\\1''", comment) + def sectioningCommand(self, level): + string = "" + if level == 0: + if self.firstSection == False: + string = "" +# string = "vbox{\n\\vspace{1cm}\n\\centering\n" + \ +# "\\includegraphics[scale=0.6]{peecol" + \ +# str(random.randint(1, 10) ) + "}}\n\n\\" + else: + self.firstSection = False + if self.style == "article": + return string + self.articleSectioningCommands[min(level, len(self.articleSectioningCommands))] + elif self.style == "book": + return string + self.bookSectioningCommands[min(level, len(self.bookSectioningCommands))] + +class Pbook: + def __init__(self, files, outFile): + self.files = files + self.commentRe = None + self.headingRe = None + self.removeRe = None + self.outFile = outFile + self.lineCounter = 0 + if not self.outFile.title: self.outFile.title = basename(file) + + def formatBuffer(self): + self.outFile.reset() + self.lineCounter = 0 + for file in self.files: + data = open(file, "r").read() + if self.removeRe: + data = self.removeRe.sub("", data) + # search the first heading + startMatch = self.headingRe.search(data) + if not startMatch: + raise "File must have at least one heading" + self.lineCounter += len(data[:startMatch.start()].split('\n')) + data = data[startMatch.start():] + self.fileName = file + + lines = data.split('\n') + while len(lines) > 0: + line = lines[0] + if re.match("^\s*$", line): + lines.pop(0) + self.lineCounter += 1 + continue + elif self.figureRe.match(line): + line = lines.pop(0) + self.doFigure(line) + self.lineCounter += 1 + elif self.escapeRe.match(line): + line = lines.pop(0) + self.doEscape(line) + self.lineCounter += 1 + elif self.headingRe.match(line): + line = lines.pop(0) + self.doHeading(line) + self.lineCounter += 1 + elif self.commentRe.match(line): + self.doComment(lines) + else: + self.doCode(lines) + + def doHeading(self, line): + match = self.headingRe.match(line) + assert(match != None) + level = len(match.group(1)) - 1 + headingName = line[match.end():] + self.outFile.addHeading(level, headingName, self.fileName, self.lineCounter) + + def doFigure(self, line): + match = self.figureRe.match(line) + assert(match != None) + figureFile = match.group(1) + figureName = match.group(3) + figureScale = match.group(2) + self.outFile.addFigure(figureFile, figureScale, figureName, self.fileName, self.lineCounter) + + def doEscape(self, line): + match = self.escapeRe.match(line) + assert(match != None) + escape = match.group(1) + self.outFile.addEscape(escape, self.fileName, self.lineCounter) + + def doComment(self, lines): + comment = "" + lineCount = 0 + while len(lines) > 0: + line = lines[0] + match = self.commentRe.match(line) + if not match: break + line = lines.pop(0) + lineCount += 1 + comment += line[:match.start()] + line[match.end():] + "\n" + self.outFile.addComment(comment, self.fileName, self.lineCounter, self.lineCounter + lineCount) + self.lineCounter += lineCount + + def doCode(self, lines): + lineCount = 0 + code = "" + while len(lines) > 0: + line = lines[0] + if (self.headingRe.match(line) or self.escapeRe.match(line) \ + or self.figureRe.match(line) \ + or self.commentRe.match(line)): + break + line = lines.pop(0) + lineCount += 1 + code += line + "\n" + self.outFile.addCode(code, self.fileName, self.lineCounter, self.lineCounter + lineCount) + self.lineCounter += lineCount + + def makeFile(self, fileName): + self.outFile.reset() + self.formatBuffer() + return self.outFile.writeFile(fileName) + +class LispPbook(Pbook): + def __init__(self, files, outFile): + Pbook.__init__(self, files, outFile) + self.commentRe = re.compile('^;;;($|[^#f])', re.M) + self.headingRe = re.compile('^;;;(#+)', re.M) + self.figureRe = re.compile('^;;;f\s+\"(.+)\"\s+([^\s]+)\s+(.*)', re.M) + self.escapeRe = re.compile('^;;;t\s+(.+)', re.M) + +class CPbook(Pbook): + def __init__(self, files, outFile): + Pbook.__init__(self, files, outFile) + self.commentRe = re.compile('^(\s|/)*\*\*($|[^f#/])', re.M); + self.headingRe = re.compile("^/\*\*(#+)", re.M) + self.removeRe = re.compile('\*\*+/', re.M) + self.figureRe = re.compile('^/\*\*f \"(.+)\"\s+([^\s]+)\s(.*)', re.M) + + +def usage(): + print "Usage: ", sys.argv[0], " [-h] [-c TexFile|BknrTexFile|IdqTexFile|TxtFile] ", \ + "[-T C|Lisp] [-t title] [-a author] [-O] [-o output] [-s style] file ..." + +def extToType(ext): + fileExtToType = ( ((".c", ".cpp", ".C", ".h"), CPbook), + ((".lisp", ".el", ".l", ".cl"), LispPbook) ) + for types, typeClass in fileExtToType: + if (ext in types): + return typeClass + return None + +def main(): + texClass = TexFile + type = None + output = None + (author, title, toc, style) = (None, None, True, "article") + try: + opts, args = getopt.getopt(sys.argv[1:], "hc:T:t:a:Oo:s:") + if not args: + raise getopt.error, "At least one file argument required" + for optname, optvalue in opts: + if optname == "-h": + usage() + return + elif optname == "-c": + if optvalue == "TexFile": + texClass = TexFile + elif optvalue == "IdqTexFile": + texClass = IdqTexFile + elif optvalue == "BknrTexFile": + texClass = BknrTexFile + elif optvalue == "TxtFile": + texClass = TxtFile + else: + raise getopt.error, "Unknown TexFile class ", optvalue + elif optname == "-t": + title = optvalue + elif optname == "-a": + author = optvalue + elif optname == "-O": + toc = False + elif optname == "-s": + style = optvalue + elif optname == "-T": + if optvalue == "C": + type = CPbook + elif optvalue == "Lisp": + type = LispPbook + else: + raise getopt.error, "Unknown pbook file type ", optvalue + elif optname == "-o": + output = optvalue + except getopt.error, msg: + print msg + usage() + return 1 + file = args[0] + name,ext = splitext(file) + if not title: + title = basename(name) + if not type: + type = extToType(ext) + if not type: + print "Could not get type for ", ext + return 2 + pbook = type(args, texClass(title, author, style, toc)) + if not output: + output = basename(name) + try: + file = pbook.makeFile(output) + if output != "-": + print "Wrote output to ", file.name + except IOError, (errno, strerror): + print "Caught an error while generating \"%s\": %s" % (output, strerror) + except: + print "Caught an error while generating \"%s\"" % (output) + return 1 + +if __name__ == "__main__": + sys.exit(main()) }