permit multiline comments and strings in macros
[bpt/coccinelle.git] / cocci.ml
index 6ab9293..3c66516 100644 (file)
--- a/cocci.ml
+++ b/cocci.ml
@@ -1,32 +1,39 @@
 (*
-* Copyright 2005-2008, Ecole des Mines de Nantes, University of Copenhagen
-* Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller
-* This file is part of Coccinelle.
-* 
-* Coccinelle is free software: you can redistribute it and/or modify
-* it under the terms of the GNU General Public License as published by
-* the Free Software Foundation, according to version 2 of the License.
-* 
-* Coccinelle is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-* GNU General Public License for more details.
-* 
-* You should have received a copy of the GNU General Public License
-* along with Coccinelle.  If not, see <http://www.gnu.org/licenses/>.
-* 
-* The authors reserve the right to distribute this or future versions of
-* Coccinelle under other licenses.
-*)
+ * Copyright 2012, INRIA
+ * Julia Lawall, Gilles Muller
+ * Copyright 2010-2011, INRIA, University of Copenhagen
+ * Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix
+ * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
+ * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix
+ * This file is part of Coccinelle.
+ *
+ * Coccinelle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, according to version 2 of the License.
+ *
+ * Coccinelle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Coccinelle.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * The authors reserve the right to distribute this or future versions of
+ * Coccinelle under other licenses.
+ *)
 
 
+# 0 "./cocci.ml"
 open Common
 
 module CCI = Ctlcocci_integration
 module TAC = Type_annoter_c
 
+module Ast_to_flow = Control_flow_c_build
+
 (*****************************************************************************)
