1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-23 21:43:51 +01:00
RIOT/dist/tools/headerguards/headerguards.py
crasbe 193b5e1a91 dist/tools/headerguards: revert 082a37b
With the migration to #pragma once in the core header in #21405,
the workaround for the header name check when using #include_next
is not necessary anymore and can be dropped.
2025-05-14 12:07:41 +02:00

114 lines
3.5 KiB
Python
Executable File

#!/usr/bin/env python3
import os
import sys
import difflib
from io import BytesIO, TextIOWrapper
_in = "/-."
_out = "___"
transtab = str.maketrans(_in, _out)
def path_to_guardname(filepath):
res = filepath.upper().translate(transtab)
if res.startswith("_"):
res = "PRIV" + res
return res
def get_guard_name(filepath):
parts = filepath.split(os.sep)
start = 0
found = False
for i, part in enumerate(parts):
if part == "include":
found = True
start = i + 1
break
if not found:
start = len(parts) - 1
return path_to_guardname(os.path.join(*parts[start:]))
def fix_headerguard(filename):
supposed = get_guard_name(filename)
with open(filename, "r", encoding='utf-8', errors='ignore') as f:
inlines = f.readlines()
tmp = TextIOWrapper(BytesIO(), encoding="utf-8", errors="ignore")
tmp.seek(0)
guard_found = 0
pragma_once_found = 0
guard_name = ""
ifstack = 0
for line in inlines:
if line.startswith("#pragma once"):
pragma_once_found += 1
elif line.lstrip().startswith("#pragma once"):
# check for lines that have leading whitespaces and add a correction
pragma_once_found += 1
line = "#pragma once\n"
if guard_found == 0:
if pragma_once_found == 0 and line.startswith("#ifndef"):
guard_found += 1
guard_name = line[8:].rstrip()
line = "#ifndef %s\n" % (supposed)
elif pragma_once_found != 0 and line.startswith("#ifndef %s" % supposed):
# check if there is pragma once *and* headerguards, but avoid false
# positives by narrowing in on the to-be-expected guard
guard_found += 1
guard_name = line[8:].rstrip()
line = ""
elif guard_found == 1:
if line.startswith("#define") and line[8:].rstrip() == guard_name:
line = "#define %s\n" % (supposed)
guard_found += 1
else:
break
elif guard_found == 2:
if line.startswith("#if"):
ifstack += 1
elif line.startswith("#endif"):
if ifstack > 0:
ifstack -= 1
else:
guard_found += 1
line = "#endif /* %s */\n" % supposed
tmp.write(line)
tmp.seek(0)
if (pragma_once_found == 0 and guard_found == 3) or \
(pragma_once_found == 1 and guard_found == 0):
# Valid cases:
# - no #pragma once, classic headerguards (#ifndef, #define, #endif)
# - one #pragma once, no classic headerguards
for line in difflib.unified_diff(inlines, tmp.readlines(),
"%s" % filename, "%s" % filename):
sys.stdout.write(line)
elif (pragma_once_found == 0 and guard_found == 0):
print("%s: no header guards found" % filename, file=sys.stderr)
return False
elif (pragma_once_found == 1 and guard_found != 0):
print("%s: #pragma once and classic header guards used in the same file" %
filename, file=sys.stderr)
return False
else:
print("%s: broken header guard" % filename, file=sys.stderr)
return False
if __name__ == "__main__":
error = False
for filename in sys.argv[1:]:
if fix_headerguard(filename) is False:
error = True
if error:
sys.exit(1)