header_guards.py 2.5 KB

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