-(* This file is a kind of driver. It gathers all the important functions 
+(* This file is a kind of driver. It gathers all the important functions
  * from coccinelle in one place. The different entities in coccinelle are:
  *  - files
  *  - astc
@@ -40,79 +47,114 @@ module TAC = Type_annoter_c
 (* --------------------------------------------------------------------- *)
 (* C related *)
 (* --------------------------------------------------------------------- *)
-let cprogram_of_file file = 
-  let (program2, _stat) = Parse_c.parse_print_error_heuristic file in
-  program2 
-
-let cprogram_of_file_cached file = 
-  let (program2, _stat) = Parse_c.parse_cache file in
+let cprogram_of_file saved_typedefs saved_macros file =
+  let (program2, _stat) =
+    Parse_c.parse_c_and_cpp_keep_typedefs
+      (if !Flag_cocci.use_saved_typedefs then (Some saved_typedefs) else None)
+      (Some saved_macros) file in
+  program2
+
+let cprogram_of_file_cached file =
+  let ((program2,typedefs,macros), _stat) = Parse_c.parse_cache file in
   if !Flag_cocci.ifdef_to_if
-  then 
-    program2 +> Parse_c.with_program2 (fun asts -> 
-      Cpp_ast_c.cpp_ifdef_statementize asts
-    )
-  else program2
-
-let cfile_of_program program2_with_ppmethod outf = 
+  then
+    let p2 =
+      program2 +> Parse_c.with_program2 (fun asts ->
+       Cpp_ast_c.cpp_ifdef_statementize asts
+         ) in
+    (p2,typedefs,macros)
+  else (program2,typedefs,macros)
+
+let cfile_of_program program2_with_ppmethod outf =
   Unparse_c.pp_program program2_with_ppmethod outf
 
 (* for memoization, contains only one entry, the one for the SP *)
 let _hparse = Hashtbl.create 101
+let _h_ocaml_init = Hashtbl.create 101
 let _hctl = Hashtbl.create 101
 
 (* --------------------------------------------------------------------- *)
 (* Cocci related *)
 (* --------------------------------------------------------------------- *)
-let sp_of_file2 file iso   =
-  Common.memoized _hparse (file, iso) (fun () ->
-    Parse_cocci.process file iso false)
-let sp_of_file file iso    = 
+(* for a given pair (file,iso), only keep an instance for the most recent
+virtual rules and virtual_env *)
+
+let sp_of_file2 file iso =
+  let redo _ =
+    let new_code =
+      let (_,xs,_,_,_,_,_) as res = Parse_cocci.process file iso false in
+      (* if there is already a compiled ML code, do nothing and use that *)
+      try let _ = Hashtbl.find _h_ocaml_init (file,iso) in res
+      with Not_found ->
+       begin
+         Hashtbl.add _h_ocaml_init (file,iso) ();
+         match Prepare_ocamlcocci.prepare file xs with
+             None -> res
+           | Some ocaml_script_file ->
+             (* compile file *)
+             Prepare_ocamlcocci.load_file ocaml_script_file;
+             (if not !Common.save_tmp_files
+              then Prepare_ocamlcocci.clean_file ocaml_script_file);
+             res
+       end in
+    Hashtbl.add _hparse (file,iso)
+      (!Flag.defined_virtual_rules,!Flag.defined_virtual_env,new_code);
+    new_code in
+  try
+    let (rules,env,code) = Hashtbl.find _hparse (file,iso) in
+    if rules = !Flag.defined_virtual_rules && env = !Flag.defined_virtual_env
+    then code
+    else (Hashtbl.remove _hparse (file,iso); redo())
+  with Not_found -> redo()
+    
+let sp_of_file file iso    =
   Common.profile_code "parse cocci" (fun () -> sp_of_file2 file iso)
 
 
 (* --------------------------------------------------------------------- *)
 (* Flow related *)
 (* --------------------------------------------------------------------- *)
-let print_flow flow = 
+let print_flow flow =
   Ograph_extended.print_ograph_mutable flow "/tmp/test.dot" true
 
 
 let ast_to_flow_with_error_messages2 x =
-  let flowopt = 
+  let flowopt =
     try Ast_to_flow.ast_to_control_flow x
-    with Ast_to_flow.Error x -> 
+    with Ast_to_flow.Error x ->
       Ast_to_flow.report_error x;
       None
   in
-  flowopt +> do_option (fun flow -> 
+  flowopt +> do_option (fun flow ->
     (* This time even if there is a deadcode, we still have a
      * flow graph, so I can try the transformation and hope the
-     * deadcode will not bother us. 
+     * deadcode will not bother us.
      *)
     try Ast_to_flow.deadcode_detection flow
-    with Ast_to_flow.Error (Ast_to_flow.DeadCode x) -> 
+    with Ast_to_flow.Error (Ast_to_flow.DeadCode x) ->
       Ast_to_flow.report_error (Ast_to_flow.DeadCode x);
   );
   flowopt
-let ast_to_flow_with_error_messages a = 
+let ast_to_flow_with_error_messages a =
   Common.profile_code "flow" (fun () -> ast_to_flow_with_error_messages2 a)
 
 
 (* --------------------------------------------------------------------- *)
 (* Ctl related *)
 (* --------------------------------------------------------------------- *)
-let ctls_of_ast2 ast ua pos =
+
+let ctls_of_ast2 ast (ua,fua,fuas) pos =
   List.map2
-    (function ast -> function (ua,pos) ->
+    (function ast -> function (ua,(fua,(fuas,pos))) ->
       List.combine
        (if !Flag_cocci.popl
        then Popl.popl ast
-       else Asttoctl2.asttoctl ast ua pos)
+       else Asttoctl2.asttoctl ast (ua,fua,fuas) pos)
        (Asttomember.asttomember ast ua))
-    ast (List.combine ua pos)
+    ast (List.combine ua (List.combine fua (List.combine fuas pos)))
 
-let ctls_of_ast ast ua =
-  Common.profile_code "asttoctl2" (fun () -> ctls_of_ast2 ast ua)
+let ctls_of_ast ast ua pl =
+  Common.profile_code "asttoctl2" (fun () -> ctls_of_ast2 ast ua pl)
 
 (*****************************************************************************)
 (* Some  debugging functions *)
@@ -127,13 +169,13 @@ let show_or_not_cfile2 cfile =
     Common.pr2_xxxxxxxxxxxxxxxxx ();
     Common.command2 ("cat " ^ cfile);
   end
-let show_or_not_cfile a = 
+let show_or_not_cfile a =
   Common.profile_code "show_xxx" (fun () -> show_or_not_cfile2 a)
 
 let show_or_not_cfiles cfiles = List.iter show_or_not_cfile cfiles
 
 
-let show_or_not_cocci2 coccifile isofile = 
+let show_or_not_cocci2 coccifile isofile =
   if !Flag_cocci.show_cocci then begin
     Common.pr2_xxxxxxxxxxxxxxxxx ();
     pr2 ("processing semantic patch file: " ^ coccifile);
@@ -142,15 +184,84 @@ let show_or_not_cocci2 coccifile isofile =
     Common.command2 ("cat " ^ coccifile);
     pr2 "";
   end
-let show_or_not_cocci a b = 
+let show_or_not_cocci a b =
   Common.profile_code "show_xxx" (fun () -> show_or_not_cocci2 a b)
 
-
+(* ---------------------------------------------------------------------- *)
 (* the output *)
 
-let show_or_not_diff2 cfile outfile show_only_minus = 
+let fix_sgrep_diffs l =
+  let l =
+    List.filter (function s -> (s =~ "^\\+\\+\\+") || not (s =~ "^\\+")) l in
+  let l = List.rev l in
+  (* adjust second number for + code *)
+  let rec loop1 n = function
+      [] -> []
+    | s::ss ->
+       if s =~ "^-" && not(s =~ "^---")
+       then s :: loop1 (n+1) ss
+       else if s =~ "^@@"
+       then
+         (match Str.split (Str.regexp " ") s with
+           bef::min::pl::aft ->
+             let (n1,n2) =
+               match Str.split (Str.regexp ",") pl with
+                 [n1;n2] -> (n1,n2)
+               | [n1] -> (n1,"1")
+               | _ -> failwith "bad + line information" in
+             let n2 = int_of_string n2 in
+             (Printf.sprintf "%s %s %s,%d %s" bef min n1 (n2-n)
+                (String.concat " " aft))
+             :: loop1 0 ss
+         | _ -> failwith "bad @@ information")
+       else s :: loop1 n ss in
+  let rec loop2 n = function
+      [] -> []
+    | s::ss ->
+       if s =~ "^---"
+       then s :: loop2 0 ss
+       else if s =~ "^@@"
+       then
+         (match Str.split (Str.regexp " ") s with
+           bef::min::pl::aft ->
+             let (m2,n1,n2) =
+               match (Str.split (Str.regexp ",") min,
+                      Str.split (Str.regexp ",") pl) with
+                 ([_;m2],[n1;n2]) -> (m2,n1,n2)
+               | ([_],[n1;n2]) -> ("1",n1,n2)
+               | ([_;m2],[n1]) -> (m2,n1,"1")
+               | ([_],[n1]) -> ("1",n1,"1")
+               | _ -> failwith "bad -/+ line information" in
+             let n1 =
+               int_of_string (String.sub n1 1 ((String.length n1)-1)) in
+             let m2 = int_of_string m2 in
+             let n2 = int_of_string n2 in
+             (Printf.sprintf "%s %s +%d,%d %s" bef min (n1-n) n2
+                (String.concat " " aft))
+             :: loop2 (n+(m2-n2)) ss
+         | _ -> failwith "bad @@ information")
+       else s :: loop2 n ss in
+  loop2 0 (List.rev (loop1 0 l))
+
+let normalize_path file =
+  let fullpath =
+    if String.get file 0 = '/' then file else (Sys.getcwd()) ^ "/" ^ file in
+  let elements = Str.split_delim (Str.regexp "/") fullpath in
+  let rec loop prev = function
+      [] -> String.concat "/" (List.rev prev)
+    | "." :: rest -> loop prev rest
+    | ".." :: rest ->
+       (match prev with
+         x::xs -> loop xs rest
+       | _ -> failwith "bad path")
+    | x::rest -> loop (x::prev) rest in
+  loop [] elements
+
+let generated_patches = Hashtbl.create(100)
+
+let show_or_not_diff2 cfile outfile =
   if !Flag_cocci.show_diff then begin
-    match Common.fst(Compare_c.compare_default cfile outfile) with
+    match Common.fst(Compare_c.compare_to_original cfile outfile) with
       Compare_c.Correct -> () (* diff only in spacing, etc *)
     | _ ->
         (* may need --strip-trailing-cr under windows *)
@@ -160,80 +271,121 @@ let show_or_not_diff2 cfile outfile show_only_minus =
          match !Flag_parsing_c.diff_lines with
          | None ->   "diff -u -p " ^ cfile ^ " " ^ outfile
          | Some n -> "diff -U "^n^" -p "^cfile^" "^outfile in
+       let res = Common.cmd_to_list line in
+       let res =
+         List.map
+           (function l ->
+             match Str.split (Str.regexp "[ \t]+") l with
+               "---"::file::date -> "--- "^file
+             | "+++"::file::date -> "+++ "^file
+             | _ -> l)
+           res in
        let xs =
-         let res = Common.cmd_to_list line in
          match (!Flag.patch,res) with
        (* create something that looks like the output of patch *)
            (Some prefix,minus_file::plus_file::rest) ->
+             let prefix =
+               let lp = String.length prefix in
+               if String.get prefix (lp-1) = '/'
+               then String.sub prefix 0 (lp-1)
+               else prefix in
              let drop_prefix file =
-               if prefix = ""
-               then "/"^file
+               let file = normalize_path file in
+               if Str.string_match (Str.regexp prefix) file 0
+               then
+                 let lp = String.length prefix in
+                 let lf = String.length file in
+                 if lp < lf
+                 then String.sub file lp (lf - lp)
+                 else
+                   failwith
+                     (Printf.sprintf "prefix %s doesn't match file %s"
+                        prefix file)
                else
-                 (match Str.split (Str.regexp prefix) file with
-                   [base_file] -> base_file
-                 | _ -> failwith "prefix not found in the old file name") in
+                 failwith
+                   (Printf.sprintf "prefix %s doesn't match file %s"
+                      prefix file) in
              let diff_line =
                match List.rev(Str.split (Str.regexp " ") line) with
                  new_file::old_file::cmdrev ->
+                   let old_base_file = drop_prefix old_file in
                    if !Flag.sgrep_mode2
                    then
                      String.concat " "
-                       (List.rev ("/tmp/nothing" :: old_file :: cmdrev))
+                       (List.rev
+                          (("/tmp/nothing"^old_base_file)
+                           :: old_file :: cmdrev))
                    else
-                     let old_base_file = drop_prefix old_file in
                      String.concat " "
                        (List.rev
-                          (("b"^old_base_file)::("a"^old_base_file)::cmdrev))
+                          (("b"^old_base_file)::("a"^old_base_file)::
+                           cmdrev))
                | _ -> failwith "bad command" in
              let (minus_line,plus_line) =
-               if !Flag.sgrep_mode2
-               then (minus_file,plus_file)
-               else
-                 match (Str.split (Str.regexp "[ \t]") minus_file,
-                        Str.split (Str.regexp "[ \t]") plus_file) with
-                   ("---"::old_file::old_rest,"+++"::new_file::new_rest) ->
-                     let old_base_file = drop_prefix old_file in
+               match (Str.split (Str.regexp "[ \t]") minus_file,
+                      Str.split (Str.regexp "[ \t]") plus_file) with
+                 ("---"::old_file::old_rest,"+++"::new_file::new_rest) ->
+                   let old_base_file = drop_prefix old_file in
+                   if !Flag.sgrep_mode2
+                   then (minus_file,"+++ /tmp/nothing"^old_base_file)
+                   else
                      (String.concat " "
                         ("---"::("a"^old_base_file)::old_rest),
                       String.concat " "
                         ("+++"::("b"^old_base_file)::new_rest))
-                 | (l1,l2) ->
-                     failwith
-                       (Printf.sprintf "bad diff header lines: %s %s"
-                          (String.concat ":" l1) (String.concat ":" l2)) in
+               | (l1,l2) ->
+                   failwith
+                     (Printf.sprintf "bad diff header lines: %s %s"
+                        (String.concat ":" l1) (String.concat ":" l2)) in
              diff_line::minus_line::plus_line::rest
-         |     _ -> res in
-       xs +> List.iter (fun s -> 
-         if s =~ "^\\+" && show_only_minus
-         then ()
-         else pr s)
+         | _ -> res in
+       let xs = if !Flag.sgrep_mode2 then fix_sgrep_diffs xs else xs in
+       let cfile = normalize_path cfile in
+       let patches =
+         try Hashtbl.find generated_patches cfile
+         with Not_found ->
+           let cell = ref [] in
+           Hashtbl.add generated_patches cfile cell;
+           cell in
+       if List.mem xs !patches
+       then ()
+       else
+         begin
+           patches := xs :: !patches;
+           xs +> List.iter pr
+         end
   end
-let show_or_not_diff a b c  = 
-  Common.profile_code "show_xxx" (fun () -> show_or_not_diff2 a b c)
-    
-    
+let show_or_not_diff a b =
+  Common.profile_code "show_xxx" (fun () -> show_or_not_diff2 a b)
+
+
 (* the derived input *)
-    
+
 let show_or_not_ctl_tex2 astcocci ctls =
   if !Flag_cocci.show_ctl_tex then begin
+    let ctls =
+      List.map
+       (List.map
+          (function ((Asttoctl2.NONDECL ctl | Asttoctl2.CODE ctl),x) ->
+            (ctl,x)))
+       ctls in
     Ctltotex.totex ("/tmp/__cocci_ctl.tex") astcocci ctls;
     Common.command2 ("cd /tmp; latex __cocci_ctl.tex; " ^
                     "dvips __cocci_ctl.dvi -o __cocci_ctl.ps;" ^
                     "gv __cocci_ctl.ps &");
   end
-let show_or_not_ctl_tex a b  = 
+let show_or_not_ctl_tex a b  =
   Common.profile_code "show_xxx" (fun () -> show_or_not_ctl_tex2 a b)
-    
-    
-    
+
+
 let show_or_not_rule_name ast rulenb =
   if !Flag_cocci.show_ctl_text or !Flag.show_trying or
-    !Flag_cocci.show_transinfo or !Flag_cocci.show_binding_in_out
+    !Flag.show_transinfo or !Flag_cocci.show_binding_in_out
   then
     begin
       let name =
        match ast with
-         Ast_cocci.CocciRule (nm, (deps, drops, exists), x, _) -> nm
+         Ast_cocci.CocciRule (nm, (deps, drops, exists), x, _, _) -> nm
        | _ -> i_to_s rulenb in
       Common.pr_xxxxxxxxxxxxxxxxx ();
       pr (name ^ " = ");
@@ -242,7 +394,7 @@ let show_or_not_rule_name ast rulenb =
 
 let show_or_not_scr_rule_name rulenb =
   if !Flag_cocci.show_ctl_text or !Flag.show_trying or
-    !Flag_cocci.show_transinfo or !Flag_cocci.show_binding_in_out
+    !Flag.show_transinfo or !Flag_cocci.show_binding_in_out
   then
     begin
       let name = i_to_s rulenb in
@@ -253,19 +405,19 @@ let show_or_not_scr_rule_name rulenb =
 
 let show_or_not_ctl_text2 ctl ast rulenb =
   if !Flag_cocci.show_ctl_text then begin
-    
-    adjust_pp_with_indent (fun () -> 
+
+    adjust_pp_with_indent (fun () ->
       Format.force_newline();
       Pretty_print_cocci.print_plus_flag := true;
       Pretty_print_cocci.print_minus_flag := true;
       Pretty_print_cocci.unparse ast;
       );
-    
+
     pr "CTL = ";
-    let (ctl,_) = ctl in
-    adjust_pp_with_indent (fun () -> 
+    let ((Asttoctl2.CODE ctl | Asttoctl2.NONDECL ctl),_) = ctl in
+    adjust_pp_with_indent (fun () ->
       Format.force_newline();
-      Pretty_print_engine.pp_ctlcocci 
+      Pretty_print_engine.pp_ctlcocci
         !Flag_cocci.show_mcodekind_in_ctl !Flag_cocci.inline_let_ctl ctl;
       );
     pr "";
@@ -276,21 +428,25 @@ let show_or_not_ctl_text a b c =
 
 
 (* running information *)
-let get_celem celem : string = 
-  match celem with 
-      Ast_c.Definition ({Ast_c.f_name = funcs;},_) -> funcs
+let get_celem celem : string =
+  match celem with
+      Ast_c.Definition ({Ast_c.f_name = namefuncs;},_) ->
+        Ast_c.str_of_name namefuncs
     | Ast_c.Declaration
-       (Ast_c.DeclList ([{Ast_c.v_namei = Some ((s, _),_);}, _], _)) -> s
+       (Ast_c.DeclList ([{Ast_c.v_namei = Some (name, _);}, _], _)) ->
+        Ast_c.str_of_name name
     | _ -> ""
 
-let show_or_not_celem2 prelude celem = 
+let show_or_not_celem2 prelude celem =
   let (tag,trying) =
-  (match celem with 
-  | Ast_c.Definition ({Ast_c.f_name = funcs;},_) -> 
+  (match celem with
+  | Ast_c.Definition ({Ast_c.f_name = namefuncs},_) ->
+      let funcs = Ast_c.str_of_name namefuncs in
       Flag.current_element := funcs;
       (" function: ",funcs)
   | Ast_c.Declaration
-      (Ast_c.DeclList ([{Ast_c.v_namei = Some ((s, _),_);}, _], _)) ->
+      (Ast_c.DeclList ([{Ast_c.v_namei = Some (name,_)}, _], _)) ->
+      let s = Ast_c.str_of_name name in
       Flag.current_element := s;
       (" variable ",s);
   | _ ->
@@ -298,30 +454,33 @@ let show_or_not_celem2 prelude celem =
       (" ","something else");
   ) in
   if !Flag.show_trying then pr2 (prelude ^ tag ^ trying)
-  
-let show_or_not_celem a b  = 
+
+let show_or_not_celem a b  =
   Common.profile_code "show_xxx" (fun () -> show_or_not_celem2 a b)
 
 
-let show_or_not_trans_info2 trans_info = 
-  if !Flag_cocci.show_transinfo then begin
+let show_or_not_trans_info2 trans_info =
+  (* drop witness tree indices for printing *)
+  let trans_info =
+    List.map (function (index,trans_info) -> trans_info) trans_info in
+  if !Flag.show_transinfo then begin
     if null trans_info then pr2 "transformation info is empty"
     else begin
       pr2 "transformation info returned:";
       let trans_info =
         List.sort (function (i1,_,_) -> function (i2,_,_) -> compare i1 i2)
-          trans_info 
+          trans_info
       in
-      indent_do (fun () -> 
-        trans_info +> List.iter (fun (i, subst, re) -> 
+      indent_do (fun () ->
+        trans_info +> List.iter (fun (i, subst, re) ->
           pr2 ("transform state: " ^ (Common.i_to_s i));
-          indent_do (fun () -> 
-            adjust_pp_with_indent_and_header "with rule_elem: " (fun () -> 
+          indent_do (fun () ->
+            adjust_pp_with_indent_and_header "with rule_elem: " (fun () ->
               Pretty_print_cocci.print_plus_flag := true;
               Pretty_print_cocci.print_minus_flag := true;
               Pretty_print_cocci.rule_elem "" re;
             );
-            adjust_pp_with_indent_and_header "with binding: " (fun () -> 
+            adjust_pp_with_indent_and_header "with binding: " (fun () ->
               Pretty_print_engine.pp_binding subst;
             );
           )
@@ -329,18 +488,18 @@ let show_or_not_trans_info2 trans_info =
       )
     end
   end
-let show_or_not_trans_info a  = 
+let show_or_not_trans_info a  =
   Common.profile_code "show_xxx" (fun () -> show_or_not_trans_info2 a)
 
 
 
 let show_or_not_binding2 s binding =
   if !Flag_cocci.show_binding_in_out then begin
-    adjust_pp_with_indent_and_header ("binding " ^ s ^ " = ") (fun () -> 
+    adjust_pp_with_indent_and_header ("binding " ^ s ^ " = ") (fun () ->
       Pretty_print_engine.pp_binding binding
     )
   end
-let show_or_not_binding a b  = 
+let show_or_not_binding a b  =
   Common.profile_code "show_xxx" (fun () -> show_or_not_binding2 a b)
 
 
@@ -349,61 +508,61 @@ let show_or_not_binding a b  =
 (* Some  helper functions *)
 (*****************************************************************************)
 
-let worth_trying cfiles tokens = 
+let worth_trying cfiles tokens =
   (* drop the following line for a list of list by rules.  since we don't
      allow multiple minirules, all the tokens within a rule should be in
      a single CFG entity *)
-  let tokens = Common.union_all tokens in
-  if not !Flag_cocci.windows && not (null tokens)
-  then
+  match (!Flag_cocci.windows,tokens) with
+    (true,_) | (_,None) -> true
+  | (_,Some tokens) ->
    (* could also modify the code in get_constants.ml *)
-    let tokens = tokens +> List.map (fun s -> 
-      match () with 
-      | _ when s =~ "^[A-Za-z_][A-Za-z_0-9]*$" -> 
-          "\\b" ^ s ^ "\\b"
+      let tokens = tokens +> List.map (fun s ->
+       match () with
+       | _ when s =~ "^[A-Za-z_][A-Za-z_0-9]*$" ->
+            "\\b" ^ s ^ "\\b"
 
-      | _ when s =~ "^[A-Za-z_]" -> 
-          "\\b" ^ s
+       | _ when s =~ "^[A-Za-z_]" ->
+            "\\b" ^ s
 
-      | _ when s =~ ".*[A-Za-z_]$" -> 
-          s ^ "\\b"
-      | _ -> s
+       | _ when s =~ ".*[A-Za-z_]$" ->
+            s ^ "\\b"
+       | _ -> s
 
-    ) in
-    let com = sprintf "egrep -q '(%s)' %s" (join "|" tokens) (join " " cfiles)
-    in
-    (match Sys.command com with
-    | 0 (* success *) -> true
-    | _ (* failure *) ->
-       (if !Flag.show_misc
-       then Printf.printf "grep failed: %s\n" com);
-       false (* no match, so not worth trying *)
-    )
-  else true
-
-let check_macro_in_sp_and_adjust tokens = 
-  let tokens = Common.union_all tokens in
-  tokens +> List.iter (fun s -> 
-    if Hashtbl.mem !Parsing_hacks._defs s
-    then begin
-      pr2 "warning: macro in semantic patch was in macro definitions";
-      pr2 ("disabling macro expansion for " ^ s);
-      Hashtbl.remove !Parsing_hacks._defs s
-    end
-  )
-
-
-let contain_loop gopt = 
+      ) in
+      let com = sprintf "egrep -q '(%s)' %s" (join "|" tokens) (join " " cfiles)
+      in
+      (match Sys.command com with
+      | 0 (* success *) -> true
+      | _ (* failure *) ->
+         (if !Flag.show_misc
+         then Printf.printf "grep failed: %s\n" com);
+         false (* no match, so not worth trying *))
+
+let check_macro_in_sp_and_adjust = function
+    None -> ()
+  | Some tokens ->
+      tokens +> List.iter (fun s ->
+       if Hashtbl.mem !Parse_c._defs s
+       then begin
+         if !Flag_cocci.verbose_cocci then begin
+            pr2 "warning: macro in semantic patch was in macro definitions";
+            pr2 ("disabling macro expansion for " ^ s);
+         end;
+         Hashtbl.remove !Parse_c._defs s
+       end)
+
+
+let contain_loop gopt =
   match gopt with
-  | Some g -> 
-      g#nodes#tolist +> List.exists (fun (xi, node) -> 
+  | Some g ->
+      g#nodes#tolist +> List.exists (fun (xi, node) ->
         Control_flow_c.extract_is_loop node
       )
   | None -> true (* means nothing, if no g then will not model check *)
 
 
 
-let sp_contain_typed_metavar_z toplevel_list_list = 
+let sp_contain_typed_metavar_z toplevel_list_list =
   let bind x y = x or y in
   let option_default = false in
   let mcode _ _ = option_default in
@@ -413,33 +572,33 @@ let sp_contain_typed_metavar_z toplevel_list_list =
     match Ast_cocci.unwrap e with
     | Ast_cocci.MetaExpr (_,_,_,Some t,_,_) -> true
     | Ast_cocci.MetaExpr (_,_,_,_,Ast_cocci.LocalID,_) -> true
-    | _ -> k e 
+    | _ -> k e
   in
 
-  let combiner = 
+  let combiner =
     Visitor_ast.combiner bind option_default
       mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode mcode
-      mcode
-      donothing donothing donothing donothing
+      donothing donothing donothing donothing donothing
       donothing expression donothing donothing donothing donothing donothing
-      donothing donothing donothing donothing donothing 
+      donothing donothing donothing donothing donothing
   in
-  toplevel_list_list +> 
+  toplevel_list_list +>
     List.exists
     (function (nm,_,rule) ->
       (List.exists combiner.Visitor_ast.combiner_top_level rule))
-    
 
 let sp_contain_typed_metavar rules =
-  sp_contain_typed_metavar_z 
+  sp_contain_typed_metavar_z
     (List.map
        (function x ->
         match x with
-          Ast_cocci.CocciRule (a,b,c,d) -> (a,b,c)
+          Ast_cocci.CocciRule (a,b,c,d,_) -> (a,b,c)
         | _ -> failwith "error in filter")
     (List.filter
        (function x ->
-        match x with Ast_cocci.CocciRule _ -> true | _ -> false)
+        match x with
+          Ast_cocci.CocciRule (a,b,c,d,Ast_cocci.Normal) -> true
+        | _ -> false)
        rules))
 
 
@@ -447,50 +606,106 @@ let sp_contain_typed_metavar rules =
 (* finding among the #include the one that we need to parse
  * because they may contain useful type definition or because
  * we may have to modify them
- * 
+ *
  * For the moment we base in part our heuristic on the name of the file, e.g.
- * serio.c is related we think to #include <linux/serio.h> 
+ * serio.c is related we think to #include <linux/serio.h>
  *)
-
-let (includes_to_parse: (Common.filename * Parse_c.program2) list -> 'a) = fun xs ->
-  if !Flag_cocci.no_includes
-  then []
-  else
-    xs +> List.map (fun (file, cs) -> 
-      let dir = Common.dirname file in
-      
-      cs +> Common.map_filter (fun (c,_info_item) -> 
-       match c with
-       | Ast_c.CppTop (Ast_c.Include {Ast_c.i_include = ((x,ii));
-                         i_rel_pos = info_h_pos;})  -> 
-            (match x with
-            | Ast_c.Local xs -> 
-               let f = Filename.concat dir (Common.join "/" xs) in
+let include_table = Hashtbl.create(100)
+
+let interpret_include_path relpath =
+  let maxdepth = List.length relpath in
+  let unique_file_exists dir f =
+    let cmd =
+      Printf.sprintf "find %s -maxdepth %d -mindepth %d -path \"*/%s\""
+       dir maxdepth maxdepth f in
+    match Common.cmd_to_list cmd with
+      [x] -> Some x
+    | _ -> None in
+  let native_file_exists dir f =
+    let f = Filename.concat dir f in
+    if Sys.file_exists f
+    then Some f
+    else None in
+  let rec search_include_path exists searchlist relpath =
+    match searchlist with
+      []       -> None
+    | hd::tail ->
+       (match exists hd relpath with
+         Some x -> Some x
+       | None -> search_include_path exists tail relpath) in
+  let rec search_path exists searchlist = function
+      [] ->
+       let res = Common.concat "/" relpath in
+       Hashtbl.add include_table (searchlist,relpath) res;
+       Some res
+    | (hd::tail) as relpath1 ->
+       let relpath1 = Common.concat "/" relpath1 in
+       (match search_include_path exists searchlist relpath1 with
+         None -> search_path unique_file_exists searchlist tail
+       | Some f ->
+           Hashtbl.add include_table (searchlist,relpath) f;
+           Some f) in
+  let searchlist =
+    match !Flag_cocci.include_path with
+      [] -> ["include"]
+    | x -> List.rev x in
+  try Some(Hashtbl.find include_table (searchlist,relpath))
+  with Not_found ->
+    search_path native_file_exists searchlist relpath
+
+let (includes_to_parse:
+       (Common.filename * Parse_c.extended_program2) list ->
+        Flag_cocci.include_options -> 'a) = fun xs choose_includes ->
+  match choose_includes with
+    Flag_cocci.I_UNSPECIFIED -> failwith "not possible"
+  | Flag_cocci.I_NO_INCLUDES -> !Flag_cocci.extra_includes
+  | x ->
+      let all_includes =
+       List.mem x
+         [Flag_cocci.I_ALL_INCLUDES; Flag_cocci.I_REALLY_ALL_INCLUDES] in
+      let xs = List.map (function (file,(cs,_,_)) -> (file,cs)) xs in
+      xs +> List.map (fun (file, cs) ->
+       let dir = Common.dirname file in
+
+       cs +> Common.map_filter (fun (c,_info_item) ->
+         match c with
+         | Ast_c.CppTop
+             (Ast_c.Include
+                {Ast_c.i_include = ((x,ii)); i_rel_pos = info_h_pos;})  ->
+           (match x with
+            | Ast_c.Local xs ->
+               let relpath = Common.join "/" xs in
+               let f = Filename.concat dir relpath in
+               if (Sys.file_exists f) then
+                 Some f
+               else
+                 if !Flag_cocci.relax_include_path
              (* for our tests, all the files are flat in the current dir *)
-               if not (Sys.file_exists f) && !Flag_cocci.relax_include_path
+                 then
+                   let attempt2 = Filename.concat dir (Common.last xs) in
+                     if not (Sys.file_exists attempt2) && all_includes
+                     then
+                       interpret_include_path xs
+                     else Some attempt2
+                 else
+                   if all_includes then interpret_include_path xs
+                   else None
+
+            | Ast_c.NonLocal xs ->
+               if all_includes ||
+               Common.fileprefix (Common.last xs) =$= Common.fileprefix file
                then
-                 let attempt2 = Filename.concat dir (Common.last xs) in
-                 if not (Sys.file_exists f) && !Flag_cocci.all_includes
-                 then Some (Filename.concat !Flag_cocci.include_path 
-                               (Common.join "/" xs))
-                 else Some attempt2
-               else Some f
-                   
-            | Ast_c.NonLocal xs -> 
-               if !Flag_cocci.all_includes ||
-               Common.fileprefix (Common.last xs) = Common.fileprefix file
-               then 
-                  Some (Filename.concat !Flag_cocci.include_path 
-                          (Common.join "/" xs))
+                 interpret_include_path xs
                else None
-            | Ast_c.Wierd _ -> None
+            | Ast_c.Weird _ -> None
                  )
-       | _ -> None
-             )
-       )
-      +> List.concat
-      +> Common.uniq
-      
+         | _ -> None))
+       +> List.concat
+       +> (fun x ->
+         (List.rev
+            (Common.uniq
+               (!Flag_cocci.extra_includes@(List.rev x)))))(*uniq keeps last*)
+
 let rec interpret_dependencies local global = function
     Ast_cocci.Dep s      -> List.mem s local
   | Ast_cocci.AntiDep s  ->
@@ -509,7 +724,8 @@ let rec interpret_dependencies local global = function
       (interpret_dependencies local global s1) or
       (interpret_dependencies local global s2)
   | Ast_cocci.NoDep -> true
-       
+  | Ast_cocci.FailDep -> false
+
 let rec print_dependencies str local global dep =
   if !Flag_cocci.show_dependencies
   then
@@ -518,62 +734,61 @@ let rec print_dependencies str local global dep =
       let seen = ref [] in
       let rec loop = function
          Ast_cocci.Dep s | Ast_cocci.AntiDep s ->
-           if not (List.mem s !seen)
-           then
-             begin
-               if List.mem s local
-               then pr2 (s^" satisfied")
-               else pr2 (s^" not satisfied");
-               seen := s :: !seen
-             end 
+             if not (List.mem s !seen)
+             then
+               begin
+                 if List.mem s local
+                 then pr2 (s^" satisfied")
+                 else pr2 (s^" not satisfied");
+                 seen := s :: !seen
+               end
        | Ast_cocci.EverDep s | Ast_cocci.NeverDep s ->
-           if not (List.mem s !seen)
-           then
-             begin
-               if List.mem s global
-               then pr2 (s^" satisfied")
-               else pr2 (s^" not satisfied");
-               seen := s :: !seen
-             end
+             if not (List.mem s !seen)
+             then
+               begin
+                 if List.mem s global
+                 then pr2 (s^" satisfied")
+                 else pr2 (s^" not satisfied");
+                 seen := s :: !seen
+               end
        | Ast_cocci.AndDep(s1,s2) ->
            loop s1;
            loop s2
        | Ast_cocci.OrDep(s1,s2)  ->
            loop s1;
            loop s2
-       | Ast_cocci.NoDep -> () in
+       | Ast_cocci.NoDep -> ()
+       | Ast_cocci.FailDep -> pr2 "False not satisfied" in
       loop dep
     end
-    
-    
-    
+
 (* --------------------------------------------------------------------- *)
 (* #include relative position in the file *)
 (* --------------------------------------------------------------------- *)
-    
+
 (* compute the set of new prefixes
- * on 
+ * on
  *  "a/b/x"; (* in fact it is now a list of string so  ["a";"b";"x"] *)
  *  "a/b/c/x";
  *  "a/x";
  *  "b/x";
- * it would give for the first element 
+ * it would give for the first element
  *   ""; "a"; "a/b"; "a/b/x"
  * for the second
  *   "a/b/c/x"
- * 
+ *
  * update: if the include is inside a ifdef a put nothing. cf -test incl.
  * this is because we dont want code added inside ifdef.
  *)
 
-let compute_new_prefixes xs = 
-  xs +> Common.map_withenv (fun already xs -> 
+let compute_new_prefixes xs =
+  xs +> Common.map_withenv (fun already xs ->
     let subdirs_prefixes = Common.inits xs in
-    let new_first = subdirs_prefixes +> List.filter (fun x -> 
+    let new_first = subdirs_prefixes +> List.filter (fun x ->
       not (List.mem x already)
     )
     in
-    new_first, 
+    new_first,
     new_first @ already
   ) []
   +> fst
@@ -581,105 +796,118 @@ let compute_new_prefixes xs =
 
 (* does via side effect on the ref in the Include in Ast_c *)
 let rec update_include_rel_pos cs =
-  let only_include = cs +> Common.map_filter (fun c -> 
-    match c with 
+  let only_include = cs +> Common.map_filter (fun c ->
+    match c with
     | Ast_c.CppTop (Ast_c.Include {Ast_c.i_include = ((x,_));
                      i_rel_pos = aref;
                      i_is_in_ifdef = inifdef}) ->
         (match x with
-        | Ast_c.Wierd _ -> None
-        | _ -> 
-            if inifdef 
+        | Ast_c.Weird _ -> None
+        | _ ->
+            if inifdef
             then None
             else Some (x, aref)
         )
     | _ -> None
   )
   in
-  let (locals, nonlocals) = 
-    only_include +> Common.partition_either (fun (c, aref)  -> 
+  let (locals, nonlocals) =
+    only_include +> Common.partition_either (fun (c, aref)  ->
       match c with
       | Ast_c.Local x -> Left (x, aref)
       | Ast_c.NonLocal x -> Right (x, aref)
-      | Ast_c.Wierd x -> raise Impossible
+      | Ast_c.Weird x -> raise (Impossible 161)
     ) in
 
   update_rel_pos_bis locals;
   update_rel_pos_bis nonlocals;
   cs
-and update_rel_pos_bis xs = 
+and update_rel_pos_bis xs =
   let xs' = List.map fst xs in
   let the_first = compute_new_prefixes xs' in
   let the_last  = List.rev (compute_new_prefixes (List.rev xs')) in
   let merged = Common.zip xs (Common.zip the_first the_last) in
-  merged +> List.iter (fun ((x, aref), (the_first, the_last)) -> 
-    aref := Some 
-      { 
+  merged +> List.iter (fun ((x, aref), (the_first, the_last)) ->
+    aref := Some
+      {
         Ast_c.first_of = the_first;
         Ast_c.last_of = the_last;
       }
   )
-        
-
-
-
 
 
 (*****************************************************************************)
 (* All the information needed around the C elements and Cocci rules *)
 (*****************************************************************************)
 
-type toplevel_c_info = { 
+type toplevel_c_info = {
   ast_c: Ast_c.toplevel; (* contain refs so can be modified *)
   tokens_c: Parser_c.token list;
   fullstring: string;
 
   flow: Control_flow_c.cflow option; (* it's the "fixed" flow *)
   contain_loop: bool;
-  
+
   env_typing_before: TAC.environment;
   env_typing_after:  TAC.environment;
 
   was_modified: bool ref;
 
+  all_typedefs: (string, Lexer_parser.identkind) Common.scoped_h_env;
+  all_macros: (string, Cpp_token_c.define_def) Hashtbl.t;
+
   (* id: int *)
 }
 
+type rule_info = {
+  rulename: string;
+  dependencies: Ast_cocci.dependency;
+  used_after: Ast_cocci.meta_name list;
+  ruleid: int;
+  was_matched: bool ref;
+} 
+
 type toplevel_cocci_info_script_rule = {
-  scr_ast_rule: string * (string * (string * string)) list * string;
+  scr_ast_rule:
+      string *
+      (Ast_cocci.script_meta_name * Ast_cocci.meta_name *
+        Ast_cocci.metavar) list *
+      Ast_cocci.meta_name list (*fresh vars*) *
+      string;
   language: string;
-  scr_dependencies: Ast_cocci.dependency;
-  scr_ruleid: int;
   script_code: string;
+  scr_rule_info: rule_info;
 }
 
 type toplevel_cocci_info_cocci_rule = {
-  ctl: Lib_engine.ctlcocci * (CCI.pred list list);
+  ctl: Asttoctl2.top_formula * (CCI.pred list list);
+  metavars: Ast_cocci.metavar list;
   ast_rule: Ast_cocci.rule;
   isexp: bool; (* true if + code is an exp, only for Flag.make_hrule *)
 
-  rulename: string;
-  dependencies: Ast_cocci.dependency;
   (* There are also some hardcoded rule names in parse_cocci.ml:
-   *  let reserved_names = ["all";"optional_storage";"optional_qualifier"] 
+   *  let reserved_names = ["all";"optional_storage";"optional_qualifier"]
    *)
   dropped_isos: string list;
   free_vars:  Ast_cocci.meta_name list;
   negated_pos_vars:  Ast_cocci.meta_name list;
-  used_after: Ast_cocci.meta_name list;
   positions: Ast_cocci.meta_name list;
 
-  ruleid: int;
+  ruletype: Ast_cocci.ruletype;
 
-  was_matched: bool ref;
+  rule_info: rule_info;
 }
 
-type toplevel_cocci_info = 
+type toplevel_cocci_info =
     ScriptRuleCocciInfo of toplevel_cocci_info_script_rule
+  | InitialScriptRuleCocciInfo of toplevel_cocci_info_script_rule
+  | FinalScriptRuleCocciInfo of toplevel_cocci_info_script_rule
   | CocciRuleCocciInfo of toplevel_cocci_info_cocci_rule
 
-type kind_file = Header | Source 
-type file_info = { 
+type cocci_info = toplevel_cocci_info list * string list option (* tokens *)
+
+type kind_file = Header | Source
+type file_info = {
   fname : string;
   full_fname : string;
   was_modified_once: bool ref;
@@ -688,25 +916,25 @@ type file_info = {
   fkind : kind_file;
 }
 
-let g_contain_typedmetavar = ref false 
+let g_contain_typedmetavar = ref false
 
 
 let last_env_toplevel_c_info xs =
   (Common.last xs).env_typing_after
 
-let concat_headers_and_c (ccs: file_info list) 
-    : (toplevel_c_info * string) list = 
-  (List.concat (ccs +> List.map (fun x -> 
+let concat_headers_and_c (ccs: file_info list)
+    : (toplevel_c_info * string) list =
+  (List.concat (ccs +> List.map (fun x ->
                                   x.asts +> List.map (fun x' ->
                                                         (x', x.fname)))))
 
-let for_unparser xs = 
-  xs +> List.map (fun x -> 
+let for_unparser xs =
+  xs +> List.map (fun x ->
     (x.ast_c, (x.fullstring, x.tokens_c)), Unparse_c.PPviastr
   )
 
 let gen_pdf_graph () =
-  (Ctl_engine.get_graph_files ()) +> List.iter (fun outfile -> 
+  (Ctl_engine.get_graph_files ()) +> List.iter (fun outfile ->
   Printf.printf "Generation of %s%!" outfile;
   let filename_stack = Ctl_engine.get_graph_comp_files outfile in
   List.iter (fun filename ->
@@ -724,69 +952,119 @@ let gen_pdf_graph () =
            ) filename_stack;
   Printf.printf " - Done\n")
 
+let local_python_code =
+    "from coccinelle import *\n"
+
+let python_code =
+  "import coccinelle\n"^
+    "import coccilib\n"^
+    "import coccilib.org\n"^
+    "import coccilib.report\n" ^
+    local_python_code ^
+    "cocci = Cocci()\n"
+
+let make_init lang code rule_info =
+  let mv = [] in
+  {
+  scr_ast_rule = (lang, mv, [], code);
+  language = lang;
+  script_code = (if lang = "python" then python_code else "") ^code;
+  scr_rule_info = rule_info;
+}
 
 (* --------------------------------------------------------------------- *)
 let prepare_cocci ctls free_var_lists negated_pos_lists
-    used_after_lists positions_list astcocci = 
+    (ua,fua,fuas) positions_list metavars astcocci =
 
   let gathered = Common.index_list_1
-      (zip (zip (zip (zip (zip ctls astcocci) free_var_lists)
-                  negated_pos_lists) used_after_lists) positions_list)
+      (zip (zip (zip (zip (zip (zip (zip (zip ctls metavars) astcocci)
+                                 free_var_lists)
+                  negated_pos_lists) ua) fua) fuas) positions_list)
   in
-  gathered +> List.map 
-    (fun ((((((ctl_toplevel_list,ast),free_var_list),negated_pos_list),
-          used_after_list),
-          positions_list),rulenb) -> 
-      
+  gathered +> List.map
+    (fun (((((((((ctl_toplevel_list,metavars),ast),free_var_list),
+            negated_pos_list),ua),fua),fuas),positions_list),rulenb) ->
+
+      let build_rule_info rulename deps =
+       {rulename = rulename;
+         dependencies = deps;
+         used_after = (List.hd ua) @ (List.hd fua);
+         ruleid = rulenb;
+         was_matched = ref false;} in
+
       let is_script_rule r =
-        match r with Ast_cocci.ScriptRule _ -> true | _ -> false in
+        match r with
+         Ast_cocci.ScriptRule _
+       | Ast_cocci.InitialScriptRule _ | Ast_cocci.FinalScriptRule _ -> true
+       | _ -> false in
 
-      if not (List.length ctl_toplevel_list = 1) && not (is_script_rule ast)
+      if not (List.length ctl_toplevel_list =|= 1) && not (is_script_rule ast)
       then failwith "not handling multiple minirules";
 
       match ast with
-        Ast_cocci.ScriptRule (lang,deps,mv,code) ->
-          let r = 
-          {
-            scr_ast_rule = (lang, mv, code);
-            language = lang;
-            scr_dependencies = deps;
-            scr_ruleid = rulenb;
-            script_code = code;
-          }
+        Ast_cocci.ScriptRule (name,lang,deps,mv,script_vars,code) ->
+          let r =
+            {
+             scr_ast_rule = (lang, mv, script_vars, code);
+              language = lang;
+              script_code = code;
+              scr_rule_info = build_rule_info name deps;
+           }
           in ScriptRuleCocciInfo r
+      | Ast_cocci.InitialScriptRule (name,lang,deps,code) ->
+         let r = make_init lang code (build_rule_info name deps) in
+           InitialScriptRuleCocciInfo r
+      | Ast_cocci.FinalScriptRule (name,lang,deps,code) ->
+         let mv = [] in
+          let r =
+            {
+              scr_ast_rule = (lang, mv, [], code);
+              language = lang;
+              script_code = code;
+              scr_rule_info = build_rule_info name deps;
+            }
+          in FinalScriptRuleCocciInfo r
       | Ast_cocci.CocciRule
-         (rulename,(dependencies,dropped_isos,z),restast,isexp) ->
-          CocciRuleCocciInfo (
-          {
-            ctl = List.hd ctl_toplevel_list;
-            ast_rule = ast;
-           isexp = List.hd isexp;
-            rulename = rulename;
-            dependencies = dependencies;
-            dropped_isos = dropped_isos;
-            free_vars = List.hd free_var_list;
-            negated_pos_vars = List.hd negated_pos_list;
-            used_after = List.hd used_after_list;
-            positions = List.hd positions_list;
-            ruleid = rulenb;
-            was_matched = ref false;
-          })
+         (rulename,(dependencies,dropped_isos,z),restast,isexp,ruletype) ->
+            CocciRuleCocciInfo (
+            {
+              ctl = List.hd ctl_toplevel_list;
+              metavars = metavars;
+              ast_rule = ast;
+             isexp = List.hd isexp;
+              dropped_isos = dropped_isos;
+              free_vars = List.hd free_var_list;
+              negated_pos_vars = List.hd negated_pos_list;
+              positions = List.hd positions_list;
+             ruletype = ruletype;
+             rule_info = build_rule_info rulename dependencies;
+            })
     )
 
-
 (* --------------------------------------------------------------------- *)
 
-let build_info_program cprogram env = 
-  let (cs, parseinfos) = Common.unzip cprogram in
-  let (cs, envs) =
-    Common.unzip (TAC.annotate_program env !g_contain_typedmetavar cs) in
+let build_info_program (cprogram,typedefs,macros) env =
+
+  let (cs, parseinfos) =
+    Common.unzip cprogram in
+
+  let alltoks =
+    parseinfos +> List.map (fun (s,toks) -> toks) +> List.flatten in
 
-  zip (zip cs parseinfos) envs +> List.map (fun ((c, parseinfo), (enva,envb))->
+  (* I use cs' but really annotate_xxx work by doing side effects on cs *)
+  let cs' =
+    Comment_annotater_c.annotate_program alltoks cs in
+
+  let cs_with_envs =
+    Type_annoter_c.annotate_program env (*!g_contain_typedmetavar*) cs'
+  in
+
+  zip cs_with_envs parseinfos +> List.map (fun ((c, (enva,envb)), parseinfo)->
     let (fullstr, tokens) = parseinfo in
 
-    let flow = 
-      ast_to_flow_with_error_messages c +> Common.map_option (fun flow -> 
+    let flow =
+      ast_to_flow_with_error_messages c +>
+      Common.map_option (fun flow ->
         let flow = Ast_to_flow.annotate_loop_nodes flow in
 
         (* remove the fake nodes for julia *)
@@ -798,156 +1076,175 @@ let build_info_program cprogram env =
         fixed_flow
       )
     in
-
     {
       ast_c = c; (* contain refs so can be modified *)
-      tokens_c =  tokens;
+      tokens_c = tokens;
       fullstring = fullstr;
 
       flow = flow;
 
       contain_loop = contain_loop flow;
-  
+
       env_typing_before = enva;
       env_typing_after = envb;
 
       was_modified = ref false;
-    }
-  )
+
+      all_typedefs = typedefs;
+      all_macros = macros;
+    })
 
 
 
 (* Optimisation. Try not unparse/reparse the whole file when have modifs  *)
-let rebuild_info_program cs file isexp = 
+let rebuild_info_program cs file isexp =
   cs +> List.map (fun c ->
     if !(c.was_modified)
     then
-      (match !Flag.make_hrule with
-       Some dir ->
-         Unparse_hrule.pp_program (c.ast_c, (c.fullstring, c.tokens_c))
-           dir file isexp;
-         []
-      |        None ->
-         let file = Common.new_temp_file "cocci_small_output" ".c" in
-         cfile_of_program 
-            [(c.ast_c, (c.fullstring, c.tokens_c)), Unparse_c.PPnormal] 
-            file;
-         
-          (* Common.command2 ("cat " ^ file); *)
-         let cprogram = cprogram_of_file file in
-         let xs = build_info_program cprogram c.env_typing_before in
-         
-          (* TODO: assert env has not changed,
-           * if yes then must also reparse what follows even if not modified.
-           * Do that only if contain_typedmetavar of course, so good opti.
-          *)
-          (* Common.list_init xs *) (* get rid of the FinalDef *)
-         xs)
+      let file = Common.new_temp_file "cocci_small_output" ".c" in
+      cfile_of_program
+        [(c.ast_c, (c.fullstring, c.tokens_c)), Unparse_c.PPnormal]
+        file;
+
+      (* Common.command2 ("cat " ^ file); *)
+      let cprogram = cprogram_of_file c.all_typedefs c.all_macros file in
+      let xs = build_info_program cprogram c.env_typing_before in
+
+      (* TODO: assert env has not changed,
+      * if yes then must also reparse what follows even if not modified.
+      * Do that only if contain_typedmetavar of course, so good opti.
+      *)
+      (* Common.list_init xs *) (* get rid of the FinalDef *)
+      xs
     else [c]
   ) +> List.concat
 
 
 let rebuild_info_c_and_headers ccs isexp =
-  ccs +> List.iter (fun c_or_h -> 
+  ccs +> List.iter (fun c_or_h ->
     if c_or_h.asts +> List.exists (fun c -> !(c.was_modified))
     then c_or_h.was_modified_once := true;
   );
-  ccs +> List.map (fun c_or_h -> 
+  ccs +> List.map (fun c_or_h ->
     { c_or_h with
-      asts = rebuild_info_program c_or_h.asts c_or_h.full_fname isexp }
+      asts =
+      rebuild_info_program c_or_h.asts c_or_h.full_fname isexp }
   )
 
+let rec prepare_h seen env hpath choose_includes : file_info list =
+  if not (Common.lfile_exists hpath)
+  then
+    begin
+      pr2_once ("TYPE: header " ^ hpath ^ " not found");
+      []
+    end
+  else
+    begin
+      let h_cs = cprogram_of_file_cached hpath in
+      let local_includes =
+       if choose_includes =*= Flag_cocci.I_REALLY_ALL_INCLUDES
+       then
+         List.filter
+           (function x -> not (List.mem x !seen))
+           (includes_to_parse [(hpath,h_cs)] choose_includes)
+       else [] in
+      seen := local_includes @ !seen;
+      let others =
+       List.concat
+         (List.map (function x -> prepare_h seen env x choose_includes)
+            local_includes) in
+      let info_h_cs = build_info_program h_cs !env in
+      env :=
+       if null info_h_cs
+       then !env
+       else last_env_toplevel_c_info info_h_cs;
+      others@
+      [{
+       fname = Common.basename hpath;
+       full_fname = hpath;
+       asts = info_h_cs;
+       was_modified_once = ref false;
+       fpath = hpath;
+       fkind = Header;
+      }]
+    end
 
-
-
-
-
-
-let prepare_c files : file_info list = 
+let prepare_c files choose_includes : file_info list =
   let cprograms = List.map cprogram_of_file_cached files in
-  let includes = includes_to_parse (zip files cprograms) in
+  let includes = includes_to_parse (zip files cprograms) choose_includes in
+  let seen = ref includes in
 
   (* todo?: may not be good to first have all the headers and then all the c *)
-  let all = 
-    (includes +> List.map (fun hpath -> Right hpath))
-    ++
-    ((zip files cprograms) +> List.map (fun (file, asts) -> Left (file, asts)))
-  in
-
-  let env = ref TAC.initial_env in
-
-  let ccs = all +> Common.map_filter (fun x -> 
-    match x with 
-    | Right hpath -> 
-        if not (Common.lfile_exists hpath) 
-        then begin 
-          pr2 ("TYPE: header " ^ hpath ^ " not found"); 
-          None 
-        end
-        else 
-          let h_cs = cprogram_of_file_cached hpath in
-          let info_h_cs = build_info_program h_cs !env in
-          env := 
-            if null info_h_cs
-            then !env
-            else last_env_toplevel_c_info info_h_cs
-          ;
-          Some { 
-            fname = Common.basename hpath;
-            full_fname = hpath;
-            asts = info_h_cs;
-            was_modified_once = ref false;
-            fpath = hpath;
-            fkind = Header;
-          }
-    | Left (file, cprogram) -> 
-        (* todo?: don't update env ? *)
+  let env = ref !TAC.initial_env in
+
+  let includes =
+    includes +>
+    List.map (function hpath -> prepare_h seen env hpath choose_includes) +>
+    List.concat in
+
+  let cfiles =
+    (zip files cprograms) +>
+    List.map
+      (function (file, cprogram) ->
+      (* todo?: don't update env ? *)
         let cs = build_info_program cprogram !env in
         (* we do that only for the c, not for the h *)
         ignore(update_include_rel_pos (cs +> List.map (fun x -> x.ast_c)));
-        Some { 
-          fname = Common.basename file;
-          full_fname = file;
-          asts = cs;
-          was_modified_once = ref false;
-          fpath = file;
-          fkind = Source;
-        }
-  ) 
-  in
-  ccs        
+        {
+        fname = Common.basename file;
+        full_fname = file;
+        asts = cs;
+        was_modified_once = ref false;
+        fpath = file;
+        fkind = Source
+      }) in
+
+  includes @ cfiles
+
+(*****************************************************************************)
+(* Manage environments as they are being built up *)
+(*****************************************************************************)
+
+let init_env _ = Hashtbl.create 101
+
+let update_env env v i = Hashtbl.replace env v i; env
+
+(* know that there are no conflicts *)
+let safe_update_env env v i = Hashtbl.add env v i; env
 
+let end_env env =
+  List.sort compare (Hashtbl.fold (fun k v rest -> (k,v) :: rest) env [])
 
 (*****************************************************************************)
 (* Processing the ctls and toplevel C elements *)
 (*****************************************************************************)
 
 (* The main algorithm =~
- * The algorithm is roughly: 
+ * The algorithm is roughly:
  *  for_all ctl rules in SP
  *   for_all minirule in rule (no more)
  *    for_all binding (computed during previous phase)
  *      for_all C elements
- *         match control flow of function vs minirule 
- *         with the binding and update the set of possible 
+ *         match control flow of function vs minirule
+ *         with the binding and update the set of possible
  *         bindings, and returned the possibly modified function.
  *   pretty print modified C elements and reparse it.
  *
- * 
+ *
  * On ne prends que les newbinding ou returned_any_state est vrai.
  * Si ca ne donne rien, on prends ce qu'il y avait au depart.
- * Mais au nouveau depart de quoi ?  
+ * Mais au nouveau depart de quoi ?
  * - si ca donne rien apres avoir traité toutes les fonctions avec ce binding ?
- * - ou alors si ca donne rien, apres avoir traité toutes les fonctions 
+ * - ou alors si ca donne rien, apres avoir traité toutes les fonctions
  *   avec tous les bindings du round d'avant ?
- * 
+ *
  * Julia pense qu'il faut prendre la premiere solution.
  * Example: on a deux environnements candidats, E1 et E2 apres avoir traité
  * la regle ctl 1. On arrive sur la regle ctl 2.
  * E1 ne donne rien pour la regle 2, on garde quand meme E1 pour la regle 3.
  * E2 donne un match a un endroit et rend E2' alors on utilise ca pour
  * la regle 3.
- * 
+ *
  * I have not to look at used_after_list to decide to restart from
  * scratch. I just need to look if the binding list is empty.
  * Indeed, let's suppose that a SP have 3 regions/rules. If we
@@ -959,7 +1256,7 @@ let prepare_c files : file_info list =
  * region must bind some metavariables used after, and that we
  * dont find any such region, then mysat() will returns lots of
  * Right, and current_binding will not grow, and so we will have
- * an empty list of binding, and we will catch such a case. 
+ * an empty list of binding, and we will catch such a case.
  *
  * opti: julia says that because the binding is
  * determined by the used_after_list, the items in the list
@@ -969,58 +1266,145 @@ let prepare_c files : file_info list =
 
 (* r(ule), c(element in C code), e(nvironment) *)
 
-let rec apply_python_rule r cache newes e rules_that_have_matched
-    rules_that_have_ever_matched =
-  show_or_not_scr_rule_name r.scr_ruleid;
+let merge_env new_e old_e =
+  List.iter
+    (function (e,rules) ->
+      let _ = update_env old_e e rules in ()) new_e;
+  old_e
+
+let contains_binding e (_,(r,m),_) =
+  try
+    let _ = List.find (function ((re, rm), _) -> r =*= re && m =$= rm) e in
+    true
+  with Not_found -> false
+
+exception Exited
+
+let python_application mv ve script_vars r =
+  let mv =
+    List.map
+      (function
+         ((Some x,None),y,z) -> (x,y,z)
+       | _ ->
+           failwith
+             (Printf.sprintf "unexpected ast metavar in rule %s"
+                r.scr_rule_info.rulename))
+      mv in
+  try
+    Pycocci.build_classes (List.map (function (x,y) -> x) ve);
+    Pycocci.construct_variables mv ve;
+    Pycocci.construct_script_variables script_vars;
+    let _ = Pycocci.pyrun_simplestring (local_python_code ^r.script_code) in
+    if !Pycocci.exited
+    then raise Exited
+    else if !Pycocci.inc_match
+    then Some (Pycocci.retrieve_script_variables script_vars)
+    else None
+  with Pycocci.Pycocciexception ->
+    (pr2 ("Failure in " ^ r.scr_rule_info.rulename);
+     raise Pycocci.Pycocciexception)
+
+let ocaml_application mv ve script_vars r =
+  try
+    let script_vals =
+      Run_ocamlcocci.run mv ve script_vars
+       r.scr_rule_info.rulename r.script_code in
+    if !Coccilib.exited
+    then raise Exited
+    else if !Coccilib.inc_match
+    then Some script_vals
+    else None
+  with e -> (pr2 ("Failure in " ^ r.scr_rule_info.rulename); raise e)
+
+(* returns Left in case of dependency failure, Right otherwise *)
+let apply_script_rule r cache newes e rules_that_have_matched
+    rules_that_have_ever_matched script_application =
+  Common.profile_code r.language (fun () ->
+  show_or_not_scr_rule_name r.scr_rule_info.ruleid;
   if not(interpret_dependencies rules_that_have_matched
-          !rules_that_have_ever_matched r.scr_dependencies)
+          !rules_that_have_ever_matched r.scr_rule_info.dependencies)
   then
     begin
       print_dependencies "dependencies for script not satisfied:"
        rules_that_have_matched
-       !rules_that_have_ever_matched r.scr_dependencies;
+       !rules_that_have_ever_matched r.scr_rule_info.dependencies;
       show_or_not_binding "in environment" e;
-      (cache, (e, rules_that_have_matched)::newes)
+      (cache, safe_update_env newes e rules_that_have_matched)
     end
   else
     begin
-      let (_, mv, _) = r.scr_ast_rule in
-      if List.for_all (Pycocci.contains_binding e) mv
-      then
-       begin
+      let (_, mv, script_vars, _) = r.scr_ast_rule in
+      let ve =
+       (List.map (function (n,v) -> (("virtual",n),Ast_c.MetaIdVal (v,[])))
+          !Flag.defined_virtual_env) @ e in
+      let not_bound x = not (contains_binding ve x) in
+      (match List.filter not_bound mv with
+       [] ->
          let relevant_bindings =
            List.filter
              (function ((re,rm),_) ->
-               List.exists (function (_,(r,m)) -> r = re && m = rm) mv)
+               List.exists (function (_,(r,m),_) -> r =*= re && m =$= rm) mv)
              e in
-         let new_cache =
-           if List.mem relevant_bindings cache
-           then cache
-           else
-             begin
-               print_dependencies "dependencies for script satisfied:"
+         (try
+           match List.assoc relevant_bindings cache with
+             None -> (cache,newes)
+           | Some script_vals ->
+               print_dependencies
+                 "dependencies for script satisfied, but cached:"
                  rules_that_have_matched
-                 !rules_that_have_ever_matched r.scr_dependencies;
+                 !rules_that_have_ever_matched
+                 r.scr_rule_info.dependencies;
                show_or_not_binding "in" e;
-               Pycocci.build_classes (List.map (function (x,y) -> x) e);
-               Pycocci.construct_variables mv e;
-               let _ = Pycocci.pyrun_simplestring
-                 ("import coccinelle\nfrom coccinelle "^
-                  "import *\ncocci = Cocci()\n" ^
-                  r.script_code) in
-               relevant_bindings :: cache
-             end in
-         if !Pycocci.inc_match
-         then (new_cache, merge_env [(e, rules_that_have_matched)] newes)
-         else (new_cache, newes)
-       end
-      else (cache, merge_env [(e, rules_that_have_matched)] newes)
-    end
-
-and apply_cocci_rule r rules_that_have_ever_matched es (ccs:file_info list ref) =
-  Common.profile_code r.rulename (fun () -> 
-    show_or_not_rule_name r.ast_rule r.ruleid;
-    show_or_not_ctl_text r.ctl r.ast_rule r.ruleid;
+             (* env might be bigger than what was cached against, so have to
+                merge with newes anyway *)
+               let new_e = (List.combine script_vars script_vals) @ e in
+               let new_e =
+                 new_e +>
+                 List.filter
+                   (fun (s,v) -> List.mem s r.scr_rule_info.used_after) in
+               (cache,update_env newes new_e rules_that_have_matched)
+         with Not_found ->
+           begin
+             print_dependencies "dependencies for script satisfied:"
+               rules_that_have_matched
+               !rules_that_have_ever_matched
+               r.scr_rule_info.dependencies;
+             show_or_not_binding "in" e;
+             match script_application mv ve script_vars r with
+               None ->
+                 (* failure means we should drop e, no new bindings *)
+                 (((relevant_bindings,None) :: cache), newes)
+             | Some script_vals ->
+                 let script_vals =
+                   List.map (function x -> Ast_c.MetaIdVal(x,[]))
+                     script_vals in
+                 let new_e = (List.combine script_vars script_vals) @ e in
+                 let new_e =
+                   new_e +>
+                   List.filter
+                     (fun (s,v) -> List.mem s r.scr_rule_info.used_after) in
+                 r.scr_rule_info.was_matched := true;
+                 (((relevant_bindings,Some script_vals) :: cache),
+                  update_env newes new_e
+                    (r.scr_rule_info.rulename :: rules_that_have_matched))
+           end)
+      |        unbound ->
+         (if !Flag_cocci.show_dependencies
+         then
+           let m2c (_,(r,x),_) = r^"."^x in
+           pr2 (Printf.sprintf "script not applied: %s not bound"
+                  (String.concat ", " (List.map m2c unbound))));
+         let e =
+           e +>
+           List.filter (fun (s,v) -> List.mem s r.scr_rule_info.used_after) in
+         (cache, update_env newes e rules_that_have_matched))
+    end)
+
+let rec apply_cocci_rule r rules_that_have_ever_matched es
+    (ccs:file_info list ref) =
+  Common.profile_code r.rule_info.rulename (fun () ->
+    show_or_not_rule_name r.ast_rule r.rule_info.ruleid;
+    show_or_not_ctl_text r.ctl r.ast_rule r.rule_info.ruleid;
 
     let reorganized_env =
       reassociate_positions r.free_vars r.negated_pos_vars !es in
@@ -1031,19 +1415,22 @@ and apply_cocci_rule r rules_that_have_ever_matched es (ccs:file_info list ref)
        (function (cache,newes) ->
          function ((e,rules_that_have_matched),relevant_bindings) ->
            if not(interpret_dependencies rules_that_have_matched
-                    !rules_that_have_ever_matched r.dependencies)
+                    !rules_that_have_ever_matched
+                    r.rule_info.dependencies)
            then
              begin
                print_dependencies
-                 ("dependencies for rule "^r.rulename^" not satisfied:")
+                 ("dependencies for rule "^r.rule_info.rulename^
+                  " not satisfied:")
                  rules_that_have_matched
-                 !rules_that_have_ever_matched r.dependencies;
+                 !rules_that_have_ever_matched r.rule_info.dependencies;
                show_or_not_binding "in environment" e;
                (cache,
-                merge_env
-                  [(e +> List.filter (fun (s,v) -> List.mem s r.used_after),
-                    rules_that_have_matched)]
-                  newes)
+                update_env newes
+                  (e +>
+                   List.filter
+                     (fun (s,v) -> List.mem s r.rule_info.used_after))
+                  rules_that_have_matched)
              end
            else
              let new_bindings =
@@ -1051,35 +1438,50 @@ and apply_cocci_rule r rules_that_have_ever_matched es (ccs:file_info list ref)
                with
                  Not_found ->
                    print_dependencies
-                     ("dependencies for rule "^r.rulename^" satisfied:")
+                     ("dependencies for rule "^r.rule_info.rulename^
+                      " satisfied:")
                      rules_that_have_matched
-                     !rules_that_have_ever_matched r.dependencies;
+                     !rules_that_have_ever_matched
+                     r.rule_info.dependencies;
                    show_or_not_binding "in" e;
                    show_or_not_binding "relevant in" relevant_bindings;
 
-                   let children_e = ref [] in
-      
+                   (* applying the rule *)
+                   (match r.ruletype with
+                     Ast_cocci.Normal ->
                       (* looping over the functions and toplevel elements in
                         .c and .h *)
-                   concat_headers_and_c !ccs +> List.iter (fun (c,f) -> 
-                     if c.flow <> None 
-                     then
-                        (* does also some side effects on c and r *)
-                       let processed =
-                         process_a_ctl_a_env_a_toplevel r relevant_bindings
-                           c f in
-                       match processed with
-                       | None -> ()
-                       | Some newbindings -> 
-                           newbindings +> List.iter (fun newbinding -> 
-                             children_e :=
-                               Common.insert_set newbinding !children_e)
-                             ); (* end iter cs *)
-
-                   !children_e in
+                       List.rev
+                         (concat_headers_and_c !ccs +>
+                          List.fold_left (fun children_e (c,f) ->
+                            if c.flow <> None
+                            then
+                             (* does also some side effects on c and r *)
+                              let processed =
+                                process_a_ctl_a_env_a_toplevel r
+                                  relevant_bindings c f in
+                              match processed with
+                              | None -> children_e
+                              | Some newbindings ->
+                                  newbindings +>
+                                  List.fold_left
+                                    (fun children_e newbinding ->
+                                      if List.mem newbinding children_e
+                                      then children_e
+                                      else newbinding :: children_e)
+                                    children_e
+                            else children_e)
+                            [])
+                   | Ast_cocci.Generated ->
+                       process_a_generated_a_env_a_toplevel r
+                         relevant_bindings !ccs;
+                       []) in
+
              let old_bindings_to_keep =
                Common.nub
-                 (e +> List.filter (fun (s,v) -> List.mem s r.used_after)) in
+                 (e +>
+                  List.filter
+                    (fun (s,v) -> List.mem s r.rule_info.used_after)) in
              let new_e =
                if null new_bindings
                then
@@ -1088,7 +1490,7 @@ and apply_cocci_rule r rules_that_have_ever_matched es (ccs:file_info list ref)
                    if !Flag_ctl.partial_match
                    then
                      printf
-                       "Empty list of bindings, I will restart from old env";
+                       "Empty list of bindings, I will restart from old env\n";
                    [(old_bindings_to_keep,rules_that_have_matched)]
                  end
                else
@@ -1105,102 +1507,31 @@ and apply_cocci_rule r rules_that_have_ever_matched es (ccs:file_info list ref)
                      (new_bindings +>
                       List.map
                         (List.filter
-                           (fun (s,v) ->
-                             List.mem s r.used_after &&
-                             not (List.mem s old_variables)))) in
+                           (function
+                               (* see comment before combine_pos *)
+                               (s,Ast_c.MetaPosValList []) -> false
+                             | (s,v) ->
+                                 List.mem s r.rule_info.used_after &&
+                                 not (List.mem s old_variables)))) in
                  List.map
                    (function new_binding_to_add ->
                      (List.sort compare
                         (Common.union_set
                            old_bindings_to_keep new_binding_to_add),
-                      r.rulename::rules_that_have_matched))
+                      r.rule_info.rulename::rules_that_have_matched))
                    new_bindings_to_add in
              ((relevant_bindings,new_bindings)::cache,
-              merge_env new_e newes))
-       ([],[]) reorganized_env in (* end iter es *)
-    if !(r.was_matched)
-    then Common.push2 r.rulename rules_that_have_ever_matched;
+  Common.profile_code "merge_env" (function _ ->
+              merge_env new_e newes)))
+       ([],init_env()) reorganized_env in (* end iter es *)
+    if !(r.rule_info.was_matched)
+    then Common.push2 r.rule_info.rulename rules_that_have_ever_matched;
 
-    es := newes;
+    es := end_env newes;
 
     (* apply the tagged modifs and reparse *)
     if not !Flag.sgrep_mode2
-    then ccs := rebuild_info_c_and_headers !ccs r.isexp
-  )
-
-and merge_env new_e old_e =
-  List.fold_left
-    (function old_e ->
-      function (e,rules) as elem ->
-       let (same,diff) = List.partition (function (e1,_) -> e = e1) old_e in
-       match same with
-         [] -> elem :: old_e
-       | [(_,old_rules)] -> (e,Common.union_set rules old_rules) :: diff
-       | _ -> failwith "duplicate environment entries")
-    old_e new_e
-
-and bigloop2 rs (ccs: file_info list) = 
-  let es = ref [(Ast_c.emptyMetavarsBinding,[])] in
-  let ccs = ref ccs in
-  let rules_that_have_ever_matched = ref [] in
-
-  (* looping over the rules *)
-  rs +> List.iter (fun r -> 
-    match r with
-      ScriptRuleCocciInfo r -> 
-       if !Flag_cocci.show_ctl_text then begin
-          Common.pr_xxxxxxxxxxxxxxxxx ();
-          pr ("script: " ^ r.language);
-          Common.pr_xxxxxxxxxxxxxxxxx ();
-         
-          adjust_pp_with_indent (fun () -> 
-            Format.force_newline();
-            let (l,mv,code) = r.scr_ast_rule in
-           let deps = r.scr_dependencies in
-            Pretty_print_cocci.unparse
-             (Ast_cocci.ScriptRule (l,deps,mv,code)));
-       end;
-
-       if !Flag.show_misc then print_endline "RESULT =";
-
-        let (_, newes) =
-          List.fold_left
-            (function (cache, newes) ->
-              function (e, rules_that_have_matched) ->
-               match r.language with
-                  "python" ->
-                   apply_python_rule r cache newes e rules_that_have_matched
-                     rules_that_have_ever_matched
-               | "test" ->
-                   concat_headers_and_c !ccs +> List.iter (fun (c,_) -> 
-                     if c.flow <> None 
-                     then
-                       Printf.printf "Flow: %s\r\nFlow!\r\n%!" c.fullstring);
-                   (cache, newes)
-               | _ ->
-                    Printf.printf "Unknown language: %s\n" r.language;
-                    (cache, newes)
-                     )
-            ([],[]) !es in
-
-        es := newes;
-    | CocciRuleCocciInfo r ->
-       apply_cocci_rule r rules_that_have_ever_matched es ccs);
-
-  if !Flag.sgrep_mode2
-  then begin
-    (* sgrep can lead to code that is not parsable, but we must
-     * still call rebuild_info_c_and_headers to pretty print the 
-     * action (MINUS), so that later the diff will show what was
-     * matched by sgrep. But we don't want the parsing error message
-     * hence the following flag setting. So this code propably
-     * will generate a NotParsedCorrectly for the matched parts
-     * and the very final pretty print and diff will work
-     *)
-    Flag_parsing_c.verbose_parsing := false;
-    ccs := rebuild_info_c_and_headers !ccs false
-  end;
-  !ccs (* return final C asts *)
+    then ccs := rebuild_info_c_and_headers !ccs r.isexp)
 
 and reassociate_positions free_vars negated_pos_vars envs =
   (* issues: isolate the bindings that are relevant to a given rule.
@@ -1251,7 +1582,7 @@ and reassociate_positions free_vars negated_pos_vars envs =
             (function (other_non_pos,other_pos) ->
                (* do we want equal? or just somehow compatible? eg non_pos
               binds only E, but other_non_pos binds both E and E1 *)
-              non_pos = other_non_pos)
+              non_pos =*= other_non_pos)
             splitted_relevant in
         (non_pos,
          List.sort compare
@@ -1263,197 +1594,462 @@ and reassociate_positions free_vars negated_pos_vars envs =
      (List.map (function (non_pos,_) -> List.assoc non_pos extended_relevant)
        splitted_relevant)
 
+(* If the negated posvar is not bound at all, this function will
+nevertheless bind it to [].  If we get rid of these bindings, then the
+matching of the term the position variable with the constraints will fail
+because some variables are unbound.  So we let the binding be [] and then
+we will have to clean these up afterwards.  This should be the only way
+that a position variable can have an empty binding. *)
 and combine_pos negated_pos_vars others =
   List.map
     (function posvar ->
-      (posvar,
-       Ast_c.MetaPosValList
-        (List.sort compare
-           (List.fold_left
-              (function positions ->
-                function other_list ->
-                  try
-                    match List.assoc posvar other_list with
-                      Ast_c.MetaPosValList l1 ->
-                        Common.union_set l1 positions
-                    | _ -> failwith "bad value for a position variable"
-                  with Not_found -> positions)
-              [] others))))
+      let positions =
+       List.sort compare
+         (List.fold_left
+            (function positions ->
+              function other_list ->
+                try
+                  match List.assoc posvar other_list with
+                    Ast_c.MetaPosValList l1 ->
+                      Common.union_set l1 positions
+                  | _ -> failwith "bad value for a position variable"
+                with Not_found -> positions)
+            [] others) in
+      (posvar,Ast_c.MetaPosValList positions))
     negated_pos_vars
 
-and bigloop a b = 
-  Common.profile_code "bigloop" (fun () -> bigloop2 a b)
-
-
-
-
+and process_a_generated_a_env_a_toplevel2 r env = function
+    [cfile] ->
+      let free_vars =
+       List.filter
+         (function
+             (rule,_) when rule =$= r.rule_info.rulename -> false
+           | (_,"ARGS") -> false
+           | _ -> true)
+         r.free_vars in
+      let env_domain = List.map (function (nm,vl) -> nm) env in
+      let metavars =
+       List.filter
+         (function md ->
+           let (rl,_) = Ast_cocci.get_meta_name md in rl =$= r.rule_info.rulename)
+         r.metavars in
+      if Common.include_set free_vars env_domain
+      then Unparse_hrule.pp_rule metavars r.ast_rule env cfile.full_fname
+  | _ -> failwith "multiple files not supported"
+
+and process_a_generated_a_env_a_toplevel rule env ccs =
+  Common.profile_code "process_a_ctl_a_env_a_toplevel"
+    (fun () -> process_a_generated_a_env_a_toplevel2 rule env ccs)
 
 (* does side effects on C ast and on Cocci info rule *)
-and process_a_ctl_a_env_a_toplevel2 r e c f = 
- indent_do (fun () -> 
-  show_or_not_celem "trying" c.ast_c;
-  Flag.currentfile := Some (f ^ ":" ^get_celem c.ast_c);
-  let (trans_info, returned_any_states, inherited_bindings, newbindings) = 
-    Common.save_excursion Flag_ctl.loop_in_src_code (fun () -> 
-      Flag_ctl.loop_in_src_code := !Flag_ctl.loop_in_src_code||c.contain_loop;
-      
+and process_a_ctl_a_env_a_toplevel2 r e c f =
+ indent_do (fun () ->
+   show_or_not_celem "trying" c.ast_c;
+   Flag.currentfile := Some (f ^ ":" ^get_celem c.ast_c);
+   match (r.ctl,c.ast_c) with
+     ((Asttoctl2.NONDECL ctl,t),Ast_c.Declaration _) -> None
+   | ((Asttoctl2.NONDECL ctl,t), _)
+   | ((Asttoctl2.CODE ctl,t), _) ->
+       let ctl = (ctl,t) in (* ctl and other info *)
+       let (trans_info, returned_any_states, inherited_bindings, newbindings) =
+        Common.save_excursion Flag_ctl.loop_in_src_code (fun () ->
+          Flag_ctl.loop_in_src_code :=
+            !Flag_ctl.loop_in_src_code||c.contain_loop;
+
       (***************************************)
       (* !Main point! The call to the engine *)
       (***************************************)
-      let model_ctl  = CCI.model_for_ctl r.dropped_isos (Common.some c.flow) e
-      in CCI.mysat model_ctl r.ctl (r.used_after, e)
-    ) 
-  in
-  if not returned_any_states 
-  then None
-  else begin
-    show_or_not_celem "found match in" c.ast_c;
-    show_or_not_trans_info trans_info;
-    List.iter (show_or_not_binding "out") newbindings;    
+            let model_ctl =
+              CCI.model_for_ctl r.dropped_isos (Common.some c.flow) e
+            in CCI.mysat model_ctl ctl
+              (r.rule_info.rulename, r.rule_info.used_after, e))
+       in
+       if not returned_any_states
+       then None
+       else
+        begin
+          show_or_not_celem "found match in" c.ast_c;
+          show_or_not_trans_info trans_info;
+          List.iter (show_or_not_binding "out") newbindings;
+
+          r.rule_info.was_matched := true;
+
+          if not (null trans_info) &&
+            not (!Flag.sgrep_mode2 && not !Flag_cocci.show_diff)
+          then
+            begin
+              c.was_modified := true;
+              try
+               (* les "more than one var in a decl" et "already tagged token"
+                * font crasher coccinelle. Si on a 5 fichiers, donc on a 5
+                * failed. Le try limite le scope des crashes pendant la
+                * trasformation au fichier concerne. *)
+
+               (* modify ast via side effect *)
+                ignore
+                  (Transformation_c.transform r.rule_info.rulename
+                     r.dropped_isos
+                     inherited_bindings trans_info (Common.some c.flow));
+              with Timeout -> raise Timeout | UnixExit i -> raise (UnixExit i)
+            end;
+
+          Some (List.map (function x -> x@inherited_bindings) newbindings)
+        end
+   )
+
+and process_a_ctl_a_env_a_toplevel  a b c f=
+  Common.profile_code "process_a_ctl_a_env_a_toplevel"
+    (fun () -> process_a_ctl_a_env_a_toplevel2 a b c f)
 
-    r.was_matched := true;
 
-    if not (null trans_info)
-    then begin
-      c.was_modified := true;
-      try 
-        (* les "more than one var in a decl" et "already tagged token"
-         * font crasher coccinelle. Si on a 5 fichiers, donc on a 5
-         * failed. Le try limite le scope des crashes pendant la
-         * trasformation au fichier concerne. *)
-
-        (* modify ast via side effect *)
-        ignore(Transformation_c.transform r.rulename r.dropped_isos
-                  inherited_bindings trans_info (Common.some c.flow));
-      with Timeout -> raise Timeout | UnixExit i -> raise (UnixExit i)
-    end;
+let rec bigloop2 rs (ccs: file_info list) =
+  let init_es = [(Ast_c.emptyMetavarsBinding,[])] in
+  let es = ref init_es in
+  let ccs = ref ccs in
+  let rules_that_have_ever_matched = ref [] in
 
-    Some (List.map (function x -> x@inherited_bindings) newbindings)
-  end
- )
-   
-and process_a_ctl_a_env_a_toplevel  a b c f= 
-  Common.profile_code "process_a_ctl_a_env_a_toplevel" 
-    (fun () -> process_a_ctl_a_env_a_toplevel2 a b c f)
-   
+  (try
 
+  (* looping over the rules *)
+  rs +> List.iter (fun r ->
+    match r with
+      InitialScriptRuleCocciInfo r | FinalScriptRuleCocciInfo r -> ()
+    | ScriptRuleCocciInfo r ->
+       if !Flag_cocci.show_ctl_text then begin
+          Common.pr_xxxxxxxxxxxxxxxxx ();
+          pr ("script: " ^ r.language);
+          Common.pr_xxxxxxxxxxxxxxxxx ();
 
-(*****************************************************************************)
-(* The main function *)
-(*****************************************************************************)
+          adjust_pp_with_indent (fun () ->
+            Format.force_newline();
+            let (l,mv,script_vars,code) = r.scr_ast_rule in
+           let nm = r.scr_rule_info.rulename in
+           let deps = r.scr_rule_info.dependencies in
+            Pretty_print_cocci.unparse
+             (Ast_cocci.ScriptRule (nm,l,deps,mv,script_vars,code)));
+       end;
 
-let full_engine2 (coccifile, isofile) cfiles = 
+      (*pr2 (List.hd(cmd_to_list "free -m | grep Mem"));*)
+       if !Flag.show_misc then print_endline "RESULT =";
 
-  show_or_not_cfiles  cfiles;
-  show_or_not_cocci   coccifile isofile;
-  Pycocci.set_coccifile coccifile;
+        let (_, newes) =
+          List.fold_left
+            (function (cache, newes) ->
+              function (e, rules_that_have_matched) ->
+               match r.language with
+                  "python" ->
+                   apply_script_rule r cache newes e rules_that_have_matched
+                     rules_that_have_ever_matched python_application
+                | "ocaml" ->
+                   apply_script_rule r cache newes e rules_that_have_matched
+                     rules_that_have_ever_matched ocaml_application
+               | "test" ->
+                   concat_headers_and_c !ccs +> List.iter (fun (c,_) ->
+                     if c.flow <> None
+                     then
+                       Printf.printf "Flow: %s\r\nFlow!\r\n%!" c.fullstring);
+                   (cache, newes)
+               | _ ->
+                    Printf.printf "Unknown language: %s\n" r.language;
+                    (cache, newes))
+            ([],init_env()) !es in
 
-  let isofile = 
-    if not (Common.lfile_exists isofile)
-    then begin 
-      pr2 ("warning: Can't find default iso file: " ^ isofile);
-      None
-    end
-    else Some isofile
-  in
+       (if !(r.scr_rule_info.was_matched)
+       then
+         Common.push2 r.scr_rule_info.rulename rules_that_have_ever_matched);
 
-  (* useful opti when use -dir *)
-  let (astcocci,free_var_lists,negated_pos_lists,used_after_lists,
-       positions_lists,toks,_) = 
-      sp_of_file coccifile isofile
-  in
-  let ctls = 
-    Common.memoized _hctl (coccifile, isofile) (fun () -> 
-      ctls_of_ast  astcocci used_after_lists positions_lists)
-  in
+       (* just newes can't work, because if one does include_match false
+           on everything that binds a variable, then nothing is left *)
+        es := (*newes*)
+         (if Hashtbl.length newes = 0 then init_es else end_env newes)
+    | CocciRuleCocciInfo r ->
+       apply_cocci_rule r rules_that_have_ever_matched
+         es ccs)
+  with Exited -> ());
 
-  let contain_typedmetavar = sp_contain_typed_metavar astcocci in
+  if !Flag.sgrep_mode2
+  then begin
+    (* sgrep can lead to code that is not parsable, but we must
+     * still call rebuild_info_c_and_headers to pretty print the
+     * action (MINUS), so that later the diff will show what was
+     * matched by sgrep. But we don't want the parsing error message
+     * hence the following flag setting. So this code propably
+     * will generate a NotParsedCorrectly for the matched parts
+     * and the very final pretty print and diff will work
+     *)
+    Flag_parsing_c.verbose_parsing := false;
+    ccs := rebuild_info_c_and_headers !ccs false
+  end;
+  !ccs (* return final C asts *)
 
-  (* optimisation allowing to launch coccinelle on all the drivers *)
-  if !Flag_cocci.worth_trying_opt && not (worth_trying cfiles toks)
-  then begin 
-    pr2 ("not worth trying:" ^ Common.join " " cfiles);
-    cfiles +> List.map (fun s -> s, None)
-  end
-  else begin
+let bigloop a b =
+  Common.profile_code "bigloop" (fun () -> bigloop2 a b)
 
-    if !Flag.show_misc then Common.pr_xxxxxxxxxxxxxxxxx();
-    if !Flag.show_misc then pr "let's go";
-    if !Flag.show_misc then Common.pr_xxxxxxxxxxxxxxxxx();
+type init_final = Initial | Final
 
-    g_contain_typedmetavar := contain_typedmetavar;
+let initial_final_bigloop2 ty rebuild r =
+  if !Flag_cocci.show_ctl_text then
+    begin
+      Common.pr_xxxxxxxxxxxxxxxxx ();
+      pr ((match ty with Initial -> "initial" | Final -> "final") ^ ": " ^
+         r.language);
+      Common.pr_xxxxxxxxxxxxxxxxx ();
 
-    check_macro_in_sp_and_adjust toks;
+      adjust_pp_with_indent (fun () ->
+       Format.force_newline();
+       Pretty_print_cocci.unparse(rebuild r.scr_ast_rule r.scr_rule_info.dependencies));
+    end;
 
-    let cocci_infos =
-      prepare_cocci ctls free_var_lists negated_pos_lists
-       used_after_lists positions_lists astcocci in
-    let c_infos  = prepare_c cfiles in
+  match r.language with
+    "python" ->
+      (* include_match makes no sense in an initial or final rule, although
+        we have no way to prevent it *)
+      let newes = init_env() in
+      let _ = apply_script_rule r [] newes [] [] (ref []) python_application in
+      ()
+  | "ocaml" when ty = Initial -> () (* nothing to do *)
+  | "ocaml" ->
+      (* include_match makes no sense in an initial or final rule, although
+        we have no way to prevent it *)
+      let newes = init_env() in
+      let _ = apply_script_rule r [] newes [] [] (ref []) ocaml_application in
+      ()
+  | _ ->
+      failwith ("Unknown language for initial/final script: "^
+               r.language)
 
-    show_or_not_ctl_tex astcocci ctls;
+let initial_final_bigloop a b c =
+  Common.profile_code "initial_final_bigloop"
+    (fun () -> initial_final_bigloop2 a b c)
 
-    (* ! the big loop ! *)
-    let c_infos' = bigloop cocci_infos c_infos in
+(*****************************************************************************)
+(* The main functions *)
+(*****************************************************************************)
+
+let pre_engine2 (coccifile, isofile) =
+  show_or_not_cocci coccifile isofile;
+  Pycocci.set_coccifile coccifile;
 
-    if !Flag.show_misc then Common.pr_xxxxxxxxxxxxxxxxx ();
-    if !Flag.show_misc then pr "Finished";
-    if !Flag_ctl.graphical_trace then gen_pdf_graph ();
-    if !Flag.show_misc then Common.pr_xxxxxxxxxxxxxxxxx();
+  let isofile =
+    if not (Common.lfile_exists isofile)
+    then begin
+      pr2 ("warning: Can't find default iso file: " ^ isofile);
+      None
+    end
+    else Some isofile in
 
-    c_infos' +> List.map (fun c_or_h -> 
-      if !(c_or_h.was_modified_once)
-      then begin
-        let outfile = Common.new_temp_file "cocci-output" ("-" ^ c_or_h.fname) 
-        in
+  (* useful opti when use -dir *)
+  let (metavars,astcocci,
+       free_var_lists,negated_pos_lists,used_after_lists,
+       positions_lists,(toks,_,_)) = sp_of_file coccifile isofile in
+
+  let ctls = ctls_of_ast astcocci used_after_lists positions_lists in
+
+  g_contain_typedmetavar := sp_contain_typed_metavar astcocci;
+
+  check_macro_in_sp_and_adjust toks;
+
+  show_or_not_ctl_tex astcocci ctls;
+
+  let cocci_infos =
+    prepare_cocci ctls free_var_lists negated_pos_lists
+      used_after_lists positions_lists metavars astcocci in
+
+  let used_languages =
+    List.fold_left
+      (function languages ->
+        function
+            ScriptRuleCocciInfo(r) ->
+              if List.mem r.language languages then
+                languages
+              else
+                r.language::languages
+          | _ -> languages)
+      [] cocci_infos in
+
+  let runrule r =
+    let rlang = r.language in
+    let rname = r.scr_rule_info.rulename in
+    try
+      let _ = List.assoc (rlang,rname) !Iteration.initialization_stack in
+      ()
+    with Not_found ->
+      begin
+       Iteration.initialization_stack :=
+         ((rlang,rname),!Flag.defined_virtual_rules) ::
+         !Iteration.initialization_stack;
+       initial_final_bigloop Initial
+         (fun (x,_,_,y) -> fun deps ->
+           Ast_cocci.InitialScriptRule(rname,x,deps,y))
+         r
+      end in
+  
+  let initialized_languages =
+    List.fold_left
+      (function languages ->
+       function
+           InitialScriptRuleCocciInfo(r) ->
+             let rlang = r.language in
+             (if List.mem rlang languages
+             then failwith ("double initializer found for "^rlang));
+             if interpret_dependencies [] [] r.scr_rule_info.dependencies
+             then begin runrule r; rlang::languages end
+             else languages
+         | _ -> languages)
+      [] cocci_infos in
+
+  let uninitialized_languages =
+    List.filter
+      (fun used -> not (List.mem used initialized_languages))
+      used_languages in
+
+  List.iter
+    (fun lgg ->
+      let rule_info =
+       {rulename = "";
+         dependencies = Ast_cocci.NoDep;
+         used_after = [];
+         ruleid = (-1);
+         was_matched = ref false;} in
+      runrule (make_init lgg "" rule_info))
+    uninitialized_languages;
+
+  (cocci_infos,toks)
+
+let pre_engine a =
+  Common.profile_code "pre_engine" (fun () -> pre_engine2 a)
+
+let full_engine2 (cocci_infos,toks) cfiles =
 
-        if c_or_h.fkind = Header 
-        then pr2 ("a header file was modified: " ^ c_or_h.fname);
+  show_or_not_cfiles  cfiles;
 
-        (* and now unparse everything *)
-        cfile_of_program (for_unparser c_or_h.asts) outfile;
+  (* optimisation allowing to launch coccinelle on all the drivers *)
+  if !Flag_cocci.worth_trying_opt && not (worth_trying cfiles toks)
+  then
+    begin
+      (match toks with
+       None -> ()
+      | Some toks ->
+         pr2 ("No matches found for " ^ (Common.join " " toks)
+              ^ "\nSkipping:" ^ (Common.join " " cfiles)));
+      cfiles +> List.map (fun s -> s, None)
+    end
+  else
+    begin
 
-        let show_only_minus = !Flag.sgrep_mode2 in
-        show_or_not_diff c_or_h.fpath outfile show_only_minus;
+      if !Flag.show_misc then Common.pr_xxxxxxxxxxxxxxxxx();
+      if !Flag.show_misc then pr "let's go";
+      if !Flag.show_misc then Common.pr_xxxxxxxxxxxxxxxxx();
 
-        (c_or_h.fpath, 
-        if !Flag.sgrep_mode2 then None else Some outfile
-        )
-      end
-      else 
-        (c_or_h.fpath, None)
-    );
-  end
+      if !Flag_cocci.show_binding_in_out
+      then
+       begin
+         (match !Flag.defined_virtual_rules with
+           [] -> ()
+         | l -> pr (Printf.sprintf "Defined virtual rules: %s"
+                      (String.concat " " l)));
+         List.iter
+           (function (v,vl) ->
+             pr (Printf.sprintf "%s = %s" v vl))
+           !Flag.defined_virtual_env;
+         Common.pr_xxxxxxxxxxxxxxxxx()
+       end;
 
-let full_engine a b = 
-  Common.profile_code "full_engine" (fun () -> full_engine2 a b)
+      let choose_includes =
+       match !Flag_cocci.include_options with
+         Flag_cocci.I_UNSPECIFIED ->
+           if !g_contain_typedmetavar
+           then Flag_cocci.I_NORMAL_INCLUDES
+           else Flag_cocci.I_NO_INCLUDES
+       | x -> x in
+      let c_infos  = prepare_c cfiles choose_includes in
+
+      (* ! the big loop ! *)
+      let c_infos' = bigloop cocci_infos c_infos in
+
+      if !Flag.show_misc then Common.pr_xxxxxxxxxxxxxxxxx ();
+      if !Flag.show_misc then pr "Finished";
+      if !Flag.show_misc then Common.pr_xxxxxxxxxxxxxxxxx ();
+      if !Flag_ctl.graphical_trace then gen_pdf_graph ();
+
+      c_infos' +> List.map (fun c_or_h ->
+       if !(c_or_h.was_modified_once)
+       then
+         begin
+            let outfile =
+             Common.new_temp_file "cocci-output" ("-" ^ c_or_h.fname) in
+
+            if c_or_h.fkind =*= Header
+            then pr2 ("a header file was modified: " ^ c_or_h.fname);
+
+            (* and now unparse everything *)
+            cfile_of_program (for_unparser c_or_h.asts) outfile;
+
+            show_or_not_diff c_or_h.fpath outfile;
+
+            (c_or_h.fpath,
+             if !Flag.sgrep_mode2 then None else Some outfile)
+         end
+       else (c_or_h.fpath, None))
+    end
 
+let full_engine a b =
+  Common.profile_code "full_engine"
+    (fun () -> let res = full_engine2 a b in (*Gc.print_stat stderr; *)res)
+
+let post_engine2 (cocci_infos,_) =
+  List.iter
+    (function ((language,_),virt_rules) ->
+      Flag.defined_virtual_rules := virt_rules;
+      let _ =
+       List.fold_left
+         (function languages ->
+           function
+               FinalScriptRuleCocciInfo(r) ->
+                 (if r.language = language && List.mem r.language languages
+                 then failwith ("double finalizer found for "^r.language));
+                 initial_final_bigloop Final
+                   (fun (x,_,_,y) -> fun deps ->
+                     Ast_cocci.FinalScriptRule(r.scr_rule_info.rulename,
+                                               x,deps,y))
+                   r;
+                 r.language::languages
+             | _ -> languages)
+         [] cocci_infos in
+      ())
+    !Iteration.initialization_stack
+
+let post_engine a =
+  Common.profile_code "post_engine" (fun () -> post_engine2 a)
 
 (*****************************************************************************)
 (* check duplicate from result of full_engine *)
 (*****************************************************************************)
 
-let check_duplicate_modif2 xs = 
+let check_duplicate_modif2 xs =
   (* opti: let groups = Common.groupBy (fun (a,resa) (b,resb) -> a =$= b) xs *)
-  pr2 ("Check duplication for " ^ i_to_s (List.length xs) ^ " files");
+  if !Flag_cocci.verbose_cocci
+  then pr2 ("Check duplication for " ^ i_to_s (List.length xs) ^ " files");
+
   let groups = Common.group_assoc_bykey_eff xs in
-  groups +> Common.map_filter (fun (file, xs) -> 
+  groups +> Common.map_filter (fun (file, xs) ->
     match xs with
-    | [] -> raise Impossible
+    | [] -> raise (Impossible 162)
     | [res] -> Some (file, res)
-    | res::xs -> 
-        match res with 
-        | None -> 
-            if not (List.for_all (fun res2 -> res2 = None) xs)
+    | res::xs ->
+        match res with
+        | None ->
+            if not (List.for_all (fun res2 -> res2 =*= None) xs)
             then begin
               pr2 ("different modification result for " ^ file);
               None
             end
             else Some (file, None)
-        | Some res -> 
-            if not(List.for_all (fun res2 -> 
+        | Some res ->
+            if not(List.for_all (fun res2 ->
               match res2 with
               | None -> false
-              | Some res2 -> 
+              | Some res2 ->
                   let diff = Common.cmd_to_list ("diff -u -b -B "^res^" "^res2)
                   in
                   null diff
@@ -1462,9 +2058,7 @@ let check_duplicate_modif2 xs =
               None
             end
             else Some (file, Some res)
-            
-        
   )
-let check_duplicate_modif a = 
+let check_duplicate_modif a =
   Common.profile_code "check_duplicate" (fun () -> check_duplicate_modif2 a)