Commit | Line | Data |
---|---|---|
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 |
26 | use strict; | |
27 | ||
28 | sub pr2 { print "$_[0]\n"; } | |
29 | sub mylog { print @_;} | |
30 | ||
31 | ||
32 | # to be launched from the git directory | |
33 | die "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 | ||
44 | my $target_dir = "/tmp/extract_c_and_res/$ARGV[0]"; | |
45 | `mkdir -p $target_dir`; | |
46 | my $old_dir = "/tmp/extract_c_and_res/$ARGV[0]_old"; | |
47 | `mkdir -p $old_dir`; | |
48 | my $new_dir = "/tmp/extract_c_and_res/$ARGV[0]_new"; | |
49 | `mkdir -p $new_dir`; | |
50 | ||
51 | my $commit_new = $ARGV[0]; | |
52 | my $commit_old = $ARGV[1] || "$commit_new^"; # default parent | |
53 | ||
54 | my $gitfile = "$target_dir/$commit_new.gitinfo"; | |
55 | my $makefile = "$target_dir/Makefile"; | |
56 | ||
57 | `git show $commit_new > $gitfile `; | |
58 | ||
59 | ||
60 | # processing the patch | |
61 | ||
62 | my @files = (); | |
63 | my $files = {}; | |
64 | my @driverheaders_in_include = (); | |
65 | ||
66 | ||
67 | open FILE, "$gitfile" or die "$!"; | |
68 | while(<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 | ||
92 | my $counter=0; | |
93 | ||
94 | # to be able to later find the corresponding local included header file | |
95 | my $kerneldir_of_file = {}; | |
96 | ||
97 | my @finalcfiles = (); | |
98 | my $finalcfiles = {}; | |
99 | ||
100 | foreach 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 | ||
141 | open MAKE, ">$makefile" or die "$!"; | |
142 | print MAKE "CEDESCRIPTION=\"\"\n"; | |
143 | print MAKE "SP=foo.cocci\n"; | |
144 | print MAKE "SOURCES = "; | |
145 | my $last = shift @finalcfiles; | |
146 | foreach my $f (@finalcfiles) { | |
147 | print MAKE "$f \\\n\t"; | |
148 | } | |
149 | print MAKE "$last\n"; | |
150 | ||
151 | print MAKE " | |
152 | ||
153 | TOP=../.. | |
154 | include \$(TOP)/generic_makefile | |
155 | "; | |
156 | ||
157 | ||
158 | ||
159 | # process potential driver headers of include/ | |
160 | ||
161 | foreach 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 | ||
192 | my @linuxheaders = `cd $target_dir; grep -E \"#include +\<[^>]*\>\" *.c *.h`; | |
193 | foreach 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 | ||
218 | my @headers = `cd $target_dir; grep -E \"#include +\\".*\\"\" *.c *.h`; | |
219 | ||
220 | my $hfiles = {}; | |
221 | foreach 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 | ||
242 | foreach 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 | } |