1"""Post-process Doxygen's refman.tex before pdflatex, to match the Cryptnox PDF style.
3Usage: python3 docs/patch_latex.py docs/latex/refman.tex ["Friendly Title"]
10title = sys.argv[2]
if len(sys.argv) > 2
else None
16except ImportError
as _e:
18 "PDF docs build requires cairosvg to generate the cover logo; "
19 "install it (pip install cairosvg)."
22 url=os.path.join(os.path.dirname(path), os.pardir,
"cryptnox-logo.svg"),
23 write_to=os.path.join(os.path.dirname(path),
"cryptnox-logo-dark.pdf"),
26with open(path, encoding=
"utf-8")
as _f:
31s = s.replace(
r"\usepackage[scaled=.90]{helvet}",
"\\usepackage{tgheros}\n\\usepackage{tgtermes}")
34s = re.sub(
r"\{\\large Generated by Doxygen[^}]*\}\\\\\s*",
"", s)
40 "\\begin{center}%\n {\\Large",
41 "\\begin{flushright}%\n"
43 " \\includegraphics[width=7cm]{cryptnox-logo-dark}\\par\n"
48 "\\end{center}\n \\end{titlepage}",
49 "\\end{flushright}\n \\vfill\n \\begin{flushright}\\large June 20, 2026\\end{flushright}\n \\end{titlepage}",
55 s = re.sub(
r"\{\\Large [^}]*\}\\\\",
56 lambda m:
r"{\LARGE\sffamily\bfseries " + title +
r" Manual}\\", s, count=1)
58 s = re.sub(
r"\{\\Large ([^}]*)\}\\\\",
r"{\\LARGE\\sffamily\\bfseries \1 Manual}\\\\", s, count=1)
62s = re.sub(
r"\[1ex\]\\large (.*?) \\\\",
r"[1.5em]{\\large\\itshape Release \1}\\\\", s, count=1)
67 r"\\doxyallsectionsfont\{%\s*\\fontseries\{bc\}\\selectfont%\s*\\color\{darkgray\}%\s*\}",
69 r"\doxyallsectionsfont{\sffamily\bfseries\color{black}}"
71 "\n\\renewcommand{\\@makechapterhead}[1]{%"
72 "\n \\vspace*{50\\p@}{\\parindent\\z@\\raggedright\\sffamily"
73 "\n \\ifnum\\c@secnumdepth>\\m@ne"
74 "\n \\huge\\bfseries\\color{black}\\@chapapp\\space\\thechapter\\par\\nobreak\\vskip 20\\p@\\fi"
75 "\n \\interlinepenalty\\@M\\Huge\\bfseries\\color{black}#1\\par\\nobreak\\vskip 40\\p@}}"
76 "\n\\renewcommand{\\@makeschapterhead}[1]{%"
77 "\n \\vspace*{50\\p@}{\\parindent\\z@\\raggedright\\sffamily"
78 "\n \\interlinepenalty\\@M\\Huge\\bfseries\\color{black}#1\\par\\nobreak\\vskip 40\\p@}}"
85s = s.replace(
r"\documentclass[twoside]",
r"\documentclass[oneside]")
90 r"\bfseries\scriptsize Generated by Doxygen",
91 r"\sffamily\fontsize{11}{13.6}\selectfont \copyright{} 2026 Cryptnox SA",
95s = s.replace(
r"\fancyhead[LE, RO]{\bfseries\thepage}",
r"\fancyhead[LE, RO]{\sffamily\fontsize{11}{13.6}\selectfont\thepage}")
96s = s.replace(
r"\fancyhead[LO]{\bfseries\rightmark}",
r"\fancyhead[LO]{\sffamily\fontsize{11}{13.6}\selectfont\rightmark}")
97s = s.replace(
r"\fancyhead[RE]{\bfseries\leftmark}",
r"\fancyhead[RE]{\sffamily\fontsize{11}{13.6}\selectfont\leftmark}")
100s = s.replace(
r"\tableofcontents",
r"\addtocontents{toc}{\protect\sffamily}\tableofcontents", 1)
104 r"\pagestyle{fancyplain}",
105 r"\def\headruleskip{4pt}\def\footruleskip{4pt}\pagestyle{fancyplain}",
115 "\\DeclareUnicodeCharacter{2264}{\\ensuremath{\\leq}}\n"
116 "\\DeclareUnicodeCharacter{2265}{\\ensuremath{\\geq}}\n"
122s = s.replace(
r"\printindex",
"")
123s = s.replace(
r"\addcontentsline{toc}{chapter}{\indexname}",
"")
127s = s.replace(
r"\vspace*{7cm}",
r"\noindent\rule{\textwidth}{1pt}\par")
129with open(path,
"w", encoding=
"utf-8")
as _f:
131print(
"patched", path)
135sty = os.path.join(os.path.dirname(path),
"doxygen.sty")
136if os.path.exists(sty):
137 with open(sty, encoding=
"utf-8")
as _f:
139 d = d.replace(
r"{\raggedright\normalfont",
r"{\raggedright\sffamily\color{black}")
140 with open(sty,
"w", encoding=
"utf-8")
as _f:
142 print(
"patched", sty)
146idx = os.path.join(os.path.dirname(path),
"index.tex")
147if os.path.exists(idx):
148 with open(idx, encoding=
"utf-8")
as _f:
150 i = re.sub(
r"^.*Download this documentation as PDF.*\n",
"", i, flags=re.MULTILINE)
151 with open(idx,
"w", encoding=
"utf-8")
as _f:
153 print(
"patched", idx)
168 0x00A0, 0x00B2, 0x00B3, 0x00D7,
169 0x2013, 0x2014, 0x2026,
170 0x2018, 0x2019, 0x201C, 0x201D,
171 0x2190, 0x2192, 0x2194,
177 cp = ord(match.group(0))
180 elif 0x2500 <= cp <= 0x257F:
182 if cp
in (0x2502, 0x2503, 0x2551):
184 elif 0x250C <= cp <= 0x254B:
193for tex
in glob.glob(os.path.join(os.path.dirname(path),
"*.tex")):
194 with open(tex, encoding=
"utf-8")
as _f:
200 marker =
"\\begin{document}"
201 split = body.find(marker)
202 head = body[:split]
if split != -1
else ""
203 tail = body[split:]
if split != -1
else body
204 fixed = head + re.sub(
r"[^\x00-\x7F]", _to_ascii, tail)
206 with open(tex,
"w", encoding=
"utf-8")
as _f:
208 print(
"transliterated", tex)