blob: 2b9631248385fb557903eae5383e765182468e99 [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
Fred Drake473a90e1998-03-07 15:34:50 +00009import getopt
Fred Drake361ee651998-03-06 21:29:00 +000010import os
11import re
12import string
13import sys
14
15
16# Ench item in an entry is a tuple of:
17#
18# Section #, Title String, Page #, List of Sub-entries
19
20cline_re = r"""^
21\\contentsline\ \{([a-z]*)} # type of section in $1
22\{(?:\\numberline\ \{([0-9.A-Z]+)})? # section number
23(.*)} # title string
24\{(\d+)}$""" # page number
25
26cline_rx = re.compile(cline_re, re.VERBOSE)
27
28OUTER_TO_INNER = -1
29
30_transition_map = {
31 ('chapter', 'section'): OUTER_TO_INNER,
32 ('section', 'subsection'): OUTER_TO_INNER,
33 ('subsection', 'subsubsection'): OUTER_TO_INNER,
34 ('subsubsection', 'subsection'): 1,
35 ('subsection', 'section'): 1,
36 ('section', 'chapter'): 1,
37 ('subsection', 'chapter'): 2,
38 ('subsubsection', 'section'): 2,
39 ('subsubsection', 'chapter'): 3,
40 }
41
Fred Drake473a90e1998-03-07 15:34:50 +000042def parse_toc(fp, bigpart=None):
Fred Drake361ee651998-03-06 21:29:00 +000043 toc = top = []
44 stack = [toc]
Fred Drake473a90e1998-03-07 15:34:50 +000045 level = bigpart or 'chapter'
Fred Drake361ee651998-03-06 21:29:00 +000046 lineno = 0
47 while 1:
48 line = fp.readline()
49 if not line:
50 break
51 lineno = lineno + 1
52 m = cline_rx.match(line)
53 if m:
54 stype, snum, title, pageno = m.group(1, 2, 3, 4)
55 title = clean_title(title)
56 entry = (stype, snum, title, string.atoi(pageno), [])
57 if stype == level:
58 toc.append(entry)
59 else:
60 direction = _transition_map[(level, stype)]
61 if direction == OUTER_TO_INNER:
62 toc = toc[-1][-1]
63 stack.insert(0, toc)
64 toc.append(entry)
65 else:
66 for i in range(direction):
67 del stack[0]
68 toc = stack[0]
69 toc.append(entry)
70 level = stype
71 else:
72 sys.stderr.write("l.%s: " + line)
73 return top
74
75
76hackscore_rx = re.compile(r"\\(hackscore|raisebox)\s*{[^}]*}")
77title_rx = re.compile(r"\\[a-zA-Z]+\s*")
78title_trans = string.maketrans("", "")
79
80def clean_title(title):
81 title = hackscore_rx.sub("_", title)
82 while 1:
83 m = title_rx.search(title)
84 if m:
85 title = title[:m.start()] + title[m.end():]
86 else:
87 break
88 return string.translate(title, title_trans, "{}")
89
90
91def write_toc(toc, fp):
92 for entry in toc:
93 write_toc_entry(entry, fp, 0)
94
95def write_toc_entry(entry, fp, layer):
96 stype, snum, title, pageno, toc = entry
97 s = "\\pdfoutline goto name{page.%d}" % pageno
98 if toc:
99 s = "%s count -%d" % (s, len(toc))
100 if snum:
101 title = "%s %s" % (snum, title)
102 s = "%s {%s}\n" % (s, title)
103 fp.write(s)
104 for entry in toc:
105 write_toc_entry(entry, fp, layer + 1)
106
107
108def main():
Fred Drake473a90e1998-03-07 15:34:50 +0000109 bigpart = None
110 opts, args = getopt.getopt(sys.argv[1:], "c:")
111 if opts:
112 bigpart = opts[0][1]
113 if not args:
114 usage()
115 sys.exit(2)
116 for filename in args:
117 base, ext = os.path.splitext(filename)
118 ext = ext or ".toc"
119 toc = parse_toc(open(base + ext), bigpart)
120 write_toc(toc, open(base + ".bkm", "w"))
Fred Drake361ee651998-03-06 21:29:00 +0000121
122
123if __name__ == "__main__":
124 main()