blob: dd74fd4f7526b0f904f6e0c72f0c30a5ff9054b2 [file] [log] [blame]
Fred Drake361ee651998-03-06 21:29:00 +00001#! /usr/bin/env python
2
3"""Convert a LaTeX .toc file to some PDFTeX magic to create that neat outline.
4
5The output file has an extension of '.bkm' instead of '.out', since hyperref
6already uses that extension. Let's avoid clashing.
7"""
8
9import os
10import re
11import string
12import sys
13
14
15# Ench item in an entry is a tuple of:
16#
17# Section #, Title String, Page #, List of Sub-entries
18
19cline_re = r"""^
20\\contentsline\ \{([a-z]*)} # type of section in $1
21\{(?:\\numberline\ \{([0-9.A-Z]+)})? # section number
22(.*)} # title string
23\{(\d+)}$""" # page number
24
25cline_rx = re.compile(cline_re, re.VERBOSE)
26
27OUTER_TO_INNER = -1
28
29_transition_map = {
30 ('chapter', 'section'): OUTER_TO_INNER,
31 ('section', 'subsection'): OUTER_TO_INNER,
32 ('subsection', 'subsubsection'): OUTER_TO_INNER,
33 ('subsubsection', 'subsection'): 1,
34 ('subsection', 'section'): 1,
35 ('section', 'chapter'): 1,
36 ('subsection', 'chapter'): 2,
37 ('subsubsection', 'section'): 2,
38 ('subsubsection', 'chapter'): 3,
39 }
40
41def parse_toc(fp):
42 toc = top = []
43 stack = [toc]
44 level = 'chapter'
45 lineno = 0
46 while 1:
47 line = fp.readline()
48 if not line:
49 break
50 lineno = lineno + 1
51 m = cline_rx.match(line)
52 if m:
53 stype, snum, title, pageno = m.group(1, 2, 3, 4)
54 title = clean_title(title)
55 entry = (stype, snum, title, string.atoi(pageno), [])
56 if stype == level:
57 toc.append(entry)
58 else:
59 direction = _transition_map[(level, stype)]
60 if direction == OUTER_TO_INNER:
61 toc = toc[-1][-1]
62 stack.insert(0, toc)
63 toc.append(entry)
64 else:
65 for i in range(direction):
66 del stack[0]
67 toc = stack[0]
68 toc.append(entry)
69 level = stype
70 else:
71 sys.stderr.write("l.%s: " + line)
72 return top
73
74
75hackscore_rx = re.compile(r"\\(hackscore|raisebox)\s*{[^}]*}")
76title_rx = re.compile(r"\\[a-zA-Z]+\s*")
77title_trans = string.maketrans("", "")
78
79def clean_title(title):
80 title = hackscore_rx.sub("_", title)
81 while 1:
82 m = title_rx.search(title)
83 if m:
84 title = title[:m.start()] + title[m.end():]
85 else:
86 break
87 return string.translate(title, title_trans, "{}")
88
89
90def write_toc(toc, fp):
91 for entry in toc:
92 write_toc_entry(entry, fp, 0)
93
94def write_toc_entry(entry, fp, layer):
95 stype, snum, title, pageno, toc = entry
96 s = "\\pdfoutline goto name{page.%d}" % pageno
97 if toc:
98 s = "%s count -%d" % (s, len(toc))
99 if snum:
100 title = "%s %s" % (snum, title)
101 s = "%s {%s}\n" % (s, title)
102 fp.write(s)
103 for entry in toc:
104 write_toc_entry(entry, fp, layer + 1)
105
106
107def main():
108 base, ext = os.path.splitext(sys.argv[1])
109 ext = ext or ".toc"
110 toc = parse_toc(open(base + ext))
111 write_toc(toc, open(base + ".bkm", "w"))
112
113
114if __name__ == "__main__":
115 main()