bug 1034: making room for crfbinlog/crfternlogi/crbinlog/crternlogi
[libreriscv.git] / openpower / texmunge.py
1 #!/usr/bin/env python3
2
3 from collections import defaultdict
4 import sys
5 import re
6
7
8 def merge_continuation_lines(lines: "list[str]"):
9 nest_level = 0
10 cur = []
11 for line in lines:
12 cur.append(line)
13 nest_level += len(re.findall(r"(?<!\\)\{", line))
14 nest_level -= len(re.findall(r"(?<!\\)\}", line))
15 assert nest_level >= 0, "too many closing }"
16 if nest_level == 0:
17 yield ''.join(cur)
18 cur.clear()
19 assert nest_level == 0, "missing closing }"
20
21
22 def merge_footnotes(lines: "list[str]"):
23 inp_ctr = 0
24 footnote_inp_ctr_to_text_map: "dict[int, str]" = {}
25
26 def replace_footnotemark(match):
27 nonlocal inp_ctr
28 print(f"input footnote ref #{inp_ctr}")
29 retval = "\\footnotemark{" + str(inp_ctr) + "}"
30 inp_ctr += 1
31 return retval
32
33 tmpl_lines = [] # template lines
34 for line in merge_continuation_lines(lines):
35 parts = line.split(r'\footnotetext')
36 if len(parts) > 1:
37 assert len(parts) == 2 and parts[0] == '', \
38 "\\footnotetext must only be at the beginning of a line"
39 nest_level = 0
40 footnote_parts = []
41 trailing_parts = []
42 after_footnote = False
43 for part in re.split(r'(?<!\\)(\{|\})', parts[1]):
44 if part == '{':
45 nest_level += 1
46 if nest_level == 1 and not after_footnote:
47 continue # remove leading {
48 if part == '}':
49 nest_level -= 1
50 if nest_level == 0 and not after_footnote:
51 after_footnote = True
52 continue # remove trailing }
53 if after_footnote:
54 trailing_parts.append(part)
55 elif nest_level:
56 footnote_parts.append(part)
57 footnote_text = ''.join(footnote_parts)
58 trailing_text = ''.join(trailing_parts)
59 print(f"input footnote #{inp_ctr - 1}: {footnote_text[:30]}")
60 footnote_inp_ctr_to_text_map[inp_ctr - 1] = footnote_text
61 line = "\\footnotetext{}" + trailing_text
62
63 match = re.fullmatch(
64 r"\\addtocounter\{footnote\}\{(-?[1-9][0-9]*)\}\n", line)
65 if match:
66 adj = int(match.group(1))
67 inp_ctr += adj
68 print(f"adjust input footnote counter by {adj} to {inp_ctr}")
69 continue
70 line = re.sub(r"\\footnotemark\{\}", replace_footnotemark, line)
71 tmpl_lines.append(line)
72 footnote_text_to_id_map: "dict[str, int]" = {}
73 next_footnote_id = 1
74 footnote_queue: "list[str]" = []
75
76 def replace_footnotemark_tmpl(match: "re.Match[str]"):
77 nonlocal next_footnote_id
78 inp_ctr = int(match.group(1))
79 text = footnote_inp_ctr_to_text_map[inp_ctr]
80 footnote_id = footnote_text_to_id_map.get(text)
81 if footnote_id is None:
82 footnote_id = next_footnote_id
83 next_footnote_id += 1
84 footnote_text_to_id_map[text] = footnote_id
85 footnote_queue.append(
86 "\\footnotetext["
87 + str(footnote_id) + "]{" + text + "}")
88 return "\\footnotemark[" + str(footnote_id) + "]"
89
90 retval = []
91 for line in tmpl_lines:
92 parts = line.split(r'\footnotetext{}')
93 if len(parts) > 1:
94 if len(footnote_queue) == 0:
95 line = parts[1]
96 else:
97 line = footnote_queue.pop() + parts[1]
98 for footnote in footnote_queue:
99 retval.append(footnote + "\n")
100 footnote_queue.clear()
101 line = re.sub(r"\\footnotemark\{([0-9]+)\}",
102 replace_footnotemark_tmpl, line)
103 retval.append(line)
104 return retval
105
106
107 with open(sys.argv[1], "r") as f:
108 lines = list(f.readlines())
109
110 with open(sys.argv[2], "w") as o:
111 if sys.argv[1].endswith("comparison_table_pre.tex"):
112 o.write("\\renewcommand{\\footnotesize}"
113 "{\\fontsize{6pt}{4pt}\\selectfont}\n")
114 lines = merge_footnotes(lines)
115
116 for line in lines:
117 if sys.argv[1].endswith("comparison_table_pre.tex") and \
118 line.startswith(r"\begin{itemize}"):
119 o.write(line)
120 o.write("\\itemsep -0.6em\n")
121 continue
122 o.write(line)