3 # Clean up include guards in headers
5 # Copyright (C) 2016 Red Hat, Inc.
8 # Markus Armbruster <armbru@redhat.com>
10 # This work is licensed under the terms of the GNU GPL, version 2 or
11 # (at your option) any later version. See the COPYING file in the
12 # top-level directory.
14 # Usage: scripts/clean-header-guards.pl [OPTION]... [FILE]...
15 # -c CC Use a compiler other than cc
16 # -n Suppress actual cleanup
17 # -v Show which files are cleaned up, and which are skipped
20 # - Header files without a recognizable header guard are skipped.
21 # - Clean up any untidy header guards in-place. Warn if the cleanup
22 # renames guard symbols, and explain how to find occurences of these
23 # symbols that may have to be updated manually.
24 # - Warn about duplicate header guard symbols. To make full use of
25 # this warning, you should clean up *all* headers in one run.
26 # - Warn when preprocessing a header with its guard symbol defined
27 # produces anything but whitespace. The preprocessor is run like
28 # "cc -E -DGUARD_H -c -P -", and fed the test program on stdin.
33 # Stuff we don't want to clean because we import it into our tree:
34 my $exclude = qr
,^(disas
/libvixl
/|include
/standard
-headers
/
35 |linux
-headers
/|pc
-bios
/|tests
/tcg
/|tests/multiboot
/),x
;
36 # Stuff that is expected to fail the preprocessing test:
37 my $exclude_cpp = qr
,^include
/libdecnumber/decNumberLocal
.h
,;
48 my ($fname, $msg, $line1, $line2) = @_;
50 return if !$opt_v or $fname =~ $exclude;
51 print "$fname skipped: $msg\n";
52 print " $line1" if defined $line1;
53 print " $line2" if defined $line2;
57 my ($fname, $msg) = @_;
58 return if $fname =~ $exclude;
59 print STDERR
"$fname: warning: $msg\n";
65 open(my $in, "<", $fname)
66 or die "can't open $fname for reading: $!";
71 my ($fname, $contents) = @_;
72 open (my $out, ">", $fname)
73 or die "can't open $fname for writing: $!";
75 or die "error writing $fname: $!";
77 or die "error writing $fname: $!";
82 $fname =~ tr/a-z/A-Z/;
83 $fname =~ tr/A-Z0-9/_/cs;
88 my ($fname, $guard) = @_;
90 open(my $pipe, "-|", "$opt_c -E -D$guard -c -P - <$fname")
91 or die "can't run $opt_c: $!";
94 gripe
($fname, "not blank after preprocessing");
99 or gripe
($fname, "preprocessing failed ($opt_c exit status $?)");
102 for my $fname (@ARGV) {
103 my $text = slurp
($fname);
105 $text =~ m
,\A
(\s
*\n|\s
*//\N
*\n|\s
*/\*.*?\*/\s
*\n)*|,msg
;
107 unless ($text =~ /\G(.*\n)/g) {
109 skipping
($fname, "no recognizable header guard", "$&\n");
113 unless ($text =~ /\G(.*\n)/g) {
115 skipping
($fname, "no recognizable header guard", "$&\n");
119 my $body = substr($text, pos($text));
121 unless ($line1 =~ /^\s
*\#\s
*(if\s
*\
!\s
*defined(\s
*\
()?
|ifndef
)\s
*
123 skipping
($fname, "no recognizable header guard", $line1, $line2);
127 unless ($line2 =~ /^\s*\#\s*define\s+([A-Za-z0-9_]+)/) {
128 skipping
($fname, "no recognizable header guard", $line1, $line2);
132 unless ($guard2 eq $guard) {
133 skipping
($fname, "mismatched header guard ($guard vs. $guard2) ",
138 unless ($body =~ m
,\A
((.*\n)*)
139 (\s
*\#\s
*endif\s
*(/\*\s*.*\s*\*/\s
*)?
\n?
)
141 skipping
($fname, "can't find end of header guard");
146 my $endif_comment = $4;
150 unless ($fname =~ $exclude) {
152 $guard =~ tr/a-z/A-Z/
153 and push @issues, "contains lowercase letters";
155 and push @issues, "is a reserved identifier";
156 $guard =~ s/(_H)?_*$/_H/
157 and $& ne "_H" and push @issues, "doesn't end with _H";
158 unless ($guard =~ /^[A-Z][A-Z0-9_]*_H/) {
159 skipping
($fname, "can't clean up odd guard symbol $oldg\n",
164 my $exp = fname2guard
($fname =~ s
,.*/,,r
);
165 unless ($guard =~ /\Q$exp\E\Z/) {
166 $guard = fname2guard
($fname =~ s
,^include
/,,r
);
167 push @issues, "doesn't match the file name";
169 if (@issues and $opt_v) {
170 print "$fname guard $oldg needs cleanup:\n ",
171 join(", ", @issues), "\n";
175 $old_guard{$guard} = $oldg
178 if (exists $guarded{$guard}) {
179 gripe
($fname, "guard $guard also used by $guarded{$guard}");
181 $guarded{$guard} = $fname;
184 unless ($fname =~ $exclude) {
185 my $newl1 = "#ifndef $guard\n";
186 my $newl2 = "#define $guard\n";
187 my $newl3 = "#endif\n";
188 $newl3 =~ s
,\Z
, /* $guard */, if defined $endif_comment;
189 if ($line1 ne $newl1 or $line2 ne $newl2 or $line3 ne $newl3) {
190 $pre =~ s/\n*\Z/\n\n/ if $pre =~ /\N/;
191 $body =~ s/\A\n*/\n/;
193 print "$fname would be cleaned up\n" if $opt_v;
195 unslurp
($fname, "$pre$newl1$newl2$body$newl3");
196 print "$fname cleaned up\n" if $opt_v;
201 preprocess
($fname, $opt_n ?
$oldg : $guard)
202 unless $fname =~ $exclude or $fname =~ $exclude_cpp;
206 print STDERR
"warning: guard symbol renaming may break things\n";
207 for my $guard (sort keys %old_guard) {
208 print STDERR
" $old_guard{$guard} -> $guard\n";
210 print STDERR
"To find uses that may have to be updated try:\n";
211 print STDERR
" git grep -Ew '", join("|", sort values %old_guard),