Advertisement
Guest User

GNU autotools

a guest
Sep 19th, 2010
227
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 19.34 KB | None | 0 0
  1. #!/usr/bin/env python
  2. '''
  3. This file is not free software. You are allowed to freely copy,
  4. distribute and modify it, as long as this copyright notice
  5. and license conditions remains.
  6. You are NOT given permission to execute this program.
  7.  
  8. This file is not even intended to be a running program at all.
  9. It's intended to be a basis for educational discussions about
  10. using latex as a generator for beautiful documents.
  11.  
  12. '''
  13.  
  14. raise NotImplementedError("You are not allowed to execute this file!")
  15.  
  16. import os
  17. import re
  18. import shutil
  19. import urllib2
  20.  
  21. _sources = [\
  22. ('work/t', 'http://nostarch.com/autotools.htm'),\
  23. ('work/t', 'http://nostarch.com/sites/default/files/imagecache/product_full/autotools_big.png'),\
  24. ('work/c0', 'http://www.freesoftwaremagazine.com/books/autotools_a_guide_to_autoconf_automake_libtool'),\
  25. \
  26. ('work/c1', 'http://www.freesoftwaremagazine.com/books/agaal/brief_introduction_to_gnu_autotools'),\
  27. ('work/c1', 'http://www.freesoftwaremagazine.com/files/www.freesoftwaremagazine.com/nodes/2754/autoconf_ahdr_dataflow.png'),\
  28. ('work/c1', 'http://www.freesoftwaremagazine.com/files/www.freesoftwaremagazine.com/nodes/2754/aclocal_dataflow.png'),\
  29. ('work/c1', 'http://www.freesoftwaremagazine.com/files/www.freesoftwaremagazine.com/nodes/2754/automake_libtool_dataflow.png'),\
  30. ('work/c1', 'http://www.freesoftwaremagazine.com/files/www.freesoftwaremagazine.com/nodes/2754/configure_dataflow.png'),\
  31. ('work/c1', 'http://www.freesoftwaremagazine.com/files/www.freesoftwaremagazine.com/nodes/2754/make_dataflow.png'),\
  32. \
  33. ('work/c2', 'http://www.freesoftwaremagazine.com/books/agaal/gnu_coding_standards_applied_to_autotools'),\
  34. ('work/c2', 'http://www.freesoftwaremagazine.com/files/www.freesoftwaremagazine.com/nodes/2763/compile_link_process.png'),\
  35. ('work/c3', 'http://www.freesoftwaremagazine.com/books/agaal/configuring_a_project_with_autoconf'),\
  36. ('work/c4', 'http://www.freesoftwaremagazine.com/books/agaal/automatically_writing_makefiles_with_autotools'),\
  37. ('work/c5', 'http://www.freesoftwaremagazine.com/books/agaal/building_shared_libraries_once_using_autotools'),\
  38. ('work/c5', 'http://www.freesoftwaremagazine.com/files/www.freesoftwaremagazine.com/nodes/2764/exe_load.png'),\
  39. ('work/c5', 'http://www.freesoftwaremagazine.com/files/www.freesoftwaremagazine.com/nodes/2764/lib_load.png'),\
  40. ('work/c6', 'http://www.freesoftwaremagazine.com/books/agaal/autotools_example'),\
  41. ('work/c7', 'http://www.freesoftwaremagazine.com/books/agaal/catalog_of_reusable_solutions'),\
  42. ('work/c8', 'http://www.freesoftwaremagazine.com/books/agaal/overview_of_m4_overview'),\
  43. ('work/c9', 'http://www.freesoftwaremagazine.com/books/agaal/reusing_autotools_solutions'),\
  44. ]
  45.  
  46. _chapter_names = ["Foreword"]
  47.  
  48.  
  49. _regex_transforms = [
  50. ("<div\s*class=\"textbox\">\s*<h3>(.*?)</h3>([\s\S]*?)</div>",\
  51. '''
  52. \\\\begin{quotation}
  53. {\\\\color{gray}\\\\noindent\\\\rule{0.89\\\\textwidth}{2pt}}
  54. \\\\subsection*{\\1}
  55.  
  56. \\2
  57.  
  58. {\\\\color{gray}\\\\noindent\\\\rule{0.89\\\\textwidth}{2pt}}
  59. \\\\end{quotation}
  60.  
  61. '''),\
  62. ("<!--.*?-->", ""),\
  63. ("&lt;", "<"),\
  64. ("&gt;", ">"),\
  65. ("&amp;", "&"),\
  66. ("&#8216;", "`"),\
  67. ("&#8217;", "'"),\
  68. ("&#8220;", "``"),\
  69. ("&#8221;", "''"),\
  70. ("&#8212;", "--"),\
  71. ("&#8230;", "\\\\ldots "),\
  72. ("<h[23]>(.+)</h[23]>\s*<pre>", "\\\\begin{lstlisting}[caption=\\1]"),\
  73. ("</pre>", "\n\\\\end{lstlisting}"),\
  74. ("<dl class=\"image\"><dt><a href=\"/files/www.freesoftwaremagazine.com/nodes/\d*/([^\"]+)\"><img src=\"[^\"]+\" alt=\"Figure \d*: ([^\"]+)\" title=\"[^\"]+\"></a></dt><dd><caption>[^\"]+</caption></dd></dl>",\
  75. '''
  76. (see fig. \\\\ref{fig-\\1})
  77.  
  78. \\\\begin{figure}[ht!]
  79. \\\\centering
  80. \\\\includegraphics[width=\\\\textwidth]{img/\\1}
  81. \\\\caption{\\2}
  82. \\\\label{fig-\\1}
  83. \\\\end{figure}
  84.  
  85. '''),\
  86. ("<a\s+href=\"([^\"]+)\">(.*?)</a>", "\\2\\\\footnote{\\\\url{\\1}}"),\
  87. ("<p>" , ""),\
  88. ("</p>", "\n"),\
  89. ("<h1[^>]*>", "\\\\section{"),\
  90. ("</h1>", "}"),\
  91. ("<h2>", "\\\\subsection{"),\
  92. ("</h2>", "}"),\
  93. ("<h3>", "\\\\subsubsection{"),\
  94. ("</h3>", "}"),\
  95. ("<code>", "\\\\texttt{"),\
  96. ("</code>", "}"),\
  97. ("<em>", "\\\\textit{"),\
  98. ("</em>", "}"),\
  99. ("<i>", "\\\\textit{"),\
  100. ("</i>", "}"),\
  101. ("<b>", "\\\\textbf{"),\
  102. ("</b>", "}"),\
  103. ("<strong>", "\\\\textbf{"),\
  104. ("</strong>", "}"),\
  105. ("<pre>", "\\\\begin{lstlisting}"),\
  106. ("</pre>", "\n\\\\end{lstlisting}"),\
  107. ("<blockquote>", "\\\\begin{quotation}"),\
  108. ("</blockquote>", "\n\\\\end{quotation}"),\
  109. ("<ul>", "\\\\begin{itemize}"),\
  110. ("</ul>", "\\\\end{itemize}"),\
  111. ("<ol>", "\\\\begin{enumerate}"),\
  112. ("</ol>", "\\\\end{enumerate}"),\
  113. ("<li>", "\\\\item "),\
  114. ("</li>", "\n"),\
  115. ("Chapter (\d)", "Chapter \\\\ref{chap-\\1}"),\
  116. ("Chapters (\d), (\d) and (\d)", "Chapters \\\\ref{chap-\\1}, \\\\ref{chap-\\2} and \\\\ref{chap-\\3}"),\
  117. ("Appendix A", "Chapter \\\\ref{chap-8}"),\
  118. ("Finally, the References section", "Finally Chapter \\\\ref{chap-9}"),\
  119. ("\\\\section{About the Author}", "\\\\section*{About the Author}\n\n"),\
  120. #last resort rules: remove missed html tags:
  121. ("</?div[^>]*>", ""),\
  122. ("<hr[^>]*>", "")\
  123. ]
  124.  
  125. #tex destination, html source
  126. _tex_files = [
  127. ('work/tex/titletext.tex', 'work/t/autotools.htm'),\
  128. ('work/tex/00_foreword.tex', 'work/c0/autotools_a_guide_to_autoconf_automake_libtool'),\
  129. ('work/tex/01_introduction.tex', 'work/c1/brief_introduction_to_gnu_autotools'),\
  130. ('work/tex/02_gnu_coding_standards.tex', 'work/c2/gnu_coding_standards_applied_to_autotools'),\
  131. ('work/tex/03_configure.tex', 'work/c3/configuring_a_project_with_autoconf'),\
  132. ('work/tex/04_automake.tex', 'work/c4/automatically_writing_makefiles_with_autotools'),\
  133. ('work/tex/05_shared_libs.tex', 'work/c5/building_shared_libraries_once_using_autotools'),\
  134. ('work/tex/06_example.tex', 'work/c6/autotools_example'),\
  135. ('work/tex/07_catalog.tex', 'work/c7/catalog_of_reusable_solutions'),\
  136. ('work/tex/08_m4.tex', 'work/c8/overview_of_m4_overview'),\
  137. ('work/tex/09_reusing.tex', 'work/c9/reusing_autotools_solutions')\
  138. ]
  139.  
  140. _tex_template =\
  141. '''
  142. \documentclass[10pt,titlepage=true,BCOR=10mm,DIV=10]{scrbook}
  143. %BCOR 10mm for ring binding
  144. %increased DIV to enlage page area (and reduce pages numbers)
  145. %be aware that reading long lines is not that easy for the eye
  146. \usepackage[T1]{fontenc}
  147. \usepackage[utf8]{inputenc}
  148. \usepackage[english]{babel}
  149. \usepackage{hyperref}
  150. \usepackage[sc]{mathpazo} %palatino
  151. \linespread{1.05} %palatino wider lines spacing
  152. \usepackage{listings}
  153. \usepackage{xcolor}
  154. \usepackage{graphicx}
  155. \usepackage[absolute]{textpos}
  156. \pretolerance=150
  157. \\tolerance=150
  158. \setlength{\emergencystretch}{3em}
  159. \hypersetup{
  160. colorlinks=true,
  161. linkcolor=black,
  162. urlcolor=black
  163. }
  164. \lstset{
  165. breaklines=true,
  166. breakatwhitespace=true,
  167. basicstyle=\\ttfamily\small
  168. }
  169. \setkomafont{disposition}{\\rmfamily\itshape}
  170.  
  171. \\author{John Calcote}
  172. \\title{Autotools: A Practical Guide To GNU Autoconf, Automake, And Libtool}
  173. \date{July 2010}
  174.  
  175. \\begin{document}
  176. \pagenumbering{roman}
  177. \\thispagestyle{empty}
  178.  
  179. \\begin{titlepage}
  180. \\begin{textblock}{297}[0,0](0,0)
  181. \includegraphics[width=\paperwidth,height=\paperheight]{img/autotools_big_scaled.png}
  182. \end{textblock}
  183.  
  184. \\vspace*{1em}
  185.  
  186. \clearpage
  187.  
  188. \input{titletext.tex}
  189.  
  190. \\vfill
  191.  
  192. \\noindent Warning: This book was generated from various unreviewed work-in-progress online sources
  193. and may contain minor incorrectnesses.
  194. The real printed book, available from No Starch Press (\\url{http://www.nostarch.com/autotools.htm}) is
  195. technically reviewed and completed. Consider buying.
  196.  
  197. \clearpage
  198. \\thispagestyle{empty}
  199. \end{titlepage}
  200.  
  201.  
  202. \maketitle
  203. \setcounter{page}{1}
  204. \\tableofcontents
  205. \listoffigures
  206. \pagestyle{empty}
  207. \cleardoublepage
  208. \pagenumbering{arabic}
  209. \pagestyle{plain}
  210.  
  211. \input{00_foreword.tex}
  212.  
  213. \input{01_introduction.tex}
  214.  
  215. \input{02_gnu_coding_standards.tex}
  216.  
  217. \input{03_configure.tex}
  218.  
  219. \input{04_automake.tex}
  220.  
  221. \input{05_shared_libs.tex}
  222.  
  223. \input{06_example.tex}
  224.  
  225. \input{07_catalog.tex}
  226.  
  227. \input{08_m4.tex}
  228.  
  229. \input{09_reusing.tex}
  230.  
  231. \end{document}
  232.  
  233. '''
  234.  
  235. def mkpath(path):
  236. if(not os.path.exists(path)):
  237. os.makedirs(path)
  238. return
  239.  
  240. def fetch_sources():
  241. if(os.path.exists('work')):
  242. print 'work directory exists; delete it to make me re-fetch book data'
  243. else:
  244. print 'fetching book data...'
  245. for path,url in _sources:
  246. mkpath(path)
  247. #os.system('cd %s && wget \'%s\'' % (path,url))
  248. print 'downloading %s' % url
  249. req = urllib2.urlopen(url)
  250. content = req.read()
  251. outfilename = '%s/%s' % (path,url.split('/')[-1])
  252. print ' storing at %s' % outfilename
  253. outfile = open(outfilename, 'w')
  254. outfile.write(content)
  255. outfile.close()
  256. return
  257.  
  258. def make_tex_template():
  259. print 'writing tex template'
  260. mkpath('work/tex')
  261. template = open('work/tex/autotools-guide.tex', 'w')
  262. template.write(_tex_template)
  263. template.close()
  264. return
  265.  
  266. def scale_title_image():
  267. print 'scaling title image'
  268. os.system('cd work && convert -resize 400\% -colorspace Gray t/autotools_big.png t/autotools_big_scaled.png')
  269. return
  270.  
  271. def read_chapter_titles():
  272. print 'extracting chapter names'
  273. for _,src in _tex_files[2:]:
  274. file = open(src, 'r')
  275. content = file.read()
  276. file.close()
  277.  
  278. matches = re.findall("<title>Chapter \d+: ([^<]+)</title>", content)
  279. if(len(matches)):
  280. _chapter_names.append(matches[0].strip())
  281. continue
  282.  
  283. matches = re.findall("<title>Appendix .+: ([^<]+)</title>", content)
  284. if(len(matches)):
  285. _chapter_names.append(matches[0].strip())
  286. continue
  287.  
  288. matches = re.findall("<title>([^<]+)</title>", content)
  289. if(len(matches)):
  290. _chapter_names.append(matches[0].strip())
  291. continue
  292.  
  293. return
  294.  
  295.  
  296. def cutncopy_html_bodies():
  297. fsm_body_open = '<div class="content">'
  298. fsm_body_close1 = '<div class="book-navigation">'
  299. fsm_body_close2 = '<h3>Source archive</h3>'
  300.  
  301. nost_body_open = 'Download the source code from the book</a></li>\n</ul>'
  302. nost_body_close = '<div><hr class="separator"><a name="toc">'
  303. for dest,src in _tex_files:
  304. infile = open(src, 'r')
  305. content = infile.read()
  306. infile.close()
  307.  
  308. pos = content.find(fsm_body_open)
  309. if(pos != -1): #we have a freesoftwaremagazine file
  310. content = content[pos+len(fsm_body_open):] #cut header garbage
  311. pos = content.find(fsm_body_close1)
  312. if(pos!=-1):
  313. content = content[:pos] #cut footer garbage
  314. pos = content.find(fsm_body_close2)
  315. if(pos!=-1):
  316. content = content[:pos]
  317.  
  318. pos = content.find(nost_body_open)
  319. if(pos != -1): #we have the nostarch titlepage
  320. content = content[pos+len(nost_body_open):] #cut header garbage
  321. pos = content.find(nost_body_close)
  322. content = content[:pos] #cut footer garbage
  323.  
  324. outfile = open(dest, 'w')
  325. outfile.write(content)
  326. outfile.close()
  327. return
  328.  
  329. def regex_transformations(content):
  330. print 'applying regex patterns'
  331. for match,replace in _regex_transforms:
  332. content = re.subn(match, replace, content)[0]
  333. return content
  334.  
  335. def context_sensitive_latex_escaping(content):
  336. print 'escaping _ $ and # in non-lstlisting environments'
  337.  
  338. #second pass lstlisting/ _ $ and # escaping
  339. sections = []
  340. start = 0
  341. lst_start_token = "\\begin{lstlisting}"
  342. lst_end_token = "\\end{lstlisting}"
  343. caption_start_token="[caption="
  344. caption_end_token="]"
  345. while True:
  346. found_start = content.find(lst_start_token, start)
  347. if(found_start == -1): #no more listing environs
  348. sections.append((content[start:], True))
  349. break
  350. non_escape_start = found_start + len(lst_start_token)
  351.  
  352. #we have an additional caption that has to be escaped
  353. if( content[non_escape_start:].startswith(caption_start_token) ):
  354. found_caption_end = content.find(caption_end_token, non_escape_start)
  355. if(found_caption_end != -1):
  356. non_escape_start = found_caption_end + len(caption_end_token)
  357.  
  358.  
  359. found_end = content.find(lst_end_token, non_escape_start)
  360. if(found_end == -1): #no more listing environs
  361. sections.append((content[start:], True))
  362. break
  363.  
  364. non_escape_end = found_end
  365.  
  366. sections.append((content[start:non_escape_start], True))
  367. sections.append((content[non_escape_start:non_escape_end], False))
  368. sections.append((content[non_escape_end:non_escape_end+len(lst_end_token)], True))
  369.  
  370. start = found_end + len(lst_end_token)
  371.  
  372. content = []
  373. for (section,doEsc) in sections:
  374. if doEsc:
  375. section = section.replace("_", "\\_")
  376. section = section.replace("$", "\\$")
  377. section = section.replace("#", "\\#")
  378. section = section.replace("...", "\\ldots ")
  379.  
  380. content.append(section)
  381.  
  382. return "".join(content)
  383.  
  384. def ref_label_cleanup(content):
  385. print 'cleaning labels and refs'
  386.  
  387. for token in ["\\ref{", "\\label{"]:
  388. start = 0
  389. while True:
  390. found_start = content.find(token, start)
  391. if(found_start == -1):
  392. break
  393.  
  394. found_end = content.find("}", found_start)
  395. if(found_end == -1):
  396. break
  397.  
  398. cleaned = content[found_start+len(token):found_end]
  399. cleaned = cleaned.replace("\\", "")
  400. cleaned = cleaned.replace("_", "-")
  401. cleaned = cleaned.replace(".", "-")
  402. content = '%s%s%s' % (content[:found_start+len(token)],cleaned,content[found_end:])
  403.  
  404. start = found_end
  405. return content
  406.  
  407. def includegraphics_cleanup(content):
  408. print 'cleaning includegraphics'
  409.  
  410. token = "\\includegraphics[width=\\textwidth]{"
  411. start = 0
  412. while True:
  413. found_start = content.find(token, start)
  414. if(found_start == -1):
  415. break
  416.  
  417. found_end = content.find("}", found_start)
  418. if(found_end == -1):
  419. break
  420.  
  421. cleaned = content[found_start+len(token):found_end]
  422. cleaned = cleaned.replace("\\", "")
  423. content = '%s%s%s' % (content[:found_start+len(token)],cleaned,content[found_end:])
  424.  
  425. start = found_end
  426.  
  427. return content
  428.  
  429. _level_tokens = ["\\chapter", "\\section", "\\subsection", "\\subsubsection"]
  430. def fix_sectioning(content):
  431. print "fixing guessable sectioning errors"
  432. current_level = 0
  433. current_expected_level = 0
  434.  
  435. pos = 0
  436. start = 0
  437. while pos != -1:
  438. next_pos = len(content)
  439. next_level = 0
  440. for level,token in enumerate(_level_tokens):
  441. pos = content.find(token, start)
  442. if pos == -1:
  443. continue
  444.  
  445. if pos<next_pos:
  446. next_pos = pos
  447. next_level = level
  448. if pos == -1:
  449. continue
  450. #print '---'
  451. #print 'pos: %d' % pos
  452. #print 'current_level: %d' % current_level
  453. #print 'current_expected_level: %d' % current_expected_level
  454.  
  455. #no level change
  456. if next_level == current_expected_level:
  457. #print 'no level change at %d' % current_expected_level
  458. start = next_pos + len(_level_tokens[next_level])
  459. continue
  460.  
  461. #moving one level down
  462. if next_level < current_expected_level :
  463. #print 'down from %s to %s' % (_level_tokens[current_expected_level], _level_tokens[next_level])
  464. current_expected_level = next_level
  465. current_level = current_expected_level
  466. start = next_pos + len(_level_tokens[next_level])
  467. continue
  468.  
  469. #moving one level up
  470. if current_level == current_expected_level and next_level == current_expected_level + 1 :
  471. #print 'up from %s to %s' % (_level_tokens[current_expected_level], _level_tokens[next_level])
  472. current_expected_level = next_level
  473. current_level = current_expected_level
  474. start = next_pos + len(_level_tokens[next_level])
  475. continue
  476.  
  477. #there is a jump in the levels
  478. if current_level == current_expected_level and next_level > current_expected_level + 1:
  479. #print 'jump from %s to %s' % (_level_tokens[current_expected_level], _level_tokens[next_level])
  480. current_expected_level += 1
  481. current_level = next_level
  482.  
  483. #now fix broken sectioning
  484. if current_level != current_expected_level :
  485. #print 'replacing %s with %s' % (_level_tokens[next_level], _level_tokens[current_expected_level])
  486. content = "".join([\
  487. content[:next_pos],\
  488. content[next_pos:].replace(_level_tokens[next_level], _level_tokens[current_expected_level], 1)])
  489.  
  490. start = next_pos + len(_level_tokens[current_expected_level])
  491.  
  492. return content
  493.  
  494.  
  495. def html_to_latex():
  496. print 'begin of html->latex conversion'
  497. for dest,_ in _tex_files:
  498. file = open(dest, 'r')
  499. content = file.read()
  500. file.close()
  501.  
  502. content = regex_transformations(content)
  503. content = context_sensitive_latex_escaping(content)
  504. content = ref_label_cleanup(content)
  505. content = includegraphics_cleanup(content)
  506. content = fix_sectioning(content)
  507.  
  508. file = open(dest, 'w')
  509. file.write(content)
  510. file.close()
  511. return
  512.  
  513. def insert_chapters():
  514. print 'inserting chapter titles'
  515. count = 0
  516.  
  517. for dest,_ in _tex_files[1:]:
  518. file = open(dest, 'r')
  519. content = file.read()
  520. file.close()
  521.  
  522. content = '\\chapter{%s}\n\label{chap-%d}\n\n%s' % (_chapter_names[count], count, content)
  523.  
  524. count+=1
  525.  
  526. file = open(dest, 'w')
  527. file.write(content)
  528. file.close()
  529. return
  530.  
  531. def compile_pdflatex():
  532. print 'compiling twice with pdflatex'
  533. os.system('cd work/tex && pdflatex autotools-guide.tex && pdflatex autotools-guide.tex')
  534. return
  535.  
  536. def copy_images_to_tex():
  537. mkpath('work/tex/img')
  538. for folder,_ in _sources:
  539. entries = os.listdir(folder)
  540. for entry in entries:
  541. if entry.endswith('.png'):
  542. shutil.copy('%s/%s' % (folder,entry), 'work/tex/img/%s' % (entry))
  543. return
  544.  
  545. def main():
  546. fetch_sources()
  547. make_tex_template()
  548. scale_title_image() #needs convert/imagemagick
  549. copy_images_to_tex()
  550. read_chapter_titles()
  551. cutncopy_html_bodies()
  552. insert_chapters()
  553. html_to_latex()
  554. compile_pdflatex() #needs pdflatex with koma-script and texlive-fontsrecommended (mathpazo/palatino)
  555.  
  556. print "\nI'm done.\nIf everythig went well, there should now be a file called autotools-guide.pdf in work/tex/"
  557. return
  558.  
  559. if __name__=="__main__":
  560. #main()
  561. raise NotImplementedError("Do you really wan't to chose the dark side?")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement