Files
LithosAnanke/docs/formal/fix-doxygen-unicode.py
T
rajamesandClaude Opus 5.5 5b58b0b16e docs(formal): make doxygen builds -- the Unicode fix-up keeps newunicodechar's characters
fix-doxygen-unicode.py protected the first argument of each
\doxynewunicodechar{...} from its replacements, then turned every
non-ASCII character left in the file -- the protected ones too -- into
"?" and wrote the file as ASCII. refman.tex's \doxynewunicodechar{⁻},
{²} and {³} became \doxynewunicodechar{?}, and newunicodechar stopped
the build: "ASCII character requested".

The "?" fallback now applies to the unprotected parts of each line
only, and the file is written as UTF-8.

make -C docs/formal doxygen, from clean, with doxygen 1.9.8: exit 0,
build/doxygen/StarForth-API-Reference.pdf, 3561 pages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
2026-11-06 02:21:21 +00:00

151 lines
5.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
fix-doxygen-unicode.py — replace problematic Unicode characters in
Doxygen-generated LaTeX files with pdflatex-safe equivalents.
Run this on the doxygen/latex/ directory before calling pdflatex.
"""
import os, sys, re
REPLACEMENTS = [
# Math symbols
('≈', r'\ensuremath{\approx}'),
('≤', r'\ensuremath{\leq}'),
('≥', r'\ensuremath{\geq}'),
('≠', r'\ensuremath{\neq}'),
('±', r'\ensuremath{\pm}'),
('×', r'\ensuremath{\times}'),
('÷', r'\ensuremath{\div}'),
('∞', r'\ensuremath{\infty}'),
('∑', r'\ensuremath{\sum}'),
('∏', r'\ensuremath{\prod}'),
('∫', r'\ensuremath{\int}'),
('√', r'\ensuremath{\sqrt{\cdot}}'),
('∂', r'\ensuremath{\partial}'),
('∆', r'\ensuremath{\Delta}'),
('∇', r'\ensuremath{\nabla}'),
('∈', r'\ensuremath{\in}'),
('∉', r'\ensuremath{\notin}'),
('∩', r'\ensuremath{\cap}'),
('∪', r'\ensuremath{\cup}'),
('⊂', r'\ensuremath{\subset}'),
('⊃', r'\ensuremath{\supset}'),
('∀', r'\ensuremath{\forall}'),
('∃', r'\ensuremath{\exists}'),
('∧', r'\ensuremath{\wedge}'),
('∨', r'\ensuremath{\vee}'),
('¬', r'\ensuremath{\neg}'),
# Arrows
('←', r'\ensuremath{\leftarrow}'),
('→', r'\ensuremath{\rightarrow}'),
('↑', r'\ensuremath{\uparrow}'),
('↓', r'\ensuremath{\downarrow}'),
('↔', r'\ensuremath{\leftrightarrow}'),
('⇒', r'\ensuremath{\Rightarrow}'),
('⇐', r'\ensuremath{\Leftarrow}'),
('⇔', r'\ensuremath{\Leftrightarrow}'),
# Greek letters
('α', r'\ensuremath{\alpha}'),
('β', r'\ensuremath{\beta}'),
('γ', r'\ensuremath{\gamma}'),
('δ', r'\ensuremath{\delta}'),
('ε', r'\ensuremath{\varepsilon}'),
('θ', r'\ensuremath{\theta}'),
('λ', r'\ensuremath{\lambda}'),
('μ', r'\ensuremath{\mu}'),
('π', r'\ensuremath{\pi}'),
('σ', r'\ensuremath{\sigma}'),
('τ', r'\ensuremath{\tau}'),
('φ', r'\ensuremath{\phi}'),
('ω', r'\ensuremath{\omega}'),
('Δ', r'\ensuremath{\Delta}'),
('Σ', r'\ensuremath{\Sigma}'),
('Ω', r'\ensuremath{\Omega}'),
# Superscripts/subscripts
('⁻', r'\ensuremath{{}^{-}}'),
('⁺', r'\ensuremath{{}^{+}}'),
('²', r'\ensuremath{{}^{2}}'),
('³', r'\ensuremath{{}^{3}}'),
('⁰', r'\ensuremath{{}^{0}}'),
('¹', r'\ensuremath{{}^{1}}'),
# Box-drawing (from ASCII art in comments)
('├', r'\textbar{}'),
('│', r'\textbar{}'),
('└', r'`'),
('┌', r'.'),
('┐', r'.'),
('┘', r"'"),
('─', r'-'),
('═', r'='),
('║', r'\textbar{}'),
('╔', r'.'),
('╗', r'.'),
('╚', r'.'),
('╝', r'.'),
('╠', r'\textbar{}'),
('╣', r'\textbar{}'),
('╦', r'-'),
('╩', r'-'),
('╬', r'+'),
# Misc
('·', r'\ensuremath{\cdot}'),
('°', r'\ensuremath{{}^{\circ}}'),
('™', r'\texttrademark{}'),
('®', r'\textregistered{}'),
('©', r'\textcopyright{}'),
('…', r'\ldots{}'),
('–', r'--'),
('—', r'---'),
('‘', r'`'), # left single quote
('’', r"'"), # right single quote
('“', r'``'), # left double quote
('”', r"''"), # right double quote
]
def fix_line(line):
# Protect \doxynewunicodechar{CHAR}{...} and \newunicodechar{CHAR}{...}
# first arguments — these must stay as literal Unicode chars.
# Strategy: split on these patterns, fix only the non-protected parts.
import re
parts = re.split(r'(\\(?:doxy)?newunicodechar\{[^}]*\})', line)
result = []
for i, part in enumerate(parts):
if i % 2 == 1: # protected token — preserve as-is
result.append(part)
else:
for char, replacement in REPLACEMENTS:
part = part.replace(char, replacement)
# Replace any remaining non-ASCII with ? placeholder -- here, and
# not over the whole file, so that the protected tokens keep their
# Unicode: a \doxynewunicodechar{?} is an ASCII character, which
# newunicodechar refuses ("ASCII character requested").
part = part.encode('ascii', errors='replace').decode('ascii')
result.append(part)
return ''.join(result)
def fix_file(path):
with open(path, encoding='utf-8', errors='replace') as f:
lines = f.readlines()
original = ''.join(lines)
fixed_lines = [fix_line(l) for l in lines]
content = ''.join(fixed_lines)
if content != original:
with open(path, 'w', encoding='utf-8') as f:
f.write(content)
return True
return False
def main():
latex_dir = sys.argv[1] if len(sys.argv) > 1 else '.'
fixed = 0
for root, _, files in os.walk(latex_dir):
for fname in files:
if fname.endswith('.tex') or fname.endswith('.sty'):
path = os.path.join(root, fname)
if fix_file(path):
fixed += 1
print(f"Fixed {fixed} files in {latex_dir}")
if __name__ == '__main__':
main()