-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathcheck_include_guards.py
executable file
·88 lines (67 loc) · 2.43 KB
/
check_include_guards.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#!/usr/bin/env python3
import os, os.path, re, subprocess
__GUARD = re.compile(
"^.*?\n\s*#ifndef\s+([^\s]+)\s+#define\s+([^\s]+).*?#endif\s+$",
re.DOTALL)
__ALL_GUARDS = {}
class IncludeGuardException(Exception):
def __init__(self, message):
self.message = message
def read_without_comments(path):
command = ["gcc", "-fpreprocessed", "-dD", "-E", path]
return subprocess.run(command,
stdout=subprocess.PIPE,
universal_newlines=True).stdout
def read_last_line(path):
with open(path, "r") as f:
return f.read().splitlines()[-1]
def check_prefix(prefix, name, path):
if not name.startswith(prefix):
raise IncludeGuardException(
"{} include guard should begin with {}".format(path, prefix))
def join_path_parts(prefix, parts):
parts = map(lambda c: re.sub("[^A-Za-z0-9_]", "_", c).upper(), parts)
return prefix + "_".join(parts)
def check_postfix(prefix, name, path):
parts = path.split(os.path.sep)[1:]
goodname = join_path_parts(prefix, parts)
if goodname != name:
raise IncludeGuardException(
"{} include guard should be named {}".format(path, goodname))
if goodname in __ALL_GUARDS:
raise IncludeGuardException(
"There's an include guard conflict between {} and {}".format(
path, __ALL_GUARDS[goodname]))
__ALL_GUARDS[goodname] = path
def check_header(prefix, path):
output = read_without_comments(path)
m = __GUARD.search(output)
if not m:
raise IncludeGuardException(
"{} doesn't seem to be protected by a proper include guard.".format(path))
if m.group(1) != m.group(2):
raise IncludeGuardException(
"{} begins with a malformed include guard.".format(path))
name = m.group(1)
check_prefix(prefix, name, path)
check_postfix(prefix, name, path)
last_line = read_last_line(path)
exp_last_line = "#endif // {}".format(name)
if last_line != exp_last_line:
raise IncludeGuardException(
"{} should end with {}".format(path, exp_last_line))
def try_check_header(prefix, path):
try:
check_header(prefix, path)
except IncludeGuardException as e:
print(e.message)
def checkdir(dirname, prefix):
for (dirpath, _, filenames) in os.walk(dirname):
for filename in filenames:
if filename.endswith(".h"):
try_check_header(prefix, os.path.join(dirpath, filename))
def check_include_guards():
checkdir("kudos", "KUDOS_")
checkdir("userland", "KUDOS_USERLAND_")
if __name__ == "__main__":
check_include_guards()