6b734524ea679e781317580cffff5ad1f7807a96
[bpt/coccinelle.git] / tools / bridge.ml
1 (*
2 * Copyright 2010, INRIA, University of Copenhagen
3 * Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix
4 * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
5 * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
6 * This file is part of Coccinelle.
7 *
8 * Coccinelle is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, according to version 2 of the License.
11 *
12 * Coccinelle is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Coccinelle. If not, see <http://www.gnu.org/licenses/>.
19 *
20 * The authors reserve the right to distribute this or future versions of
21 * Coccinelle under other licenses.
22 *)
23
24
25 let drop_spaces s =
26 String.concat "" (Str.split (Str.regexp "[ ]+") s)
27
28 let parse_line fp l n =
29 if List.mem l fp
30 then None
31 else
32 if Str.string_match (Str.regexp "#") l 0
33 then None (* comment line *)
34 else
35 let top_split = Str.split (Str.regexp ":") l in
36 match top_split with
37 cocci::first::others ->
38 let rec loop tag = function
39 [x] ->
40 let x =
41 String.concat "\\ " (Str.split (Str.regexp "[ ]+") x) in
42 [(tag,x)]
43 | first::rest ->
44 let splitted = Str.split (Str.regexp "[ ]+") first in
45 (match List.rev splitted with
46 new_tag::info ->
47 let rest = loop new_tag rest in
48 (tag,String.concat "\\ " (List.rev info))::rest
49 | _ -> failwith "bad element")
50 | _ -> failwith "no data" in
51 Some (cocci,loop (drop_spaces first) others)
52 | _ -> failwith (Printf.sprintf "bad line: %s" l)
53
54 let collect_lines fp i =
55 let lines = ref [] in
56 let ln = ref 0 in
57 let rec loop _ =
58 ln := !ln + 1;
59 (match parse_line fp (input_line i) !ln with
60 Some l ->
61 if List.mem l !lines
62 then ()
63 else lines := l::!lines
64 | None -> ());
65 loop() in
66 try loop() with End_of_file -> !lines
67
68 (* --------------------------------------------------------------------- *)
69
70 let process_fp fl =
71 let i = open_in fl in
72 let lines = ref ([] : string list) in
73 let rec loop _ =
74 let l = input_line i in
75 (if not(Str.string_match (Str.regexp "#") l 0)
76 then lines := l :: !lines);
77 loop() in
78 (try loop() with End_of_file -> ());
79 close_in i;
80 !lines
81
82 (* --------------------------------------------------------------------- *)
83 (* same info, different categories *)
84
85 let discard_ambiguous lines =
86 let rec loop = function
87 [] -> []
88 | (cocci,tags)::rest ->
89 let (same,others) =
90 List.partition
91 (function (cocci2,tags2) -> tags = tags2 && not(cocci = cocci2))
92 rest in
93 match same with
94 [] -> (cocci,tags)::loop rest
95 | _ ->
96 Printf.printf "ignoring ambiguity:\n";
97 List.iter
98 (function (cocci,tags) ->
99 Printf.printf "%s: %s\n" cocci
100 (String.concat ", "
101 (List.map
102 (function (tag,tagval) ->
103 Printf.sprintf "%s: %s" tag tagval)
104 tags)))
105 ((cocci,tags)::same);
106 loop others in
107 loop lines
108
109 (* --------------------------------------------------------------------- *)
110 (* only actually collects the rightmost element into ors *)
111
112 let split_or (cocci,line) =
113 let rev = List.rev line in
114 (cocci,List.rev(List.tl rev), List.hd rev)
115
116 let collect_ors fp lines =
117 let rec loop = function
118 [] -> failwith "no lines"
119 | [line] ->
120 let (c,k,v) = split_or line in
121 ((c,k,[v]),[])
122 | line::xs ->
123 let (c,k,v) = split_or line in
124 let ((c1,k1,v1),rest) = loop xs in
125 if c = c1 && k = k1 && not (k = [])
126 then
127 if List.mem v v1
128 then ((c1,k1,v1),rest)
129 else ((c1,k1,v::v1),rest)
130 else ((c,k,[v]),((c1,k1,v1)::rest)) in
131 let ((c,k,v),rest) = loop lines in
132 let res = (c,k,v)::rest in
133 List.fold_left
134 (function prev ->
135 function (c,k,v) ->
136 match v with
137 [] -> failwith "not possible"
138 | [x] -> (c,k@v) :: prev
139 | (tag,_)::_ ->
140 (*let vs =
141 Printf.sprintf "%s:(%s)" tag
142 (String.concat "|"
143 (List.sort compare
144 (List.map (function (_,vl) -> vl) v))) in
145 let attempt =
146 Printf.sprintf "%s: %s %s" c
147 (String.concat " " (List.map (function (k,v) -> k^":"^v) k))
148 vs in*)
149 if true (*List.mem attempt fp*)
150 then
151 let vs =
152 Printf.sprintf "\\\\\\\\\\(%s\\\\\\\\\\)"
153 (String.concat "\\\\\\\\\\|"
154 (List.sort compare
155 (List.map (function (_,vl) -> vl) v))) in
156 (c,k@[(tag,vs)]) :: prev
157 else (List.map (function vi -> (c,k@[vi])) v) @ prev)
158 [] res
159
160 (* --------------------------------------------------------------------- *)
161
162 let command s =
163 let _ = Sys.command s in
164 ()
165
166 let created = ref ([] : (string * (string list ref * out_channel)) list)
167
168 let mktag n = Printf.sprintf "x%d" n
169
170 let created_files = ref ([] : (string * int ref) list)
171
172 let process_line env (cocci,tags) =
173 let files = List.filter (function (c,f) -> c = cocci) env in
174 List.iter
175 (function (_,cocci_file) ->
176 let resdir = Filename.chop_extension cocci_file in
177 (if not(Sys.file_exists cocci_file)
178 then failwith "no cocci file");
179 let (n,o) =
180 try List.assoc resdir !created
181 with Not_found ->
182 begin
183 if Sys.file_exists resdir
184 then
185 command
186 (Printf.sprintf
187 "test %s -nt %s && /bin/rm -r -f %s && mkdir %s"
188 cocci_file resdir resdir resdir)
189 else command (Printf.sprintf "mkdir %s" resdir);
190 let files = Printf.sprintf "%s/files" resdir in
191 let o = open_out files in
192 Printf.fprintf o "all: real_all\n\n";
193 let cell = ((ref []),o) in
194 created := (resdir,cell) :: !created;
195 cell
196 end in
197 let temp_file = Filename.temp_file cocci ".cocci" in
198 command (Printf.sprintf "cp %s %s" cocci_file temp_file);
199 let first_tag_val =
200 match tags with
201 [] -> failwith "no tags"
202 | (_,first_tag_val)::_ ->
203 let cell =
204 try List.assoc first_tag_val !created_files
205 with Not_found ->
206 let c = ref (-1) in
207 created_files := (first_tag_val,c)::!created_files;
208 c in
209 cell := !cell + 1;
210 if !cell = 0
211 then first_tag_val
212 else Printf.sprintf "%s%d" first_tag_val !cell in
213 List.iter
214 (function (tag,tagval) ->
215 command
216 (Printf.sprintf "sed s/%s/%s/ %s > %s_out; cp %s_out %s"
217 tag tagval temp_file temp_file temp_file temp_file))
218 tags;
219 command
220 (Printf.sprintf "mv %s %s/%s.cocci" temp_file resdir first_tag_val);
221 Printf.fprintf o "%s.out:\n\tmono_spatch_linux %s.cocci ${ARGS}\n\n"
222 first_tag_val first_tag_val;
223 n := (first_tag_val^".out") :: !n)
224 files
225
226 (* --------------------------------------------------------------------- *)
227
228 let rec mkenv = function
229 [] -> []
230 | [_] -> failwith "required arguments: file (category x cocci file)*"
231 | category::cocci::rest ->
232 if Filename.check_suffix cocci ".cocci"
233 then (category,cocci)::mkenv rest
234 else failwith "required arguments: file (category x cocci file)*"
235
236 let rec upto = function
237 0 -> []
238 | n -> (mktag (n-1)) :: (upto (n-1))
239
240 let _ =
241 let (no_ors,args) =
242 List.partition (function "-no_ors" -> true | _ -> false)
243 (Array.to_list Sys.argv) in
244 let (file,fp,env) =
245 match List.tl args with
246 file::env ->
247 let rec loop prev = function
248 [] ->
249 if prev = ""
250 then ([],[])
251 else ([prev],[])
252 | x::xs ->
253 try
254 let _ = Str.search_forward (Str.regexp ".cocci") x 0 in
255 if prev = ""
256 then ([],x::xs)
257 else ([],prev::x::xs)
258 with Not_found ->
259 let (fp,env) = loop x xs in
260 if prev = ""
261 then (fp,env)
262 else (prev::fp,env) in
263 let (fp,env) = loop "" env in
264 (file,fp,mkenv env)
265 | _ -> failwith "one argument expected" in
266 let fp = List.fold_left (@) [] (List.map process_fp fp) in
267 let i = open_in file in
268 let lines = collect_lines fp i in
269 let lines = if no_ors = [] then collect_ors fp lines else lines in
270 close_in i;
271 let lines = discard_ambiguous lines in
272 List.iter (process_line env) lines;
273 List.iter
274 (function (resdir,(n,o)) ->
275 Printf.fprintf o "real_all: %s\n"
276 (String.concat " " (List.rev !n));
277 Printf.fprintf o "\tcat %s > completed\n"
278 (String.concat " " (List.rev !n));
279 close_out o)
280 !created