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 "\\usepackage{graphicx}\n" + \
70 '\\definecolor{gray}{gray}{0.6}\n' + \
71 '\\title{' + TexFile
.escapeString(self
.title
) + '}\n' + \
72 (self
.author
and ('\\author{' + self
.author
+ '}\n') or '') + \
74 '\\begin{document}\n\\maketitle\n' + \
75 (self
.includeToc
and '\\tableofcontents\n' or '')
77 return '\\printindex\n\\end{document}\n'
78 def sectioningCommand(self
, level
):
79 if self
.style
== "article":
80 return self
.articleSectioningCommands
[min(level
, len(self
.articleSectioningCommands
))]
81 elif self
.style
== "book":
82 return self
.bookSectioningCommands
[min(level
, len(self
.bookSectioningCommands
))]
84 def escapeString(aStr
):
85 aStr
= re
.sub("\\\\", "$\\\\backslash$", aStr
)
86 def escapeRepl(match
):
87 if match
.group(1) != '$' or \
88 not (aStr
[match
.start():].startswith("$\\backslash$") or \
89 aStr
[:match
.start()].endswith("$\\backslash")):
90 return '\\' + match
.group(1)
93 return re
.sub("([#%&~$_^{}])", escapeRepl
, aStr
)
94 escapeString
= staticmethod(escapeString
)
97 return tempfile
.NamedTemporaryFile('w+', -1, '.tex', 'pbook')
98 def writeFile(self
, fileName
= None):
100 file = self
.tempFile()
101 elif fileName
== "-":
102 return self
.writeTex(sys
.stdout
)
104 name
,ext
= splitext(fileName
)
107 file = open(name
+ ext
, "w+")
108 name
,ext
= splitext(file.name
)
110 return self
.writeTex(file)
112 return self
.writePdf(file)
114 raise "Can not write format " + ext
116 def writeTex(self
, output
):
117 output
.write(self
.beginning())
118 output
.write(self
.buffer)
119 output
.write(self
.ending())
123 def writePdf(self
, output
):
124 tmpfile
= self
.tempFile()
125 self
.writeTex(tmpfile
)
126 (dir, name
) = os
.path
.split(tmpfile
.name
)
127 print "cd " + dir + "; latex " + name
+ " && pdflatex " + name
128 os
.system("cd " + dir + "; latex " + name
+ " && pdflatex " + name
)
130 pdfname
= splitext(tmpfile
.name
)[0] + ".pdf"
131 shutil
.copyfile(pdfname
, output
.name
)
135 def addEscape(self
, escape
, fileName
, line
):
136 self
+= escape
+ "\n"
137 def addFigure(self
, figureFile
, figureScale
, figureName
, fileName
, endLine
):
138 self
+= "\\begin{figure}[htbp]\n \\centering\n"
139 self
+= " \\fbox{\\includegraphics[scale=" + figureScale
+ "]{" + figureFile
+ "}}\n"
140 self
+= " \\caption{" + figureName
+ "}\n"
141 self
+= "\\end{figure}\n"
142 def addHeading(self
, level
, heading
, fileName
, line
):
143 heading
= re
.sub("\s+", " ", heading
)
144 self
+= "\n\n\\" + self
.sectioningCommand(level
) + "{" + \
145 TexFile
.escapeString(heading
) + "}\n"
146 def addComment(self
, comment
, fileName
, startLine
, endLine
):
147 comment
= TexFile
.escapeString(comment
)
148 comment
= re
.sub("`([^`']*)'", "{\\\\tt \\1}", comment
)
149 self
+= re
.sub("\"([^\"]*)\"", "``\\1''", comment
)
150 def addCode(self
, code
, fileName
, startLine
, endLine
):
152 code
= re
.sub("\\\\end{Verbatim}", "\\\\_end{Verbatim}", code
)
153 code
= re
.sub("\t", " ", code
)
154 self
+= "\n\\begin{Verbatim}[fontsize=\\small,frame=leftline,framerule=0.9mm," + \
155 "rulecolor=\\color{gray},framesep=5.1mm,xleftmargin=5mm,fontfamily=cmtt]\n"
157 self
+= "\n\\end{Verbatim}\n"
159 class IdqTexFile(TexFile
):
160 def __init__(self
, title
, author
= "id Quantique", style
= "article", includeToc
= True):
161 TexFile
.__init
__(self
, title
, author
, style
, includeToc
)
163 class BknrTexFile(TexFile
):
164 def __init__(self
, title
, author
, style
, includeToc
):
165 TexFile
.__init
__(self
, title
, author
, style
, includeToc
)
166 self
.firstSection
= True
168 return '\\chapter{' + TexFile
.escapeString(self
.title
) + '}\n'
171 def addComment(self
, comment
, fileName
, startLine
, endLine
):
172 comment
= TexFile
.escapeString(comment
)
173 self
+= re
.sub("\"([^\"]*)\"", "``\\1''", comment
)
174 def sectioningCommand(self
, level
):
177 if self
.firstSection
== False:
179 # string = "vbox{\n\\vspace{1cm}\n\\centering\n" + \
180 # "\\includegraphics[scale=0.6]{peecol" + \
181 # str(random.randint(1, 10) ) + "}}\n\n\\"
183 self
.firstSection
= False
184 if self
.style
== "article":
185 return string
+ self
.articleSectioningCommands
[min(level
, len(self
.articleSectioningCommands
))]
186 elif self
.style
== "book":
187 return string
+ self
.bookSectioningCommands
[min(level
, len(self
.bookSectioningCommands
))]
190 def __init__(self
, files
, outFile
):
192 self
.commentRe
= None
193 self
.headingRe
= None
195 self
.outFile
= outFile
197 if not self
.outFile
.title
: self
.outFile
.title
= basename(file)
199 def formatBuffer(self
):
202 for file in self
.files
:
203 data
= open(file, "r").read()
205 data
= self
.removeRe
.sub("", data
)
206 # search the first heading
207 startMatch
= self
.headingRe
.search(data
)
209 raise "File must have at least one heading"
210 self
.lineCounter
+= len(data
[:startMatch
.start()].split('\n'))
211 data
= data
[startMatch
.start():]
214 lines
= data
.split('\n')
215 while len(lines
) > 0:
217 if re
.match("^\s*$", line
):
219 self
.lineCounter
+= 1
221 elif self
.figureRe
.match(line
):
224 self
.lineCounter
+= 1
225 elif self
.escapeRe
.match(line
):
228 self
.lineCounter
+= 1
229 elif self
.headingRe
.match(line
):
232 self
.lineCounter
+= 1
233 elif self
.commentRe
.match(line
):
234 self
.doComment(lines
)
238 def doHeading(self
, line
):
239 match
= self
.headingRe
.match(line
)
240 assert(match
!= None)
241 level
= len(match
.group(1)) - 1
242 headingName
= line
[match
.end():]
243 self
.outFile
.addHeading(level
, headingName
, self
.fileName
, self
.lineCounter
)
245 def doFigure(self
, line
):
246 match
= self
.figureRe
.match(line
)
247 assert(match
!= None)
248 figureFile
= match
.group(1)
249 figureName
= match
.group(3)
250 figureScale
= match
.group(2)
251 self
.outFile
.addFigure(figureFile
, figureScale
, figureName
, self
.fileName
, self
.lineCounter
)
253 def doEscape(self
, line
):
254 match
= self
.escapeRe
.match(line
)
255 assert(match
!= None)
256 escape
= match
.group(1)
257 self
.outFile
.addEscape(escape
, self
.fileName
, self
.lineCounter
)
259 def doComment(self
, lines
):
262 while len(lines
) > 0:
264 match
= self
.commentRe
.match(line
)
268 comment
+= line
[:match
.start()] + line
[match
.end():] + "\n"
269 self
.outFile
.addComment(comment
, self
.fileName
, self
.lineCounter
, self
.lineCounter
+ lineCount
)
270 self
.lineCounter
+= lineCount
272 def doCode(self
, lines
):
275 while len(lines
) > 0:
277 if (self
.headingRe
.match(line
) or self
.escapeRe
.match(line
) \
278 or self
.figureRe
.match(line
) \
279 or self
.commentRe
.match(line
)):
284 self
.outFile
.addCode(code
, self
.fileName
, self
.lineCounter
, self
.lineCounter
+ lineCount
)
285 self
.lineCounter
+= lineCount
287 def makeFile(self
, fileName
):
290 return self
.outFile
.writeFile(fileName
)
292 class LispPbook(Pbook
):
293 def __init__(self
, files
, outFile
):
294 Pbook
.__init
__(self
, files
, outFile
)
295 self
.commentRe
= re
.compile('^;;;($|[^#f])', re
.M
)
296 self
.headingRe
= re
.compile('^;;;(#+)', re
.M
)
297 self
.figureRe
= re
.compile('^;;;f\s+\"(.+)\"\s+([^\s]+)\s+(.*)', re
.M
)
298 self
.escapeRe
= re
.compile('^;;;t\s+(.+)', re
.M
)
301 def __init__(self
, files
, outFile
):
302 Pbook
.__init
__(self
, files
, outFile
)
303 self
.commentRe
= re
.compile('^(\s|/)*\*\*($|[^f#/])', re
.M
);
304 self
.headingRe
= re
.compile("^/\*\*(#+)", re
.M
)
305 self
.removeRe
= re
.compile('\*\*+/', re
.M
)
306 self
.figureRe
= re
.compile('^/\*\*f \"(.+)\"\s+([^\s]+)\s(.*)', re
.M
)
310 print "Usage: ", sys
.argv
[0], " [-h] [-c TexFile|BknrTexFile|IdqTexFile|TxtFile] ", \
311 "[-T C|Lisp] [-t title] [-a author] [-O] [-o output] [-s style] file ..."
314 fileExtToType
= ( ((".c", ".cpp", ".C", ".h"), CPbook
),
315 ((".lisp", ".el", ".l", ".cl"), LispPbook
) )
316 for types
, typeClass
in fileExtToType
:
325 (author
, title
, toc
, style
) = (None, None, True, "article")
327 opts
, args
= getopt
.getopt(sys
.argv
[1:], "hc:T:t:a:Oo:s:")
329 raise getopt
.error
, "At least one file argument required"
330 for optname
, optvalue
in opts
:
334 elif optname
== "-c":
335 if optvalue
== "TexFile":
337 elif optvalue
== "IdqTexFile":
338 texClass
= IdqTexFile
339 elif optvalue
== "BknrTexFile":
340 texClass
= BknrTexFile
341 elif optvalue
== "TxtFile":
344 raise getopt
.error
, "Unknown TexFile class ", optvalue
345 elif optname
== "-t":
347 elif optname
== "-a":
349 elif optname
== "-O":
351 elif optname
== "-s":
353 elif optname
== "-T":
356 elif optvalue
== "Lisp":
359 raise getopt
.error
, "Unknown pbook file type ", optvalue
360 elif optname
== "-o":
362 except getopt
.error
, msg
:
367 name
,ext
= splitext(file)
369 title
= basename(name
)
371 type = extToType(ext
)
373 print "Could not get type for ", ext
375 pbook
= type(args
, texClass(title
, author
, style
, toc
))
377 output
= basename(name
)
379 file = pbook
.makeFile(output
)
381 print "Wrote output to ", file.name
382 except IOError, (errno
, strerror
):
383 print "Caught an error while generating \"%s\": %s" % (output
, strerror
)
385 print "Caught an error while generating \"%s\"" % (output
)
388 if __name__
== "__main__":