2 ######################################################################
4 # This script find duplicates of #include files, ignoring #ifdef's, etc.
5 # from C source files, and (at your command) removes the duplicates.
7 # It is meant to be run ONLY by FreeRADUS developers, and has nothing
8 # whatsoever to do with RADIUS, FreeRADIUS, or confguring a RADIUS server.
10 ######################################################################
12 # Run as: ./min-includes.pl `find . -name "*.c" -print`
13 # prints out duplicate includes from files.
15 # ./min-includes.pl +n `find . -name "*.c" -print`
16 # removes the duplicate includes from each file.
17 # Remember to check that it still builds!
19 # It has to be run from the TOP of the FreeRADIUS build tree,
20 # i.e. where the top-level "configure" script is located.
22 ######################################################################
24 # FIXME: We don't handle include files taken from the current
27 # FIXME: we should take -I <path> from the command line.
29 ######################################################################
31 # Copyright (C) 2006 Alan DeKok <aland@freeradius.org>
35 ######################################################################
43 # Find the #include's for one file.
48 return if ($processed{$file});
52 open FILE, "<$file" or die "Failed to open $file: $!\n";
58 next if (!/^\s*\#\s*include\s+/);
60 if (/^\s*\#\s*include\s+"(.+?)"/) {
61 $refs{$file}{$1} = $line;
63 # FIXME: local header files?
64 # src/foo/bar.c: #include "foo.h"
65 # src/foo/foo.h do stuff..
68 } elsif (/^\s*\#\s*include\s+<(.+?)>/) {
69 $refs{$file}{$1} = $line;
78 # Where include files are located.
82 @directories = ("src/lib", "src");
88 if ($ARGV[0] eq "+n") {
94 # Bootstrap the basic C files.
96 foreach $file (@ARGV) {
102 # Process the include files referenced from the C files, to find out
103 # what they include Note that we create a temporary array, rather
104 # than walking over %include, because the process() function adds
105 # entries to the %include hash.
107 @work = sort keys %include;
108 foreach $inc (@work) {
110 foreach $dir (@directories) {
111 $path = $dir . "/" . $inc;
114 $path =~ s:/.*?/\.\.::;
115 $path =~ s:/.*?/\.\.::;
117 next if (! -e $path);
119 $forward{$inc} = $path;
120 $reverse{$path} = $inc;
122 # ignore system include files
123 next if ((scalar keys %{$refs{$path}}) == 0);
125 # Remember that X includes Y, and push Y onto the list
127 foreach $inc2 (sort keys %{$refs{$path}}) {
128 $maps{$inc}{$inc2} = 0;
135 # Process all of the forward refs, so that we have a complete
136 # list of who's referencing who.
138 # This doesn't find the shortest path from A to B, but it does
141 foreach $inc (sort keys %maps) {
142 foreach $inc2 (sort keys %{$maps{$inc}}) {
143 foreach $inc3 (sort keys %{$maps{$inc2}}) {
144 # map is already there...
145 next if (defined $maps{$inc}{$inc3});
147 $maps{$inc}{$inc3} = $maps{$inc2}{$inc3} + 1;
153 # Walk through the files again, looking for includes that are
154 # unnecessary. Note that we process header files, too.
156 foreach $file (sort keys %refs) {
158 # print out some debugging information.
160 if (defined $reverse{$file}) {
161 print $file, "\t(", $reverse{$file}, ")\n";
167 # walk of the list of include's in this file
168 foreach $ref (sort keys %{$refs{$file}}) {
170 # walk over the include files we include, or included by
171 # files that we include.
172 foreach $inc2 (sort keys %{$maps{$ref}}) {
174 # If we include X, and X includes Y, and we include
175 # Y ourselves *after* X, it's a definite dupe.
177 # Note that this is a *guaranteed* duplicate.
179 # Sometimes order matters, so we can't always delete X if
180 # we include Y after X, and Y includes X
182 if (defined $refs{$file}{$inc2} &&
183 ($refs{$file}{$inc2} > $refs{$file}{$ref})) {
184 $duplicate{$file}{$inc2} = $ref;
186 # mark the line to be deleted.
187 $delete_line{$file}{$refs{$file}{$inc2}}++;
192 print "\t", $ref, "\n" if ($debug > 0);
197 print "------------------------------------\n";
201 # Maybe just print out the dups so that a person can validate them.
204 foreach $file (sort keys %duplicate) {
207 foreach $inc (sort keys %{$duplicate{$file}}) {
208 print "\t[", $refs{$file}{$inc}, "] ", $inc, " (", $duplicate{$file}{$inc}, " at ", $refs{$file}{$duplicate{$file}{$inc}}, ")\n";
212 foreach $file (sort keys %duplicate) {
213 open FILE, "<$file" or die "Failed to open $file: $!\n";
214 open OUTPUT, ">$file.tmp" or die "Failed to create $file.tmp: $!\n";
220 # supposed to delete this line, don't print it to the output.
221 next if (defined $delete_line{$file}{$line});
226 rename "$file.tmp", $file;
231 # If we succeeded in re-writing the files, it's OK.
234 # If there are no duplicates, then we're OK.
235 exit 0 if (!$any_dups);
237 # Else there are duplicates, complain.