#!/usr/bin/env python3 """ Generate src/logos_data.inc from the ANSI art files under logos/. Each ANSI logo is converted into a NULL-terminated array of C string literals so render.c can embed them directly without needing to parse files at runtime. """ from __future__ import annotations import argparse from pathlib import Path LOGO_SOURCES = [ ("logo_86_dos", "logos/86.ans"), ("logo_concurrentdos", "logos/concurrentdos.ans"), ("logo_dos", "logos/dos.ans"), ("logo_dosbian", "logos/dosbian.ans"), ("logo_dosbox", "logos/dosbox.ans"), ("logo_dosbox_staging", "logos/dosbox_staging.ans"), ("logo_dosbox_x", "logos/dosbox_x.ans"), ("logo_dr_dos", "logos/drdos.ans"), ("logo_freedos", "logos/freedos.ans"), ("logo_ms_dos", "logos/msdos.ans"), ("logo_novell_dos", "logos/novell.ans"), ("logo_pc_dos", "logos/ibmdos.ans"), ] def split_lines(path: Path) -> list[bytes]: """Return the ANSI file as a list of raw lines without line endings.""" data = path.read_bytes() # splitlines() handles CRLF/CR/LF and preserves empty lines. return data.splitlines() def to_c_literal(line: bytes) -> str: """Convert a raw line to a C string literal with escaped bytes.""" pieces = ['"'] for byte in line: if byte == 0x5C: # backslash pieces.append("\\\\") elif byte == 0x22: # double quote pieces.append('\\"') elif byte == 0x07: pieces.append("\\a") elif byte == 0x08: pieces.append("\\b") elif byte == 0x09: pieces.append("\\t") elif byte == 0x0C: pieces.append("\\f") elif byte == 0x0B: pieces.append("\\v") elif 0x20 <= byte <= 0x7E: pieces.append(chr(byte)) else: pieces.append(f"\\x{byte:02x}") pieces.append('"') return "".join(pieces) def generate(output: Path) -> None: root = Path(__file__).resolve().parents[1] lines = [ "/* Auto-generated by tools/generate_logos_data.py. Do not edit. */", "", ] for symbol, rel_path in LOGO_SOURCES: logo_path = root / rel_path if not logo_path.exists(): raise FileNotFoundError(f"Missing logo file: {logo_path}") lines.append(f"static const char *const {symbol}[] = {{") for raw_line in split_lines(logo_path): lines.append(f" {to_c_literal(raw_line)},") lines.append(" NULL,") lines.append("};") lines.append("") output_path = root / output output_path.write_text("\n".join(lines), encoding="utf-8") def main() -> None: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument( "-o", "--output", default="src/logos_data.inc", type=Path, help="Path to write the generated include (default: %(default)s)", ) args = parser.parse_args() generate(args.output) if __name__ == "__main__": main()