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