Simple Directmedia Layer
at main 8.1 kB view raw
1#!/usr/bin/env python3 2# 3# This script renames symbols in the API, updating SDL_oldnames.h and 4# adding documentation for the change. 5 6import argparse 7import os 8import pathlib 9import pprint 10import re 11import sys 12from rename_symbols import create_regex_from_replacements, replace_symbols_in_path 13 14SDL_ROOT = pathlib.Path(__file__).resolve().parents[1] 15 16SDL_INCLUDE_DIR = SDL_ROOT / "include/SDL3" 17SDL_BUILD_SCRIPTS = SDL_ROOT / "build-scripts" 18 19 20def main(): 21 if len(args.args) == 0 or (len(args.args) % 2) != 0: 22 print("Usage: %s [-h] [--skip-header-check] header {enum,function,hint,structure,symbol} [old new ...]" % sys.argv[0]) 23 exit(1) 24 25 # Check whether we can still modify the ABI 26 version_header = pathlib.Path( SDL_INCLUDE_DIR / "SDL_version.h" ).read_text() 27 if not re.search(r"SDL_MINOR_VERSION\s+[01]\s", version_header): 28 raise Exception("ABI is frozen, symbols cannot be renamed") 29 30 # Find the symbol in the headers 31 if pathlib.Path(args.header).is_file(): 32 header = pathlib.Path(args.header) 33 else: 34 header = pathlib.Path(SDL_INCLUDE_DIR / args.header) 35 36 if not header.exists(): 37 raise Exception("Couldn't find header %s" % header) 38 39 header_name = header.name 40 if (header.name == "SDL_gamepad.h"): 41 header_name = "SDL_gamecontroller.h" 42 43 header_text = header.read_text() 44 45 # Replace the symbols in source code 46 replacements = {} 47 i = 0 48 while i < len(args.args): 49 oldname = args.args[i + 0] 50 newname = args.args[i + 1] 51 52 if not args.skip_header_check and not re.search((r"\b%s\b" % oldname), header_text): 53 raise Exception("Couldn't find %s in %s" % (oldname, header)) 54 55 replacements[ oldname ] = newname 56 replacements[ oldname + "_REAL" ] = newname + "_REAL" 57 i += 2 58 59 regex = create_regex_from_replacements(replacements) 60 for dir in ["src", "test", "examples", "include", "docs", "cmake/test"]: 61 replace_symbols_in_path(SDL_ROOT / dir, regex, replacements) 62 63 # Replace the symbols in documentation 64 i = 0 65 while i < len(args.args): 66 oldname = args.args[i + 0] 67 newname = args.args[i + 1] 68 69 add_symbol_to_oldnames(header_name, oldname, newname) 70 add_symbol_to_migration(header_name, args.type, oldname, newname) 71 add_symbol_to_coccinelle(args.type, oldname, newname) 72 i += 2 73 74 75def add_line(lines, i, section): 76 lines.insert(i, section) 77 i += 1 78 return i 79 80 81def add_content(lines, i, content, add_trailing_line): 82 if lines[i - 1] == "": 83 lines[i - 1] = content 84 else: 85 i = add_line(lines, i, content) 86 87 if add_trailing_line: 88 i = add_line(lines, i, "") 89 return i 90 91 92def add_symbol_to_coccinelle(symbol_type, oldname, newname): 93 file = open(SDL_BUILD_SCRIPTS / "SDL_migration.cocci", "a") 94 # Append-adds at last 95 96 if symbol_type == "function": 97 file.write("@@\n") 98 file.write("@@\n") 99 file.write("- %s\n" % oldname) 100 file.write("+ %s\n" % newname) 101 file.write(" (...)\n") 102 103 if symbol_type == "symbol": 104 file.write("@@\n") 105 file.write("@@\n") 106 file.write("- %s\n" % oldname) 107 file.write("+ %s\n" % newname) 108 109 # double check ? 110 if symbol_type == "hint": 111 file.write("@@\n") 112 file.write("@@\n") 113 file.write("- %s\n" % oldname) 114 file.write("+ %s\n" % newname) 115 116 if symbol_type == "enum" or symbol_type == "structure": 117 file.write("@@\n") 118 file.write("typedef %s, %s;\n" % (oldname, newname)) 119 file.write("@@\n") 120 file.write("- %s\n" % oldname) 121 file.write("+ %s\n" % newname) 122 123 file.close() 124 125 126def add_symbol_to_oldnames(header, oldname, newname): 127 file = (SDL_INCLUDE_DIR / "SDL_oldnames.h") 128 lines = file.read_text().splitlines() 129 mode = 0 130 i = 0 131 while i < len(lines): 132 line = lines[i] 133 if line == "#ifdef SDL_ENABLE_OLD_NAMES": 134 if mode == 0: 135 mode = 1 136 section = ("/* ##%s */" % header) 137 section_added = False 138 content = ("#define %s %s" % (oldname, newname)) 139 content_added = False 140 else: 141 raise Exception("add_symbol_to_oldnames(): expected mode 0") 142 elif line == "#elif !defined(SDL_DISABLE_OLD_NAMES)": 143 if mode == 1: 144 if not section_added: 145 i = add_line(lines, i, section) 146 147 if not content_added: 148 i = add_content(lines, i, content, True) 149 150 mode = 2 151 section = ("/* ##%s */" % header) 152 section_added = False 153 content = ("#define %s %s_renamed_%s" % (oldname, oldname, newname)) 154 content_added = False 155 else: 156 raise Exception("add_symbol_to_oldnames(): expected mode 1") 157 elif line == "#endif /* SDL_ENABLE_OLD_NAMES */": 158 if mode == 2: 159 if not section_added: 160 i = add_line(lines, i, section) 161 162 if not content_added: 163 i = add_content(lines, i, content, True) 164 165 mode = 3 166 else: 167 raise Exception("add_symbol_to_oldnames(): expected mode 2") 168 elif line != "" and (mode == 1 or mode == 2): 169 if line.startswith("/* ##"): 170 if section_added: 171 if not content_added: 172 i = add_content(lines, i, content, True) 173 content_added = True 174 elif line == section: 175 section_added = True 176 elif section < line: 177 i = add_line(lines, i, section) 178 section_added = True 179 i = add_content(lines, i, content, True) 180 content_added = True 181 elif line != "" and section_added and not content_added: 182 if content == line: 183 content_added = True 184 elif content < line: 185 i = add_content(lines, i, content, False) 186 content_added = True 187 i += 1 188 189 file.write_text("\n".join(lines) + "\n") 190 191 192def add_symbol_to_migration(header, symbol_type, oldname, newname): 193 file = (SDL_ROOT / "docs/README-migration.md") 194 lines = file.read_text().splitlines() 195 section = ("## %s" % header) 196 section_added = False 197 note = ("The following %ss have been renamed:" % symbol_type) 198 note_added = False 199 if symbol_type == "function": 200 content = ("* %s() => %s()" % (oldname, newname)) 201 else: 202 content = ("* %s => %s" % (oldname, newname)) 203 content_added = False 204 mode = 0 205 i = 0 206 while i < len(lines): 207 line = lines[i] 208 if line.startswith("##") and line.endswith(".h"): 209 if line == section: 210 section_added = True 211 elif section < line: 212 break 213 214 elif section_added and not note_added: 215 if note == line: 216 note_added = True 217 elif note_added and not content_added: 218 if content == line: 219 content_added = True 220 elif line == "" or content < line: 221 i = add_line(lines, i, content) 222 content_added = True 223 i += 1 224 225 if not section_added: 226 i = add_line(lines, i, section) 227 i = add_line(lines, i, "") 228 229 if not note_added: 230 i = add_line(lines, i, note) 231 232 if not content_added: 233 i = add_content(lines, i, content, True) 234 235 file.write_text("\n".join(lines) + "\n") 236 237 238if __name__ == "__main__": 239 240 parser = argparse.ArgumentParser(fromfile_prefix_chars='@') 241 parser.add_argument("--skip-header-check", action="store_true") 242 parser.add_argument("header") 243 parser.add_argument("type", choices=["enum", "function", "hint", "structure", "symbol"]) 244 parser.add_argument("args", nargs="*") 245 args = parser.parse_args() 246 247 try: 248 main() 249 except Exception as e: 250 print(e) 251 exit(-1) 252 253 exit(0) 254