Coccinelle release-1.0.0-rc11
[bpt/coccinelle.git] / scripts / extract_c_and_res.pl
CommitLineData
17ba0788
C
1# Copyright 2012, INRIA
2# Julia Lawall, Gilles Muller
3# Copyright 2010-2011, INRIA, University of Copenhagen
f537ebc4
C
4# Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix
5# Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
6# Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
7# This file is part of Coccinelle.
8#
9# Coccinelle is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, according to version 2 of the License.
12#
13# Coccinelle is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
20#
21# The authors reserve the right to distribute this or future versions of
22# Coccinelle under other licenses.
23
24
34e49164
C
25#!/usr/bin/perl -w
26use strict;
27
28sub pr2 { print "$_[0]\n"; }
29sub mylog { print @_;}
30
31
32# to be launched from the git directory
33die "usage: $0 commithashafter [commithashbefore]"
34 if(@ARGV <= 0 || @ARGV >= 3);
35
36# update: now I also extract the headers files, the one
37# that were modified in the commit and the one that are
38# locally used and that may contain useful type information
39# for spatch.
40
41# update: now I also extract some include/linux/header.h files, the
42# one having the same name of one of the driver.
43
44my $target_dir = "/tmp/extract_c_and_res/$ARGV[0]";
45`mkdir -p $target_dir`;
46my $old_dir = "/tmp/extract_c_and_res/$ARGV[0]_old";
47`mkdir -p $old_dir`;
48my $new_dir = "/tmp/extract_c_and_res/$ARGV[0]_new";
49`mkdir -p $new_dir`;
50
51my $commit_new = $ARGV[0];
52my $commit_old = $ARGV[1] || "$commit_new^"; # default parent
53
54my $gitfile = "$target_dir/$commit_new.gitinfo";
55my $makefile = "$target_dir/Makefile";
56
57`git show $commit_new > $gitfile `;
58
59
60# processing the patch
61
62my @files = ();
63my $files = {};
64my @driverheaders_in_include = ();
65
66
67open FILE, "$gitfile" or die "$!";
68while(<FILE>) {
69
70 # allow other dir ? # fs|mm there is drivers under arch/ too
71 if(/^diff --git a\/((drivers|sound)\/.*?\.[ch]) b/){
72 mylog " $1\n";
73
74 push @files, $1;
75 $files->{$1} = 1;
76
77 }
78 elsif(/^diff --git a\/(include\/.*?\.h) b/) {
79 mylog "potential header driver $1\n";
80 push @driverheaders_in_include, $1;
81 }
82 elsif(/^diff --git a\//) {
83 mylog " not driver:$_";
84 }
85 elsif(/^diff/) {
86 die "PB: strange diff line: $_";
87 }
88}
89
90# extracting the .c and .h of the patch
91
92my $counter=0;
93
94# to be able to later find the corresponding local included header file
95my $kerneldir_of_file = {};
96
97my @finalcfiles = ();
98my $finalcfiles = {};
99
100foreach my $f (@files) {
101 my ($base) = `basename $f`;
102 chomp $base;
103 my $res = $base;
104 if($base =~ /\.c$/) {
105 $res =~ s/\.c$/.res/;
106 }
107 if($base =~ /\.h$/) {
108 $res =~ s/\.h$/.h.res/;
109 }
110
111 pr2 "processing: $f $base $res";
112 if(-e "$target_dir/$base") {
113 $counter++;
114 $base = "${counter}_$base";
115 $res = "${counter}_$res";
116 pr2 "try transform one file because already exist: $base";
117 if($base =~ /\.h$/) {
118 die "PB: Two header files share the same name: $base.";
119 }
120
121 }
122 die "PB: one of the file already exist: $base" if (-e "$target_dir/$base");
123
190f1acf
C
124 `git cat-file blob $commit_old:$f > $target_dir/$base`;
125 `git cat-file blob $commit_new:$f > $target_dir/$res`;
34e49164 126
190f1acf
C
127 `git cat-file blob $commit_old:$f > $old_dir/$base`;
128 `git cat-file blob $commit_new:$f > $new_dir/$base`;
34e49164
C
129
130 $kerneldir_of_file->{$base} = `dirname $f`;
131 chomp $kerneldir_of_file->{$base};
132
133 push @finalcfiles, $base;
134 $finalcfiles->{$base} = 1;
135
136
137}
138
139# generate Makefile
140
141open MAKE, ">$makefile" or die "$!";
142print MAKE "CEDESCRIPTION=\"\"\n";
143print MAKE "SP=foo.cocci\n";
144print MAKE "SOURCES = ";
145my $last = shift @finalcfiles;
146foreach my $f (@finalcfiles) {
147 print MAKE "$f \\\n\t";
148}
149print MAKE "$last\n";
150
151print MAKE "
152
153TOP=../..
154include \$(TOP)/generic_makefile
155";
156
157
158
159# process potential driver headers of include/
160
161foreach my $f (@driverheaders_in_include) {
162 my $base = `basename $f`;
163 chomp $base;
164 if($base =~ /.h$/) {
165 $base =~ s/.h$/.c/;
166 } else { die "PB: internal error"; }
167
168
169# julia want all .h that were in the patch, not just the headers
170# of our heuristic. Hence the comment.
171
172# pr2 "$f $base";
173# if(defined($finalcfiles->{$base})) {
174 {
175# pr2 "found header of driver in include/: $f of $base";
176 my $dir = `dirname $f`;
177 chomp $dir;
178 `mkdir -p $target_dir/$dir`;
190f1acf
C
179 `git cat-file blob $commit_old:$f > $target_dir/$f`;
180 `git cat-file blob $commit_new:$f > $target_dir/$f.res`;
34e49164
C
181
182 `mkdir -p $old_dir/$dir`;
183 `mkdir -p $new_dir/$dir`;
190f1acf
C
184 `git cat-file blob $commit_old:$f > $old_dir/$f`;
185 `git cat-file blob $commit_new:$f > $new_dir/$f`;
34e49164
C
186
187 }
188}
189
190# compute other linux headers not in the patch
191
192my @linuxheaders = `cd $target_dir; grep -E \"#include +\<[^>]*\>\" *.c *.h`;
193foreach my $line (@linuxheaders) {
194 chomp $line;
195 #pr2 ($line);
196 if($line =~ /^(.*)?:#include *\<([^>]*)\>/) {
197 my ($_file, $f) = ($1, $2);
198
199 my $base = `basename $f`;
200 chomp $base;
201 if($base =~ /.h$/) {
202 $base =~ s/.h$/.c/;
203 } else { die "PB: internal error"; }
204
205 if(defined($finalcfiles->{$base}) && ! -e "$target_dir/include/$f") {
206 pr2 "found header of driver in include/: $f of $base";
207 my $dir = `dirname $f`;
208 chomp $dir;
209 `mkdir -p $target_dir/include/$dir`;
190f1acf 210 `git cat-file blob $commit_old:include/$f > $target_dir/include/$f`;
34e49164
C
211 }
212 } else { pr2 "pb regexp: $line"; }
213}
214
215
216# compute other local headers not in the patch
217
218my @headers = `cd $target_dir; grep -E \"#include +\\".*\\"\" *.c *.h`;
219
220my $hfiles = {};
221foreach my $line (@headers) {
222 chomp $line;
223 #pr2 ($line);
224 if($line =~ /^(.*)?:#include *"(.*)"/) {
225
226 my ($file, $header) = ($1, $2);
227 my $dir = $kerneldir_of_file->{$file};
228
229 my $fullheader = "$dir/$header";
230 #pr2 ($fullheader);
231
232 if($files->{$fullheader}) {
233 pr2 "INFO: $fullheader was already in commit";
234 } else {
235 $hfiles->{$fullheader} = 1;
236 }
237
238 } else { pr2 "pb regexp: $line"; }
239
240}
241
242foreach my $h (keys %{$hfiles}) {
243 my ($base) = `basename $h`;
244 chomp $base;
245 pr2 "processing additionnal header file: $h $base";
246
247 if(-e "$target_dir/$base") {
248 pr2 "-------------------------------------";
249 pr2 "PB: local header (not modified in the git) $base already exists";
250 pr2 "BUT I CONTINUE, but may have more .failed in the end";
251 pr2 "-------------------------------------";
252 } else {
190f1acf 253 `git cat-file blob $commit_old:$h > $target_dir/$base`;
34e49164
C
254 }
255}