added some results
[tridge/junkcode.git] / minimal_includes.pl
1 #!/usr/bin/perl -w
2 # find a list of #include lines in C code that might not be needed
3 # usually called with something like this:
4 #    minimal_includes.pl `find . -name "*.c"`
5 # Andrew Tridgell <tridge@samba.org>
6
7 use strict;
8 use Data::Dumper;
9 use Getopt::Long;
10
11 my $opt_help = 0;
12 my $opt_remove = 0;
13
14 #####################################################################
15 # write a string into a file
16 sub FileSave($$)
17 {
18     my($filename) = shift;
19     my($v) = shift;
20     local(*FILE);
21     open(FILE, ">$filename") || die "can't open $filename";    
22     print FILE $v;
23     close(FILE);
24 }
25
26 sub load_lines($)
27 {
28         my $fname = shift;
29         my @lines = split(/^/m, `cat $fname`);
30         return @lines;
31 }
32
33 sub save_lines($$)
34 {
35         my $fname = shift;
36         my $lines = shift;
37         my $data = join('', @{$lines});
38         FileSave($fname, $data);
39 }
40
41 sub obj_name($)
42 {
43     my $fname = shift;
44     $fname =~ s/(.*)\.c$/$1.o/;
45     return $fname;
46 }
47
48 sub test_compile($)
49 {
50         my $fname = shift;
51         my $obj = obj_name($fname);
52         if ($obj eq $fname) {
53                 return "NOT A C FILE";
54         }
55         unlink($obj);
56         my $ret = `make $obj 2>&1 && md5sum $obj`;
57         if (!stat("$obj")) {
58                 return "COMPILE FAILED";
59         }
60         return $ret;
61 }
62
63 sub test_include($$$$)
64 {
65         my $fname = shift;
66         my $lines = shift;
67         my $i = shift;
68         my $original = shift;
69         my $line = $lines->[$i];
70
71         $lines->[$i] = "";
72         save_lines($fname, $lines);
73
74         my $out = test_compile($fname);
75         
76         if ($out eq $original) {
77                 if ($opt_remove) {
78                         print "$fname: removing $line";
79                         return;
80                 }
81                 print "$fname: might be able to remove $line";
82         } else {
83 #               print "OUT:  $out\n";
84 #               print "ORIG: $original\n";
85         }
86
87         $lines->[$i] = $line;
88         save_lines($fname, $lines);
89 }
90
91 sub process_file($)
92 {
93         my $fname = shift;
94         my @lines = load_lines($fname);
95         my $num_lines = $#lines;
96
97         if (!stat(obj_name($fname))) {
98             return;
99         }
100         
101         my $original = test_compile($fname);
102
103         if ($original eq "COMPILE FAILED") {
104 #               print "Failed to compile $fname\n";
105                 return;
106         }
107
108         print "Processing $fname (with $num_lines lines)\n";
109         
110         my $if_level = 0;
111
112         for (my $i=0;$i<=$num_lines;$i++) {
113                 my $line = $lines[$i];
114                 if ($line =~ /^\#\s*if/) {
115                         $if_level++;
116                 }
117                 if ($line =~ /^\#\s*endif/) {
118                         $if_level--;
119                 }
120                 if ($if_level == 0 &&
121                     $line =~ /^\#\s*include/ && 
122                     !($line =~ /needed/)) {
123                         test_include($fname, \@lines, $i, $original);
124                 }
125         }
126 }
127
128
129 #########################################
130 # display help text
131 sub ShowHelp()
132 {
133     print "
134            minimise includes
135            Copyright (C) tridge\@samba.org
136
137            Usage: minimal_includes.pl [options] <C files....>
138            
139            Options:
140                  --help       show help
141                  --remove     remove includes, don't just list them
142 ";
143 }
144
145
146 # main program
147 GetOptions (
148             'h|help|?' => \$opt_help,
149             'remove' => \$opt_remove,
150             );
151
152 if ($opt_help) {
153         ShowHelp();
154         exit(0);
155 }
156
157 for (my $i=0;$i<=$#ARGV;$i++) {
158         my $fname = $ARGV[$i];
159         process_file($fname);
160 }