blob: 0a17f46d13b2e11c892f1b1e4bee90dbad3e96a5 [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
Fred Drake25d4e281998-05-14 20:07:10 +000019#
20# The return value of parse_toc() is such a tuple.
Fred Drake361ee651998-03-06 21:29:00 +000021
22cline_re = r"""^
23\\contentsline\ \{([a-z]*)} # type of section in $1
24\{(?:\\numberline\ \{([0-9.A-Z]+)})? # section number
25(.*)} # title string
26\{(\d+)}$""" # page number
27
28cline_rx = re.compile(cline_re, re.VERBOSE)
29
30OUTER_TO_INNER = -1
31
32_transition_map = {
33 ('chapter', 'section'): OUTER_TO_INNER,
34 ('section', 'subsection'): OUTER_TO_INNER,
35 ('subsection', 'subsubsection'): OUTER_TO_INNER,
36 ('subsubsection', 'subsection'): 1,
37 ('subsection', 'section'): 1,
38 ('section', 'chapter'): 1,
39 ('subsection', 'chapter'): 2,
40 ('subsubsection', 'section'): 2,
41 ('subsubsection', 'chapter'): 3,
42 }
43
Fred Drake473a90e1998-03-07 15:34:50 +000044def parse_toc(fp, bigpart=None):
Fred Drake361ee651998-03-06 21:29:00 +000045 toc = top = []
46 stack = [toc]
Fred Drake473a90e1998-03-07 15:34:50 +000047 level = bigpart or 'chapter'
Fred Drake361ee651998-03-06 21:29:00 +000048 lineno = 0
49 while 1:
50 line = fp.readline()
51 if not line:
52 break
53 lineno = lineno + 1
54 m = cline_rx.match(line)
55 if m:
56 stype, snum, title, pageno = m.group(1, 2, 3, 4)
57 title = clean_title(title)
58 entry = (stype, snum, title, string.atoi(pageno), [])
59 if stype == level:
60 toc.append(entry)
61 else:
62 direction = _transition_map[(level, stype)]
63 if direction == OUTER_TO_INNER:
64 toc = toc[-1][-1]
65 stack.insert(0, toc)
66 toc.append(entry)
67 else:
68 for i in range(direction):
69 del stack[0]
70 toc = stack[0]
71 toc.append(entry)
72 level = stype
73 else:
74 sys.stderr.write("l.%s: " + line)
75 return top
76
77
Fred Drakeac77b791998-03-10 14:02:35 +000078hackscore_rx = re.compile(r"\\hackscore\s*{[^}]*}")
79raisebox_rx = re.compile(r"\\raisebox\s*{[^}]*}")
80title_rx = re.compile(r"\\([a-zA-Z])+\s+")
Fred Drake361ee651998-03-06 21:29:00 +000081title_trans = string.maketrans("", "")
82
83def clean_title(title):
Fred Drakeac77b791998-03-10 14:02:35 +000084 title = raisebox_rx.sub("", title)
85 title = hackscore_rx.sub(r"\\_", title)
86 pos = 0
Fred Drake361ee651998-03-06 21:29:00 +000087 while 1:
Fred Drakeac77b791998-03-10 14:02:35 +000088 m = title_rx.search(title, pos)
Fred Drake361ee651998-03-06 21:29:00 +000089 if m:
Fred Drakeac77b791998-03-10 14:02:35 +000090 start = m.start()
Fred Drakeac77b791998-03-10 14:02:35 +000091 if title[start:start+15] != "\\textunderscore":
92 title = title[:start] + title[m.end():]
93 pos = start + 1
Fred Drake361ee651998-03-06 21:29:00 +000094 else:
95 break
Fred Drakeac77b791998-03-10 14:02:35 +000096 title = string.translate(title, title_trans, "{}")
Fred Drakeac77b791998-03-10 14:02:35 +000097 return title
Fred Drake361ee651998-03-06 21:29:00 +000098
99
100def write_toc(toc, fp):
101 for entry in toc:
102 write_toc_entry(entry, fp, 0)
103
104def write_toc_entry(entry, fp, layer):
105 stype, snum, title, pageno, toc = entry
Fred Drakebf88c381998-04-15 17:50:22 +0000106 s = "\\pdfoutline goto name{page%03d}" % pageno
Fred Drake361ee651998-03-06 21:29:00 +0000107 if toc:
108 s = "%s count -%d" % (s, len(toc))
109 if snum:
110 title = "%s %s" % (snum, title)
111 s = "%s {%s}\n" % (s, title)
112 fp.write(s)
113 for entry in toc:
114 write_toc_entry(entry, fp, layer + 1)
115
116
117def main():
Fred Drake473a90e1998-03-07 15:34:50 +0000118 bigpart = None
119 opts, args = getopt.getopt(sys.argv[1:], "c:")
120 if opts:
121 bigpart = opts[0][1]
122 if not args:
123 usage()
124 sys.exit(2)
125 for filename in args:
126 base, ext = os.path.splitext(filename)
127 ext = ext or ".toc"
128 toc = parse_toc(open(base + ext), bigpart)
129 write_toc(toc, open(base + ".bkm", "w"))
Fred Drake361ee651998-03-06 21:29:00 +0000130
131
132if __name__ == "__main__":
133 main()