#!/usr/bin/env python3 """Split a handler source file into one file per UMCPHandler class. Usage: python3 tools/split-handlers.py Reads the #include block from the top of the file, then splits at the closing }; (column 0) of each UMCPHandler class. Each output file is named after the handler class and placed in the same directory. The shared #include block is prepended to every output file. """ import sys import re import os def main(): if len(sys.argv) != 2: print(f"Usage: {sys.argv[0]} ") sys.exit(1) filepath = sys.argv[1] with open(filepath) as f: lines = f.readlines() # Extract the #include block from the top of the file. # Collect #pragma, #include, blank lines, and // comment lines # until we hit something else. include_block = [] body_start = 0 for i, line in enumerate(lines): stripped = line.strip() if (stripped == '' or stripped.startswith('#pragma') or stripped.startswith('#include') or stripped.startswith('//')): include_block.append(line) else: body_start = i break # Strip trailing blank/comment lines from include block while include_block and include_block[-1].strip() in ('', ) or ( include_block and include_block[-1].strip().startswith('//')): body_start -= 1 include_block.pop() if not include_block: break # Remove the .generated.h include from the shared block (each output # file gets its own). include_block = [l for l in include_block if '.generated.h' not in l] body_lines = lines[body_start:] # Find split points in the body: after each }; that closes a UMCPHandler. handler_name = None splits = [] # list of (end_index_exclusive_in_body, class_name) for i, line in enumerate(body_lines): m = re.match(r'class (UMCPHandler_\w+)', line) if m: handler_name = m.group(1) if line.startswith('};') and handler_name: splits.append((i + 1, handler_name)) handler_name = None if not splits: print("No UMCPHandler classes found.") sys.exit(1) dirname = os.path.dirname(filepath) start = 0 for end, name in splits: outpath = os.path.join(dirname, name + '.h') with open(outpath, 'w') as f: f.writelines(include_block) f.write(f'#include "{name}.generated.h"\n') f.write('\n') f.writelines(body_lines[start:end]) print(f" {name}.h ({end - start} lines)") start = end # Warn about trailing content if start < len(body_lines): remaining = ''.join(body_lines[start:]).strip() if remaining: print(f"Warning: {len(body_lines) - start} trailing lines not included in any output file:") for line in body_lines[start:]: print(f" | {line}", end='') if __name__ == '__main__': main()