root/trunk/bknr/tools/pbook.py

Revision 1711, 14.9 kB (checked in by manuel, 4 years ago)

neues pbook.py, damit geht auch das klammerscript manual durch

  • Property svn:executable set to *
Line 
1 #! /usr/bin/env python
2
3 import re
4 import tempfile
5 import os, getopt, sys, shutil, random
6 from os.path import splitext, basename
7
8 class TxtFile:
9     def __init__(self, title, author = None, style = None, includeToc = None):
10         self.title = title
11         self.author = author
12         self.buffer = ""
13
14     def reset(self):
15         self.buffer = ""
16
17     def __add__(self, aStr):
18         self.buffer += aStr
19         return self
20
21     def tempFile(self):
22         return tempfile.NamedTemporaryFile('w+', -1, '.txt', 'pbook')
23    
24     def writeFile(self, fileName = None):
25         if not fileName:
26             file = self.tempFile()
27         elif fileName == "-":
28             file = sys.stdout
29         else:
30             name,ext = splitext(fileName)
31             if ext == "":
32                 ext = ".txt"
33             elif ext != ".txt":
34                 raise "Can not write format " + ext
35             file = open(name + ext, "w+")
36         file.write(self.buffer)
37         file.flush()
38         return file
39
40     def addEscape(self, escape, fileName, line):
41         return
42     def addHeading(self, level, heading, fileName, line):
43         heading = re.sub("\s+", " ", heading)
44         self += "++ " + heading + "\n"
45     def addComment(self, comment, fileName, startLine, endLine):
46         self += comment
47     def addFigure(self, figureFile, figureScale, figureName, fileName, endLine):
48         self += "            " + figureName + " (" + figureFile + ")" + "\n"
49     def addCode(self, code, fileName, startLine, endLine):
50         code = code.rstrip()
51         code = re.sub("\t", "   ", code)
52         self += "\n== %s (%s:%s) ================\n" % (basename(fileName), startLine, endLine)
53         self += code
54         self += "\n=========================================================\n\n"
55
56 class TexFile(TxtFile):
57     def __init__(self, title, author = None, style = "article", includeToc = True):
58         TxtFile.__init__(self, title, author, style, includeToc)
59         self.style = style
60         self.includeToc = includeToc
61         self.bookSectioningCommands = ("chapter", "section", \
62                                        "subsection", "subsubsection")
63         self.articleSectioningCommands = ("section", "subsection", \
64                                           "subsubsection")
65
66     def beginning(self):
67         return '\n\\documentclass[notitlepage,a4paper,makeidx]{' + self.style + '}\n' + \
68                '\\usepackage{fancyvrb,color,palatino,makeidx}\n' + \
69                "\\newif\\ifpdf\n\\ifx\\pdfoutput\\undefined\n\\pdffalse\n" + \
70                "\\else\n\\pdfoutput=1\n\\pdftrue\n\\fi\n" + \
71                "\\ifpdf\n\\usepackage[pdftex]{graphicx}\n" + \
72                "\\else\n\\usepackage{graphicx}\n\\fi\n" + \
73                '\\definecolor{gray}{gray}{0.6}\n' + \
74                '\\title{' + TexFile.escapeString(self.title) + '}\n' +  \
75                (self.author and ('\\author{' + self.author + '}\n') or '') + \
76                '\\makeindex' + \
77                '\\begin{document}\n\\maketitle\n' + \
78                (self.includeToc and '\\tableofcontents\n' or '')
79     def ending(self):
80         return '\\printindex\n\\end{document}\n'
81     def sectioningCommand(self, level):
82         if self.style == "article":
83             return self.articleSectioningCommands[min(level, len(self.articleSectioningCommands))]
84         elif self.style == "book":
85             return self.bookSectioningCommands[min(level, len(self.bookSectioningCommands))]
86    
87     def escapeString(aStr):
88         aStr = re.sub("\\\\", "$\\\\backslash$", aStr)
89         def escapeRepl(match):
90             if match.group(1) != '$' or \
91                not (aStr[match.start():].startswith("$\\backslash$") or \
92                     aStr[:match.start()].endswith("$\\backslash")):
93                 return '\\' + match.group(1)
94             else:
95                 return match.group(0)
96         return re.sub("([#%&~$_^{}])", escapeRepl, aStr)
97     escapeString = staticmethod(escapeString)
98    
99     def tempFile(self):
100         return tempfile.NamedTemporaryFile('w+', -1, '.tex', 'pbook')
101     def writeFile(self, fileName = None):
102         if not fileName:
103             file = self.tempFile()
104         elif fileName == "-":
105             return self.writeTex(sys.stdout)
106         else:
107             name,ext = splitext(fileName)
108             if ext == "":
109                 ext = ".pdf"
110             file = open(name + ext, "w+")
111         name,ext = splitext(file.name)
112         if ext == ".tex":
113             return self.writeTex(file)
114         elif ext == ".pdf":
115             return self.writePdf(file)
116         else:
117             raise "Can not write format " + ext
118
119     def writeTex(self, output):
120         output.write(self.beginning())
121         output.write(self.buffer)
122         output.write(self.ending())
123         output.flush()
124         return output
125
126     def writePdf(self, output):
127         tmpfile = self.tempFile()
128         self.writeTex(tmpfile)
129         (dir, name) = os.path.split(tmpfile.name)
130         print "cd " + dir + "; latex " + name + " && pdflatex " + name
131         os.system("cd " + dir + "; latex " + name + " && pdflatex " + name)
132         tmpfile.close()
133         pdfname = splitext(tmpfile.name)[0] + ".pdf"
134         shutil.copyfile(pdfname, output.name)
135         os.remove(pdfname)
136         return output
137
138     def addEscape(self, escape, fileName, line):
139         self += escape + "\n"
140     def addFigure(self, figureFile, figureScale, figureName, fileName, endLine):
141         self += "\\begin{figure}[htbp]\n  \\centering\n"
142         self += "  \\fbox{\\includegraphics[scale=" + figureScale + "]{" + figureFile + "}}\n"
143         self += "  \\caption{" + figureName + "}\n"
144         self += "\\end{figure}\n"
145     def addHeading(self, level, heading, fileName, line):
146         heading = re.sub("\s+", " ", heading)
147         self += "\n\n\\" + self.sectioningCommand(level) + "{" + \
148                 TexFile.escapeString(heading) + "}\n"
149     def addComment(self, comment, fileName, startLine, endLine):
150         comment = TexFile.escapeString(comment)
151         comment = re.sub("`([^`']*)'", "{\\\\tt \\1}", comment)
152         self += re.sub("\"([^\"]*)\"", "``\\1''", comment)
153     def addCode(self, code, fileName, startLine, endLine):
154         code = code.rstrip()
155         code = re.sub("\\\\end{Verbatim}", "\\\\_end{Verbatim}", code)
156         code = re.sub("\t", "   ", code)
157         self += "\n\\begin{Verbatim}[fontsize=\\small,frame=leftline,framerule=0.9mm," + \
158                 "rulecolor=\\color{gray},framesep=5.1mm,xleftmargin=5mm,fontfamily=cmtt]\n"
159         self += code
160         self +=  "\n\\end{Verbatim}\n"
161
162 class IdqTexFile(TexFile):
163     def __init__(self, title, author = "id Quantique", style = "article", includeToc = True):
164         TexFile.__init__(self, title, author, style, includeToc)
165
166 class BknrTexFile(TexFile):
167     def __init__(self, title, author, style, includeToc):
168         TexFile.__init__(self, title, author, style, includeToc)
169         self.firstSection = True
170     def beginning(self):
171         return '\\chapter{' + TexFile.escapeString(self.title) + '}\n'
172     def ending(self):
173         return ''
174     def addComment(self, comment, fileName, startLine, endLine):
175         comment = TexFile.escapeString(comment)
176         self += re.sub("\"([^\"]*)\"", "``\\1''", comment)
177     def sectioningCommand(self, level):
178         string = ""
179         if level == 0:
180             if self.firstSection == False:
181                 string = ""
182 #                string = "vbox{\n\\vspace{1cm}\n\\centering\n" + \
183 #                         "\\includegraphics[scale=0.6]{peecol" + \
184 #                         str(random.randint(1, 10) ) +  "}}\n\n\\"
185             else:
186                 self.firstSection = False
187         if self.style == "article":
188             return string + self.articleSectioningCommands[min(level, len(self.articleSectioningCommands))]
189         elif self.style == "book":
190             return string + self.bookSectioningCommands[min(level, len(self.bookSectioningCommands))]
191
192 class Pbook:
193     def __init__(self, files, outFile):
194         self.files = files
195         self.commentRe = None
196         self.headingRe = None
197         self.removeRe = None
198         self.outFile = outFile
199         self.lineCounter = 0
200         if not self.outFile.title: self.outFile.title = basename(file)
201
202     def formatBuffer(self):
203         self.outFile.reset()
204         self.lineCounter = 0
205         for file in self.files:
206             data = open(file, "r").read()
207             if self.removeRe:
208                 data = self.removeRe.sub("", data)
209             # search the first heading
210             startMatch = self.headingRe.search(data)
211             if not startMatch:
212                 raise "File must have at least one heading"
213             self.lineCounter += len(data[:startMatch.start()].split('\n'))
214             data = data[startMatch.start():]
215             self.fileName = file
216
217             lines = data.split('\n')
218             while len(lines) > 0:
219                 line = lines[0]
220                 if re.match("^\s*$", line):
221                     lines.pop(0)
222                     self.lineCounter += 1
223                     continue
224                 elif self.figureRe.match(line):
225                     line = lines.pop(0)
226                     self.doFigure(line)
227                     self.lineCounter += 1
228                 elif self.escapeRe.match(line):
229                     line = lines.pop(0)
230                     self.doEscape(line)
231                     self.lineCounter += 1
232                 elif self.headingRe.match(line):
233                     line = lines.pop(0)
234                     self.doHeading(line)
235                     self.lineCounter += 1
236                 elif self.commentRe.match(line):
237                     self.doComment(lines)
238                 else:
239                     self.doCode(lines)
240
241     def doHeading(self, line):
242         match = self.headingRe.match(line)
243         assert(match != None)
244         level = len(match.group(1)) - 1
245         headingName = line[match.end():]
246         self.outFile.addHeading(level, headingName, self.fileName, self.lineCounter)
247
248     def doFigure(self, line):
249         match = self.figureRe.match(line)
250         assert(match != None)
251         figureFile = match.group(1)
252         figureName = match.group(3)
253         figureScale = match.group(2)
254         self.outFile.addFigure(figureFile, figureScale, figureName, self.fileName, self.lineCounter)
255
256     def doEscape(self, line):
257         match = self.escapeRe.match(line)
258         assert(match != None)
259         escape = match.group(1)
260         self.outFile.addEscape(escape, self.fileName, self.lineCounter)
261
262     def doComment(self, lines):
263         comment = ""
264         lineCount = 0
265         while len(lines) > 0:
266             line = lines[0]
267             match = self.commentRe.match(line)
268             if not match: break
269             line = lines.pop(0)
270             lineCount += 1
271             comment += line[:match.start()] + line[match.end():] + "\n"
272         self.outFile.addComment(comment, self.fileName, self.lineCounter, self.lineCounter + lineCount)
273         self.lineCounter += lineCount
274
275     def doCode(self, lines):
276         lineCount = 0
277         code = ""
278         while len(lines) > 0:
279             line = lines[0]
280             if (self.headingRe.match(line) or self.escapeRe.match(line) \
281                                            or self.figureRe.match(line) \
282                                            or self.commentRe.match(line)):
283                 break
284             line = lines.pop(0)
285             lineCount += 1
286             code += line + "\n"
287         self.outFile.addCode(code, self.fileName, self.lineCounter, self.lineCounter + lineCount)
288         self.lineCounter += lineCount
289
290     def makeFile(self, fileName):
291         self.outFile.reset()
292         self.formatBuffer()
293         return self.outFile.writeFile(fileName)
294    
295 class LispPbook(Pbook):
296     def __init__(self, files, outFile):
297         Pbook.__init__(self, files, outFile)
298         self.commentRe = re.compile('^;;;($|[^#f])', re.M)
299         self.headingRe = re.compile('^;;;(#+)', re.M)
300         self.figureRe = re.compile('^;;;f\s+\"(.+)\"\s+([^\s]+)\s+(.*)', re.M)
301         self.escapeRe = re.compile('^;;;t\s+(.+)', re.M)
302
303 class CPbook(Pbook):
304     def __init__(self, files, outFile):
305         Pbook.__init__(self, files, outFile)
306         self.commentRe = re.compile('^(\s|/)*\*\*($|[^f#/])', re.M);
307         self.headingRe = re.compile("^/\*\*(#+)", re.M)
308         self.removeRe = re.compile('\*\*+/', re.M)
309         self.figureRe = re.compile('^/\*\*f \"(.+)\"\s+([^\s]+)\s(.*)', re.M)
310
311
312 def usage():
313     print "Usage: ", sys.argv[0], " [-h] [-c TexFile|BknrTexFile|IdqTexFile|TxtFile] ", \
314           "[-T C|Lisp] [-t title] [-a author] [-O] [-o output] [-s style] file ..."
315
316 def extToType(ext):
317     fileExtToType = ( ((".c", ".cpp", ".C", ".h"), CPbook),
318                       ((".lisp", ".el", ".l", ".cl"), LispPbook) )
319     for types, typeClass in fileExtToType:
320         if (ext in types):
321             return typeClass
322     return None
323
324 def main():
325     texClass = TexFile
326     type = None
327     output = None
328     (author, title, toc, style) = (None, None, True, "article")
329     try:
330         opts, args = getopt.getopt(sys.argv[1:], "hc:T:t:a:Oo:s:")
331         if not args:
332             raise getopt.error, "At least one file argument required"
333         for optname, optvalue in opts:
334             if optname == "-h":
335                 usage()
336                 return
337             elif optname == "-c":
338                 if optvalue == "TexFile":
339                     texClass = TexFile
340                 elif optvalue == "IdqTexFile":
341                     texClass = IdqTexFile
342                 elif optvalue == "BknrTexFile":
343                     texClass = BknrTexFile
344                 elif optvalue == "TxtFile":
345                     texClass = TxtFile
346                 else:
347                     raise getopt.error, "Unknown TexFile class ", optvalue
348             elif optname == "-t":
349                 title = optvalue
350             elif optname == "-a":
351                 author = optvalue
352             elif optname == "-O":
353                 toc = False
354             elif optname == "-s":
355                 style = optvalue
356             elif optname == "-T":
357                 if optvalue == "C":
358                     type = CPbook
359                 elif optvalue == "Lisp":
360                     type = LispPbook
361                 else:
362                     raise getopt.error, "Unknown pbook file type ", optvalue
363             elif optname == "-o":
364                 output = optvalue
365     except getopt.error, msg:
366         print msg
367         usage()
368         return 1
369     file = args[0]
370     name,ext = splitext(file)
371     if not title:
372         title = basename(name)
373     if not type:
374         type = extToType(ext)
375         if not type:
376             print "Could not get type for ", ext
377             return 2
378     pbook = type(args, texClass(title, author, style,