Commit | Line | Data |
---|---|---|
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 |
22 | use strict; | |
23 | ||
24 | sub pr2 { print "$_[0]\n"; } | |
25 | sub mylog { print @_;} | |
26 | ||
27 | ||
28 | # to be launched from the git directory | |
29 | die "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 | ||
40 | my $target_dir = "/tmp/extract_c_and_res/$ARGV[0]"; | |
41 | `mkdir -p $target_dir`; | |
42 | my $old_dir = "/tmp/extract_c_and_res/$ARGV[0]_old"; | |
43 | `mkdir -p $old_dir`; | |
44 | my $new_dir = "/tmp/extract_c_and_res/$ARGV[0]_new"; | |
45 | `mkdir -p $new_dir`; | |
46 | ||
47 | my $commit_new = $ARGV[0]; | |
48 | my $commit_old = $ARGV[1] || "$commit_new^"; # default parent | |
49 | ||
50 | my $gitfile = "$target_dir/$commit_new.gitinfo"; | |
51 | my $makefile = "$target_dir/Makefile"; | |
52 | ||
53 | `git show $commit_new > $gitfile `; | |
54 | ||
55 | ||
56 | # processing the patch | |
57 | ||
58 | my @files = (); | |
59 | my $files = {}; | |
60 | my @driverheaders_in_include = (); | |
61 | ||
62 | ||
63 | open FILE, "$gitfile" or die "$!"; | |
64 | while(<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 | ||
88 | my $counter=0; | |
89 | ||
90 | # to be able to later find the corresponding local included header file | |
91 | my $kerneldir_of_file = {}; | |
92 | ||
93 | my @finalcfiles = (); | |
94 | my $finalcfiles = {}; | |
95 | ||
96 | foreach 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 | ||
137 | open MAKE, ">$makefile" or die "$!"; | |
138 | print MAKE "CEDESCRIPTION=\"\"\n"; | |
139 | print MAKE "SP=foo.cocci\n"; | |
140 | print MAKE "SOURCES = "; | |
141 | my $last = shift @finalcfiles; | |
142 | foreach my $f (@finalcfiles) { | |
143 | print MAKE "$f \\\n\t"; | |
144 | } | |
145 | print MAKE "$last\n"; | |
146 | ||
147 | print MAKE " | |
148 | ||
149 | TOP=../.. | |
150 | include \$(TOP)/generic_makefile | |
151 | "; | |
152 | ||
153 | ||
154 | ||
155 | # process potential driver headers of include/ | |
156 | ||
157 | foreach 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 | ||
188 | my @linuxheaders = `cd $target_dir; grep -E \"#include +\<[^>]*\>\" *.c *.h`; | |
189 | foreach 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 | ||
214 | my @headers = `cd $target_dir; grep -E \"#include +\\".*\\"\" *.c *.h`; | |
215 | ||
216 | my $hfiles = {}; | |
217 | foreach 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 | ||
238 | foreach 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 | } |