Files

162 lines
5.1 KiB
Python

#####################################################################
# NOTE: This is a modified version of decompctx.py. #
# Originally written by the PrimeDecomp team: #
# https://github.com/PrimeDecomp/prime/blob/main/tools/decompctx.py #
#####################################################################
from sys import platform, argv
from subprocess import Popen, PIPE
from os import walk, path
from os.path import join, exists, relpath, dirname, abspath, realpath
from re import compile
INCLUDE_DIR = "include/"
SRC_DIR = "src/"
STL_INCLUDE_DIR = "include/MSL"
RVL_INCLUDE_DIR = "include/revolution"
TYPES_H_PATH = f"{RVL_INCLUDE_DIR}/types.h"
SCRIPT_DIR = dirname(realpath(__file__))
ROOT_DIR = abspath(join(SCRIPT_DIR, ".."))
SRC_DIR = join(ROOT_DIR, "src")
INCLUDE_PATTERN = compile(r'^#include\s*[<"](.+?)[>"]$')
GUARD_PATTERN = compile(r"^#ifndef\s+(.*)$")
GUARD_IFDEF_PATTERN = compile(r"^#ifdef\s+(.*)$")
GUARD_ELSE_PATTERN = compile(r"^#else\s*$")
GUARD_END_PATTERN = compile(r"^#endif\s*$")
DEFINES = set()
def main():
if len(argv) < 2:
print("[FATAL] Please supply a source file name.")
exit(0)
src_file = resolve_src_name(argv[1])
print()
print("[INFO] Generating context...")
# Generate context file
with open("ctx.c", "w+") as f:
print(import_c_file(src_file), file=f)
print("[INFO] Context written to ./ctx.c!")
# Copy to clipboard if on Windows
try:
with open("ctx.c", "r") as f:
copy_to_clip("".join(f.readlines()))
except OSError:
# Not a big deal really
pass
def copy_to_clip(text: str):
if platform == "win32":
Popen(['CLIP'], stdin=PIPE).communicate(text.encode())
print("[INFO] Copied to clipboard!")
def resolve_src_name(src_file) -> str:
# Is the source file an absolute path?
try:
with open(src_file, "r") as tmp:
return src_file
# Relative path to some directory, try to find that directory
except OSError:
print(
f"[INFO] Source file ({src_file}) appears to be a relative path.")
print("[INFO] Attempting to resolve to an absolute path...")
# Convert any path separators in the source file to what is expected
src_file = src_file.replace("/", path.sep)
src_file = src_file.replace("\\", path.sep)
for _root, _dirs, _files in walk(SRC_DIR):
for file in _files:
p = join(_root, file)
# Case sensitive check
found = p.endswith(src_file)
# Case insensitive check (on Windows)
if platform == "win32":
found = found or p.lower().endswith(src_file.lower())
if found:
print(
f"[INFO] I think you are referring to this file: {p}")
return p
print("[FATAL] Sorry, but I don't know what file you want.")
exit()
def import_h_file(in_file, r_path) -> str:
# Only non-STL relative include should be types.h
if in_file == "revolution/types.h" or in_file == "types.h" and exists(TYPES_H_PATH):
return import_h_file_as_c(TYPES_H_PATH)
# Try root directory
rel_path = join(ROOT_DIR, r_path, in_file)
if exists(rel_path):
return import_h_file_as_c(rel_path)
# Try root include directory
inc_path = join(INCLUDE_DIR, in_file)
if exists(inc_path):
return import_h_file_as_c(inc_path)
# Try root include directory
inc_path = join(STL_INCLUDE_DIR, in_file)
if exists(inc_path):
return import_h_file_as_c(inc_path)
print(f"Failed to locate header: {in_file}")
return ""
def import_h_file_as_c(in_file) -> str:
in_file = relpath(in_file, ROOT_DIR)
out_text = ""
with open(in_file) as file:
for idx, line in enumerate(file):
# Header guard
guard_match = GUARD_PATTERN.match(line.strip())
if guard_match:
# At the beginning of the file = actually a header guard
if idx == 0:
if guard_match[1] in DEFINES:
break
DEFINES.add(guard_match[1])
# Sub-include
include_match = INCLUDE_PATTERN.match(line.strip())
if include_match:
out_text += f'/* "{in_file}" line {idx} "{include_match[1]}" */\n'
out_text += import_h_file(include_match[1], dirname(in_file))
out_text += f'/* end "{include_match[1]}" */\n'
# File text
else:
out_text += line
return out_text
def import_c_file(in_file) -> str:
in_file = relpath(in_file, ROOT_DIR)
out_text = ""
with open(in_file) as file:
for idx, line in enumerate(file):
# Sub-include
include_match = INCLUDE_PATTERN.match(line.strip())
if include_match:
out_text += f'/* "{in_file}" line {idx} "{include_match[1]}" */\n'
out_text += import_h_file(include_match[1], dirname(in_file))
out_text += f'/* end "{include_match[1]}" */\n'
return out_text
main()