5 import os
, getopt
, sys
, shutil
, random
6 from os
.path
import splitext
, basename
9 def __init__(self
, title
, author
= None, style
= None, includeToc
= None):
17 def __add__(self
, aStr
):
22 return tempfile
.NamedTemporaryFile('w+', -1, '.txt', 'pbook')
24 def writeFile(self
, fileName
= None):
26 file = self
.tempFile()
30 name
,ext
= splitext(fileName
)
34 raise "Can not write format " + ext
35 file = open(name
+ ext
, "w+")
36 file.write(self
.buffer)
40 def addEscape(self
, escape
, fileName
, line
):
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
):
47 def addFigure(self
, figureFile
, figureScale
, figureName
, fileName
, endLine
):
48 self
+= " " + figureName
+ " (" + figureFile
+ ")" + "\n"
49 def addCode(self
, code
, fileName
, startLine
, endLine
):
51 code
= re
.sub("\t", " ", code
)
52 self
+= "\n== %s (%s:%s) ================\n" % (basename(fileName
), startLine
, endLine
)
54 self
+= "\n=========================================================\n\n"
56 class TexFile(TxtFile
):
57 def __init__(self
, title
, author
= None, style
= "article", includeToc
= True):
58 TxtFile
.__init
__(self
, title
, author
, style
, includeToc
)
60 self
.includeToc
= includeToc
61 self
.bookSectioningCommands
= ("chapter", "section", \
62 "subsection", "subsubsection")
63 self
.articleSectioningCommands
= ("section", "subsection", \
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 '') + \
77 '\\begin{document}\n\\maketitle\n' + \
78 (self
.includeToc
and '\\tableofcontents\n' or '')
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
))]
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)
96 return re
.sub("([#%&~$_^{}])", escapeRepl
, aStr
)
97 escapeString
= staticmethod(escapeString
)
100 return tempfile
.NamedTemporaryFile('w+', -1, '.tex', 'pbook')
101 def writeFile(self
, fileName
= None):
103 file = self
.tempFile()
104 elif fileName
== "-":
105 return self
.writeTex(sys
.stdout
)
107 name
,ext
= splitext(fileName
)
110 file = open(name
+ ext
, "w+")
111 name
,ext
= splitext(file.name
)
113 return self
.writeTex(file)
115 return self
.writePdf(file)
117 raise "Can not write format " + ext
119 def writeTex(self
, output
):
120 output
.write(self
.beginning())
121 output
.write(self
.buffer)
122 output
.write(self
.ending())
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
)
133 pdfname
= splitext(tmpfile
.name
)[0] + ".pdf"
134 shutil
.copyfile(pdfname
, output
.name
)
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
):
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"
160 self
+= "\n\\end{Verbatim}\n"
162 class IdqTexFile(TexFile
):
163 def __init__(self
, title
, author
= "id Quantique", style
= "article", includeToc
= True):
164 TexFile
.__init
__(self
, title
, author
, style
, includeToc
)
166 class BknrTexFile(TexFile
):
167 def __init__(self
, title
, author
, style
, includeToc
):
168 TexFile
.__init
__(self
, title
, author
, style
, includeToc
)
169 self
.firstSection
= True
171 return '\\chapter{' + TexFile
.escapeString(self
.title
) + '}\n'
174 def addComment(self
, comment
, fileName
, startLine
, endLine
):
175 comment
= TexFile
.escapeString(comment
)
176 self
+= re
.sub("\"([^\"]*)\"", "``\\1''", comment
)
177 def sectioningCommand(self
, level
):
180 if self
.firstSection
== False:
182 # string = "vbox{\n\\vspace{1cm}\n\\centering\n" + \
183 # "\\includegraphics[scale=0.6]{peecol" + \
184 # str(random.randint(1, 10) ) + "}}\n\n\\"
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
))]
193 def __init__(self
, files
, outFile
):
195 self
.commentRe
= None
196 self
.headingRe
= None
198 self
.outFile
= outFile
200 if not self
.outFile
.title
: self
.outFile
.title
= basename(file)
202 def formatBuffer(self
):
205 for file in self
.files
:
206 data
= open(file, "r").read()
208 data
= self
.removeRe
.sub("", data
)
209 # search the first heading
210 startMatch
= self
.headingRe
.search(data
)
212 raise "File must have at least one heading"
213 self
.lineCounter
+= len(data
[:startMatch
.start()].split('\n'))
214 data
= data
[startMatch
.start():]
217 lines
= data
.split('\n')
218 while len(lines
) > 0:
220 if re
.match("^\s*$", line
):
222 self
.lineCounter
+= 1
224 elif self
.figureRe
.match(line
):
227 self
.lineCounter
+= 1
228 elif self
.escapeRe
.match(line
):
231 self
.lineCounter
+= 1
232 elif self
.headingRe
.match(line
):
235 self
.lineCounter
+= 1
236 elif self
.commentRe
.match(line
):
237 self
.doComment(lines
)
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
)
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
)
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
)
262 def doComment(self
, lines
):
265 while len(lines
) > 0:
267 match
= self
.commentRe
.match(line
)
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
275 def doCode(self
, lines
):
278 while len(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
)):
287 self
.outFile
.addCode(code
, self
.fileName
, self
.lineCounter
, self
.lineCounter
+ lineCount
)
288 self
.lineCounter
+= lineCount
290 def makeFile(self
, fileName
):
293 return self
.outFile
.writeFile(fileName
)
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
)
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
)
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 ..."
317 fileExtToType
= ( ((".c", ".cpp", ".C", ".h"), CPbook
),
318 ((".lisp", ".el", ".l", ".cl"), LispPbook
) )
319 for types
, typeClass
in fileExtToType
:
328 (author
, title
, toc
, style
) = (None, None, True, "article")
330 opts
, args
= getopt
.getopt(sys
.argv
[1:], "hc:T:t:a:Oo:s:")
332 raise getopt
.error
, "At least one file argument required"
333 for optname
, optvalue
in opts
:
337 elif optname
== "-c":
338 if optvalue
== "TexFile":
340 elif optvalue
== "IdqTexFile":
341 texClass
= IdqTexFile
342 elif optvalue
== "BknrTexFile":
343 texClass
= BknrTexFile
344 elif optvalue
== "TxtFile":
347 raise getopt
.error
, "Unknown TexFile class ", optvalue
348 elif optname
== "-t":
350 elif optname
== "-a":
352 elif optname
== "-O":
354 elif optname
== "-s":
356 elif optname
== "-T":
359 elif optvalue
== "Lisp":
362 raise getopt
.error
, "Unknown pbook file type ", optvalue
363 elif optname
== "-o":
365 except getopt
.error
, msg
:
370 name
,ext
= splitext(file)
372 title
= basename(name
)
374 type = extToType(ext
)
376 print "Could not get type for ", ext
378 pbook
= type(args
, texClass(title
, author
, style
, toc
))
380 output
= basename(name
)
382 file = pbook
.makeFile(output
)
384 print "Wrote output to ", file.name
385 except IOError, (errno
, strerror
):
386 print "Caught an error while generating \"%s\": %s" % (output
, strerror
)
388 print "Caught an error while generating \"%s\"" % (output
)
391 if __name__
== "__main__":