summaryrefslogtreecommitdiff
path: root/tools/decompctx.py
blob: d243c66c8d2653b271e68ec11bb2783c84816f73 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#!/usr/bin/env python3

###
# Generates a ctx.c file, usable for "Context" on https://decomp.me.
#
# Usage:
#   python3 tools/decompctx.py src/file.cpp
#
# If changes are made, please submit a PR to
# https://github.com/encounter/dtk-template
###

import argparse
import os
import re

script_dir = os.path.dirname(os.path.realpath(__file__))
root_dir = os.path.abspath(os.path.join(script_dir, ".."))
src_dir = os.path.join(root_dir, "src")
include_dirs = [
   os.path.join(root_dir, "include"),
   os.path.join(root_dir, "include/dolphin"),
   os.path.join(root_dir, "libs/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common/Include"),
   os.path.join(root_dir, "libs/PowerPC_EABI_Support/MSL/MSL_C/MSL_Common_Embedded/Math/Include"),
   os.path.join(root_dir, "libs/PowerPC_EABI_Support/MSL/MSL_C/PPC_EABI/Include"),
   os.path.join(root_dir, "libs/PowerPC_EABI_Support/MSL/MSL_C++/MSL_Common/Include"),
   os.path.join(root_dir, "libs/PowerPC_EABI_Support/Runtime/Inc"),
]

include_pattern = re.compile(r'^#include\s*[<"](.+?)[>"]$')
guard_pattern = re.compile(r'^#ifndef\s+(.*)$')

defines = set()

def import_h_file(in_file: str, r_path: str) -> str:
    rel_path = os.path.join(root_dir, r_path, in_file)
    if os.path.exists(rel_path):
      return import_c_file(rel_path)
    else:
      for inc_dir in include_dirs:
        inc_path = os.path.join(inc_dir, in_file)
        if os.path.exists(inc_path):
          return import_c_file(inc_path)
      else:
        print("Failed to locate", in_file)
        exit(1)

def import_c_file(in_file) -> str:
    in_file = os.path.relpath(in_file, root_dir)
    out_text = ''

    try:
      with open(in_file, encoding="shift-jis") as file:
        out_text += process_file(in_file, list(file))
    except Exception:
      with open(in_file) as file:
        out_text += process_file(in_file, list(file))
    return out_text

def process_file(in_file: str, lines) -> str:
    out_text = ''
    for idx, line in enumerate(lines):
      guard_match = guard_pattern.match(line.strip())
      if idx == 0:
        if guard_match:
          if guard_match[1] in defines:
            break
          defines.add(guard_match[1])
        print("Processing file", in_file)
      include_match = include_pattern.match(line.strip())
      if include_match and not include_match[1].endswith(".s"):
        out_text += f"/* \"{in_file}\" line {idx} \"{include_match[1]}\" */\n"
        out_text += import_h_file(include_match[1], os.path.dirname(in_file))
        out_text += f"/* end \"{include_match[1]}\" */\n"
      else:
        out_text += line

    return out_text

def main():
    parser = argparse.ArgumentParser(
        description="""Create a context file which can be used for decomp.me"""
    )
    parser.add_argument(
        "c_file",
        help="""File from which to create context""",
    )
    args = parser.parse_args()

    output = import_c_file(args.c_file)

    with open(os.path.join(root_dir, "ctx.c"), "w", encoding="utf-8") as f:
        f.write(output)


if __name__ == "__main__":
    main()