rename_api.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. #!/usr/bin/env python3
  2. # WHAT IS THIS?
  3. # This script renames symbols in the API, updating SDL_oldnames.h and
  4. # adding documentation for the change.
  5. import argparse
  6. import os
  7. import pathlib
  8. import pprint
  9. import re
  10. from rename_symbols import create_regex_from_replacements, replace_symbols_in_path
  11. SDL_ROOT = pathlib.Path(__file__).resolve().parents[1]
  12. SDL_INCLUDE_DIR = SDL_ROOT / "include/SDL3"
  13. def main():
  14. # Check whether we can still modify the ABI
  15. version_header = pathlib.Path( SDL_INCLUDE_DIR / "SDL_version.h" ).read_text()
  16. if not re.search("SDL_MINOR_VERSION\s+[01]\s", version_header):
  17. raise Exception("ABI is frozen, symbols cannot be renamed")
  18. pattern = re.compile(r"\b%s\b" % args.oldname)
  19. # Find the symbol in the headers
  20. if pathlib.Path(args.header).is_file():
  21. header = pathlib.Path(args.header)
  22. else:
  23. header = pathlib.Path(SDL_INCLUDE_DIR / args.header)
  24. if not header.exists():
  25. raise Exception("Couldn't find header %s" % header)
  26. if not args.skip_header_check and not pattern.search(header.read_text()):
  27. raise Exception("Couldn't find %s in %s" % (args.oldname, header))
  28. # Replace the symbol in source code and documentation
  29. replacements = {
  30. args.oldname: args.newname,
  31. args.oldname + "_REAL": args.newname + "_REAL"
  32. }
  33. regex = create_regex_from_replacements(replacements)
  34. for dir in ["src", "test", "include", "docs", "Xcode-iOS/Demos"]:
  35. replace_symbols_in_path(SDL_ROOT / dir, regex, replacements)
  36. add_symbol_to_oldnames(header.name, args.oldname, args.newname)
  37. add_symbol_to_migration(header.name, args.type, args.oldname, args.newname)
  38. add_symbol_to_whatsnew(args.type, args.oldname, args.newname)
  39. def add_line(lines, i, section):
  40. lines.insert(i, section)
  41. i += 1
  42. return i
  43. def add_content(lines, i, content, add_trailing_line):
  44. if lines[i - 1] == "":
  45. lines[i - 1] = content
  46. else:
  47. i = add_line(lines, i, content)
  48. if add_trailing_line:
  49. i = add_line(lines, i, "")
  50. return i
  51. def add_symbol_to_oldnames(header, oldname, newname):
  52. file = (SDL_INCLUDE_DIR / "SDL_oldnames.h")
  53. lines = file.read_text().splitlines()
  54. mode = 0
  55. i = 0
  56. while i < len(lines):
  57. line = lines[i]
  58. if line == "#ifdef SDL_ENABLE_OLD_NAMES":
  59. if mode == 0:
  60. mode = 1
  61. section = ("/* ##%s */" % header)
  62. section_added = False
  63. content = ("#define %s %s" % (oldname, newname))
  64. content_added = False
  65. else:
  66. raise Exception("add_symbol_to_oldnames(): expected mode 0")
  67. elif line == "#else /* !SDL_ENABLE_OLD_NAMES */":
  68. if mode == 1:
  69. if not section_added:
  70. i = add_line(lines, i, section)
  71. if not content_added:
  72. i = add_content(lines, i, content, True)
  73. mode = 2
  74. section = ("/* ##%s */" % header)
  75. section_added = False
  76. content = ("#define %s %s_renamed_%s" % (oldname, oldname, newname))
  77. content_added = False
  78. else:
  79. raise Exception("add_symbol_to_oldnames(): expected mode 1")
  80. elif line == "#endif /* SDL_ENABLE_OLD_NAMES */":
  81. if mode == 2:
  82. if not section_added:
  83. i = add_line(lines, i, section)
  84. if not content_added:
  85. i = add_content(lines, i, content, True)
  86. mode = 3
  87. else:
  88. raise Exception("add_symbol_to_oldnames(): expected mode 2")
  89. elif line != "" and (mode == 1 or mode == 2):
  90. if line.startswith("/* ##"):
  91. if section_added:
  92. if not content_added:
  93. i = add_content(lines, i, content, True)
  94. content_added = True
  95. elif line == section:
  96. section_added = True
  97. elif section < line:
  98. i = add_line(lines, i, section)
  99. section_added = True
  100. i = add_content(lines, i, content, True)
  101. content_added = True
  102. elif line != "" and section_added and not content_added:
  103. if content == line:
  104. content_added = True
  105. elif content < line:
  106. i = add_content(lines, i, content, False)
  107. content_added = True
  108. i += 1
  109. file.write_text("\n".join(lines) + "\n")
  110. def add_symbol_to_migration(header, symbol_type, oldname, newname):
  111. file = (SDL_ROOT / "docs/README-migration.md")
  112. lines = file.read_text().splitlines()
  113. section = ("## %s" % header)
  114. section_added = False
  115. note = ("The following %ss have been renamed:" % symbol_type)
  116. note_added = False
  117. content = ("* %s => %s" % (oldname, newname))
  118. content_added = False
  119. mode = 0
  120. i = 0
  121. while i < len(lines):
  122. line = lines[i]
  123. if line.startswith("##") and line.endswith(".h"):
  124. if line == section:
  125. section_added = True
  126. elif section < line:
  127. break
  128. elif section_added and not note_added:
  129. if note == line:
  130. note_added = True
  131. elif note_added and not content_added:
  132. if content == line:
  133. content_added = True
  134. elif line == "" or content < line:
  135. i = add_line(lines, i, content)
  136. content_added = True
  137. i += 1
  138. if not section_added:
  139. i = add_line(lines, i, section)
  140. i = add_line(lines, i, "")
  141. if not note_added:
  142. i = add_line(lines, i, note)
  143. if not content_added:
  144. i = add_content(lines, i, content, True)
  145. file.write_text("\n".join(lines) + "\n")
  146. def add_symbol_to_whatsnew(symbol_type, oldname, newname):
  147. file = (SDL_ROOT / "WhatsNew.txt")
  148. lines = file.read_text().splitlines()
  149. note = ("* The following %ss have been renamed:" % symbol_type)
  150. note_added = False
  151. content = (" * %s => %s" % (oldname, newname))
  152. content_added = False
  153. mode = 0
  154. i = 0
  155. while i < len(lines):
  156. line = lines[i]
  157. if not note_added:
  158. if note == line:
  159. note_added = True
  160. elif not content_added:
  161. if content == line:
  162. content_added = True
  163. elif not line.startswith(" *") or content < line:
  164. i = add_line(lines, i, content)
  165. content_added = True
  166. i += 1
  167. if not note_added:
  168. i = add_line(lines, i, note)
  169. if not content_added:
  170. i = add_line(lines, i, content)
  171. file.write_text("\r\n".join(lines) + "\r\n")
  172. if __name__ == '__main__':
  173. parser = argparse.ArgumentParser()
  174. parser.add_argument('--skip-header-check', action='store_true')
  175. parser.add_argument('header');
  176. parser.add_argument('type', choices=['enum', 'function', 'macro', 'structure']);
  177. parser.add_argument('oldname');
  178. parser.add_argument('newname');
  179. args = parser.parse_args()
  180. try:
  181. main()
  182. except Exception as e:
  183. print(e)
  184. exit(-1)
  185. exit(0)