header_guards.py 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. #!/usr/bin/env python3
  2. import sys
  3. if len(sys.argv) < 2:
  4. print("Invalid usage of header_guards.py, it should be called with a path to one or multiple files.")
  5. sys.exit(1)
  6. changed = []
  7. invalid = []
  8. for file in sys.argv[1:]:
  9. header_start = -1
  10. header_end = -1
  11. with open(file.strip(), "rt", encoding="utf-8", newline="\n") as f:
  12. lines = f.readlines()
  13. for idx, line in enumerate(lines):
  14. sline = line.strip()
  15. if header_start < 0:
  16. if sline == "": # Skip empty lines at the top.
  17. continue
  18. if sline.startswith("/**********"): # Godot header starts this way.
  19. header_start = idx
  20. else:
  21. header_end = 0 # There is no Godot header.
  22. break
  23. else:
  24. if not sline.startswith(("*", "/*")): # Not in the Godot header anymore.
  25. header_end = idx + 1 # The guard should be two lines below the Godot header.
  26. break
  27. if (HEADER_CHECK_OFFSET := header_end) < 0 or HEADER_CHECK_OFFSET >= len(lines):
  28. invalid.append(file)
  29. continue
  30. if lines[HEADER_CHECK_OFFSET].startswith("#pragma once"):
  31. continue
  32. # Might be using legacy header guards.
  33. HEADER_BEGIN_OFFSET = HEADER_CHECK_OFFSET + 1
  34. HEADER_END_OFFSET = len(lines) - 1
  35. if HEADER_BEGIN_OFFSET >= HEADER_END_OFFSET:
  36. invalid.append(file)
  37. continue
  38. if (
  39. lines[HEADER_CHECK_OFFSET].startswith("#ifndef")
  40. and lines[HEADER_BEGIN_OFFSET].startswith("#define")
  41. and lines[HEADER_END_OFFSET].startswith("#endif")
  42. ):
  43. lines[HEADER_CHECK_OFFSET] = "#pragma once"
  44. lines[HEADER_BEGIN_OFFSET] = "\n"
  45. lines.pop()
  46. with open(file, "wt", encoding="utf-8", newline="\n") as f:
  47. f.writelines(lines)
  48. changed.append(file)
  49. continue
  50. # Verify `#pragma once` doesn't exist at invalid location.
  51. misplaced = False
  52. for line in lines:
  53. if line.startswith("#pragma once"):
  54. misplaced = True
  55. break
  56. if misplaced:
  57. invalid.append(file)
  58. continue
  59. # Assume that we're simply missing a guard entirely.
  60. lines.insert(HEADER_CHECK_OFFSET, "#pragma once\n\n")
  61. with open(file, "wt", encoding="utf-8", newline="\n") as f:
  62. f.writelines(lines)
  63. changed.append(file)
  64. if changed:
  65. for file in changed:
  66. print(f"FIXED: {file}")
  67. if invalid:
  68. for file in invalid:
  69. print(f"REQUIRES MANUAL CHANGES: {file}")
  70. sys.exit(1)