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