Merge branch 'master' of ssh://jra@git.samba.org/data/git/samba
[amitay/samba.git] / source4 / script / 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 my $opt_skip_system = 0;
14
15 #####################################################################
16 # write a string into a file
17 sub FileSave($$)
18 {
19     my($filename) = shift;
20     my($v) = shift;
21     local(*FILE);
22     open(FILE, ">$filename") || die "can't open $filename";    
23     print FILE $v;
24     close(FILE);
25 }
26
27 sub load_lines($)
28 {
29         my $fname = shift;
30         my @lines = split(/^/m, `cat $fname`);
31         return @lines;
32 }
33
34 sub save_lines($$)
35 {
36         my $fname = shift;
37         my $lines = shift;
38         my $data = join('', @{$lines});
39         FileSave($fname, $data);
40 }
41
42 sub test_compile($)
43 {
44         my $fname = shift;
45         my $obj;
46         if ($fname =~ s/(.*)\..*$/$1.o/) {
47                 $obj = "$1.o";
48         } else {
49                 return "NOT A C FILE";
50         }
51         unlink($obj);
52         my $ret = `make $obj 2>&1`;
53         if (!unlink("$obj")) {
54                 return "COMPILE FAILED";
55         }
56         return $ret;
57 }
58
59 sub test_include($$$$)
60 {
61         my $fname = shift;
62         my $lines = shift;
63         my $i = shift;
64         my $original = shift;
65         my $line = $lines->[$i];
66         my $testfname;
67
68         $lines->[$i] = "";
69
70         `/bin/mv -f $fname $fname.misaved` && die "failed to rename $fname";
71         save_lines($fname, $lines);
72         
73         my $out = test_compile($fname);
74
75         if ($out eq $original) {
76                 if ($opt_remove) {
77                         if ($opt_skip_system && 
78                             $line =~ /system\//) {
79                                 print "$fname: not removing system include $line\n";
80                         } else {
81                                 print "$fname: removing $line\n";
82                                 return;
83                         }
84                 } else {
85                         print "$fname: might be able to remove $line\n";
86                 }
87         }
88
89         $lines->[$i] = $line;
90         `/bin/mv -f $fname.misaved $fname` && die "failed to restore $fname";
91 }
92
93 sub process_file($)
94 {
95         my $fname = shift;
96         my @lines = load_lines($fname);
97         my $num_lines = $#lines;
98
99         my $original = test_compile($fname);
100
101         if ($original eq "COMPILE FAILED") {
102                 print "Failed to compile $fname\n";
103                 return;
104         }
105
106         print "Processing $fname (with $num_lines lines)\n";
107         
108         my $if_level = 0;
109
110         for (my $i=0;$i<=$num_lines;$i++) {
111                 my $line = $lines[$i];
112                 if ($line =~ /^\#\s*if/) {
113                         $if_level++;
114                 }
115                 if ($line =~ /^\#\s*endif/) {
116                         $if_level--;
117                 }
118                 if ($if_level == 0 &&
119                     $line =~ /^\#\s*include/ && 
120                     !($line =~ /needed/)) {
121                         test_include($fname, \@lines, $i, $original);
122                 }
123         }
124 }
125
126
127 #########################################
128 # display help text
129 sub ShowHelp()
130 {
131     print "
132            minimise includes
133            Copyright (C) tridge\@samba.org
134
135            Usage: minimal_includes.pl [options] <C files....>
136            
137            Options:
138                  --help         show help
139                  --remove       remove includes, don't just list them
140                  --skip-system  don't remove system/ includes
141 ";
142 }
143
144
145 # main program
146 GetOptions (
147             'h|help|?' => \$opt_help,
148             'remove' => \$opt_remove,
149             'skip-system' => \$opt_skip_system,
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 }