diff --git a/docs/genhhk.py b/docs/genhhk.py new file mode 100644 index 000000000..f699a09ca --- /dev/null +++ b/docs/genhhk.py @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- +"""Generate the .hhk keyword index for the CHM build. + +Sphinx's htmlhelp builder writes an empty x64dbgdoc.hhk because the docs +don't use index directives. This script fills it with one entry per page, +keyed by the page's , so the CHM gets a usable Index tab. + +Usage: python genhhk.py _build/htmlhelp/x64dbgdoc.hhp +Compatible with Python 2.7 (the portable build) and Python 3. +""" + +from __future__ import print_function, unicode_literals + +import io +import os +import re +import sys + +TITLE_RE = re.compile(r"<title>(.*?)", re.IGNORECASE | re.DOTALL) + +ENTRY = ( + '
  • \n' + '\n' + '\n' + "\n" +) + + +def parse_files_section(hhp_path): + files = [] + in_files = False + with io.open(hhp_path, "r", encoding="utf-8") as f: + for line in f: + line = line.strip() + if line.startswith("["): + in_files = line == "[FILES]" + continue + if in_files and line: + files.append(line) + return files + + +def extract_title(html_path): + with io.open(html_path, "rb") as f: + data = f.read() + # Sphinx (py2) occasionally emits cp1252 bytes in files declared utf-8 + try: + text = data.decode("utf-8") + except UnicodeDecodeError: + text = data.decode("cp1252") + match = TITLE_RE.search(text) + if not match: + return None + return " ".join(match.group(1).split()) + + +def escape_value(text): + # Pure-ASCII output so hhc.exe (ANSI) and pyhhc agree on the encoding + out = [] + for ch in text: + if ch == '"': + out.append(""") + elif ord(ch) > 126: + out.append("&#{0};".format(ord(ch))) + else: + out.append(ch) + return "".join(out) + + +def main(): + if len(sys.argv) != 2: + print("Usage: genhhk.py ") + return 1 + + hhp_path = sys.argv[1] + base_dir = os.path.dirname(os.path.abspath(hhp_path)) + hhk_path = os.path.splitext(hhp_path)[0] + ".hhk" + + entries = [] + for rel in parse_files_section(hhp_path): + if not rel.lower().endswith((".htm", ".html")): + continue + html_path = os.path.join(base_dir, rel.replace("\\", os.sep)) + if not os.path.isfile(html_path): + print("warning: missing file: " + rel) + continue + title = extract_title(html_path) + if not title: + print("warning: no in: " + rel) + continue + local = rel.replace("\\", "/") + entries.append((title, local)) + + entries.sort(key=lambda e: (e[0].lower(), e[1])) + + with io.open(hhk_path, "w", encoding="utf-8", newline="\n") as f: + f.write("<UL>\n") + for title, local in entries: + f.write(ENTRY.format(escape_value(title), local)) + f.write("</UL>\n") + + print("Wrote {0} index entries to {1}".format(len(entries), hhk_path)) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/docs/makechm.bat b/docs/makechm.bat index 615696dd0..9f0c8222a 100644 --- a/docs/makechm.bat +++ b/docs/makechm.bat @@ -41,6 +41,9 @@ if %ERRORLEVEL% neq 0 exit /b %ERRORLEVEL% echo Applying CHM hacks copy theme.js .\_build\htmlhelp\_static\js\theme.js type hacks.css >> .\_build\htmlhelp\_static\css\theme.css +echo Generating keyword index +"%PORTABLE_PYTHON%\python.exe" genhhk.py .\_build\htmlhelp\x64dbgdoc.hhp +if %ERRORLEVEL% neq 0 exit /b %ERRORLEVEL% echo Building CHM File hhc.exe .\_build\htmlhelp\x64dbgdoc.hhp copy /Y .\_build\htmlhelp\x64dbgdoc.chm x64dbg.chm