1
0
Fork 0
mirror of https://github.com/zeldaret/oot.git synced 2024-12-26 06:36:19 +00:00
oot/tools/preprocess.py
Dragorn421 cd2264f018
Handle multiline #pragma increment_block_number (#2023)
* Handle multiline #pragma increment_block_number

* fix: align all continuation characters vertically

* simplify continuation line character alignment

* Update tools/fix_bss.py

Co-authored-by: cadmic <cadmic24@gmail.com>

---------

Co-authored-by: cadmic <cadmic24@gmail.com>
2024-08-09 20:13:59 -04:00

110 lines
3.8 KiB
Python
Executable file

#!/usr/bin/env python3
# SPDX-FileCopyrightText: © 2024 ZeldaRET
# SPDX-License-Identifier: CC0-1.0
# Usage: preprocess.py [flags] -- [compile command minus input file...] [single input file]
# Preprocess a C file to:
# * Re-encode from UTF-8 to EUC-JP (the repo uses UTF-8 for text encoding, but
# the strings in the ROM are encoded in EUC-JP)
# * Replace `#pragma increment_block_number` with fake structs for controlling BSS ordering
import argparse
from pathlib import Path
import re
import tempfile
import subprocess
import sys
import typing
def fail(message):
print(message, file=sys.stderr)
sys.exit(1)
def process_file(
version: str,
filename: str,
input: typing.TextIO,
output: typing.TextIO,
):
output.write(f'#line 1 "{filename}"\n')
# whether the current line follows a #pragma increment_block_number,
# including continuation lines (lines after a \-ending line)
in_pragma_incblocknum = False
# the line where the #pragma increment_block_number is
pragma_incblocknum_first_line_num = None
# all the lines from the #pragma increment_block_number line to the last
# continuation line, as a list[str]
pragma_incblocknum_lines = None
for i, line in enumerate(input, start=1):
if not in_pragma_incblocknum and line.startswith(
"#pragma increment_block_number"
):
in_pragma_incblocknum = True
pragma_incblocknum_first_line_num = i
pragma_incblocknum_lines = []
if in_pragma_incblocknum:
if line.endswith("\\\n"):
pragma_incblocknum_lines.append(line)
else:
in_pragma_incblocknum = False
pragma_incblocknum_lines.append(line)
amount = 0
for s in pragma_incblocknum_lines:
# Note if we had two versions like "abc-def-version" and "def-version"
# then this code would find either given "def-version", but
# thankfully we don't have such nested version names.
m = re.search(rf"{version}:(\d+)\b", s)
if m:
amount = int(m.group(1))
break
# Always generate at least one struct,
# so that fix_bss.py can know where the increment_block_number pragmas are
if amount == 0:
amount = 256
# Write fake structs for BSS ordering
# pragma_incblocknum_first_line_num is used for symbol uniqueness, and
# also by fix_bss.py to locate the pragma these symbols originate from.
for j in range(amount):
output.write(
"struct increment_block_number_"
f"{pragma_incblocknum_first_line_num:05}_{j:03};\n"
)
output.write(f'#line {i + 1} "{filename}"\n')
else:
output.write(line)
def main():
parser = argparse.ArgumentParser()
parser.add_argument("-v", "--oot-version", help="Which version should be processed")
parser.add_argument(
"args",
nargs="+",
)
args = parser.parse_args()
filename = Path(args.args[-1])
with tempfile.TemporaryDirectory(prefix="oot_") as tmpdir:
tmpfile = Path(tmpdir) / filename.name
with open(filename, mode="r", encoding="utf-8") as input:
with open(tmpfile, mode="w", encoding="euc-jp") as output:
process_file(args.oot_version, filename, input, output)
compile_command = args.args[:-1] + ["-I", filename.parent, tmpfile]
process = subprocess.run(compile_command)
return process.returncode
if __name__ == "__main__":
try:
sys.exit(main())
except KeyboardInterrupt:
sys.exit(1)