diff --git a/server/src/tools/def_symbols.py b/server/src/tools/def_symbols.py new file mode 100644 index 0000000..8e48b9c --- /dev/null +++ b/server/src/tools/def_symbols.py @@ -0,0 +1,36 @@ +"""Block templates and addresses declared in NX post definition (.def) files.""" + +import re +from dataclasses import dataclass, field +from pathlib import Path + +_BLOCK_TEMPLATE_RE = re.compile(r"^\s*BLOCK_TEMPLATE\s+([^\s{]+)", re.MULTILINE) +_ADDRESS_RE = re.compile(r"^\s*ADDRESS\s+([^\s{]+)", re.MULTILINE) + + +@dataclass(frozen=True) +class DefSymbols: + block_templates: tuple[str, ...] = () + addresses: tuple[str, ...] = () + + +def _names(pattern: re.Pattern, source: str) -> tuple[str, ...]: + return tuple(dict.fromkeys(pattern.findall(source))) + + +def parse_def_symbols(source: str) -> DefSymbols: + """Return the BLOCK_TEMPLATE and ADDRESS names of a .def source in declaration order.""" + return DefSymbols( + block_templates=_names(_BLOCK_TEMPLATE_RE, source), + addresses=_names(_ADDRESS_RE, source), + ) + + +def read_def_symbols(path: Path) -> DefSymbols: + data = path.read_bytes() + try: + source = data.decode("utf-8-sig") + except UnicodeDecodeError: + # Older Windows NX layers use the ANSI code page. + source = data.decode("cp1252") + return parse_def_symbols(source)