3 # Usage: check-include-guard.py [--fix] FILE
5 # Checks (and optionally tries to fix) the C/C++ header include guard
6 # names and format of `FILE`.
8 # With `--fix`, this script fixes the include guard names in place.
16 class _Oops(Exception):
17 def __init__(self
, msg
: str):
25 def _make_expected_ig_name(filename
: pathlib
.Path
):
26 # Normalize `filename` (e.g. remove `..`) and make it relative to
27 # the root of the source tree.
28 root
= pathlib
.Path(__file__
).parent
.parent
.resolve(strict
=True)
29 filename
= filename
.absolute().resolve(strict
=True).relative_to(root
)
31 expected_ig_name
= re
.sub(r
"[/.-]", "_", str(filename
)).upper()
32 expected_ig_name
= re
.sub(r
"^SRC_", "", expected_ig_name
)
33 return "BABELTRACE_" + expected_ig_name
36 def _check_file(filename
: pathlib
.Path
, fix
: bool):
37 with
open(filename
) as f
:
43 top_re
= re
.compile(r
"^(/\*.+?\*/)\n\n#ifndef (\w+)\n#define (\w+)\n", re
.DOTALL
)
44 top_m
= top_re
.match(contents
)
48 "Top of the file doesn't have the expected form: block comment, empty line, and then two include guard lines"
51 expected_ig_name
= _make_expected_ig_name(filename
)
54 contents
= top_re
.sub(
55 rf
"\1\n\n#ifndef {expected_ig_name}\n#define {expected_ig_name}\n",
60 if top_m
.group(2) != expected_ig_name
:
62 f
"In `#ifndef {top_m.group(2)}` include guard line: expecting `#ifndef {expected_ig_name}`"
65 if top_m
.group(3) != expected_ig_name
:
67 f
"In `#define {top_m.group(3)}` include guard line: expecting `#define {expected_ig_name}`"
71 bottom_re
= re
.compile(r
"\n\n#endif(?: /\* (\w+) \*/)?\n$")
72 bottom_m
= bottom_re
.search(contents
)
75 raise _Oops("Missing final `#endif` include guard line and trailing empty line")
78 contents
= bottom_re
.sub(f
"\n\n#endif /* {expected_ig_name} */\n", contents
)
81 if bottom_m
.group(1) != expected_ig_name
:
83 f
"In bottom `#endif` include guard line: expecting `#endif /* {expected_ig_name} */`"
87 with
open(filename
, "w") as f
:
92 argparser
= argparse
.ArgumentParser()
93 argparser
.add_argument(
97 help="attempt to fix the include guards of FILE",
99 argparser
.add_argument("FILE")
100 args
= argparser
.parse_args()
101 filename
= pathlib
.Path(args
.FILE
)
104 _check_file(filename
, args
.fix
)
106 print(f
"{filename}: {exc}", file=sys
.stderr
)
110 if __name__
== "__main__":
This page took 0.033478 seconds and 5 git commands to generate.