Release coccinelle-0.2.4rc6
[bpt/coccinelle.git] / cocci.ml
index a43055e..16a4b88 100644 (file)
--- a/cocci.ml
+++ b/cocci.ml
@@ -69,13 +69,14 @@ let _hctl = Hashtbl.create 101
 (* --------------------------------------------------------------------- *)
 let sp_of_file2 file iso   =
   Common.memoized _hparse (file, iso) (fun () ->
-    let (_,xs,_,_,_,_,_,_) as res = Parse_cocci.process file iso false in
+    let (_,xs,_,_,_,_,_) as res = Parse_cocci.process file iso false in
     (match Prepare_ocamlcocci.prepare file xs with
       None -> ()
     | Some ocaml_script_file ->
         (* compile file *)
        Prepare_ocamlcocci.load_file ocaml_script_file;
-       Prepare_ocamlcocci.clean_file ocaml_script_file);
+       if not !Common.save_tmp_files
+       then Prepare_ocamlcocci.clean_file ocaml_script_file);
     res)
 let sp_of_file file iso    =
   Common.profile_code "parse cocci" (fun () -> sp_of_file2 file iso)
@@ -174,13 +175,15 @@ let fix_sgrep_diffs l =
        then
          (match Str.split (Str.regexp " ") s with
            bef::min::pl::aft ->
-             (match Str.split (Str.regexp ",") pl with
-               [n1;n2] ->
-                 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 + line information")
+             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
@@ -192,18 +195,21 @@ let fix_sgrep_diffs l =
        then
          (match Str.split (Str.regexp " ") s with
            bef::min::pl::aft ->
-             (match (Str.split (Str.regexp ",") min,
-                     Str.split (Str.regexp ",") pl) with
-               ([_;m2],[n1;n2]) ->
-                 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 -/+ line information")
+             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))
@@ -263,24 +269,26 @@ let show_or_not_diff2 cfile outfile =
              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))
                | _ -> failwith "bad command" in
              let (minus_line,plus_line) =
-               if !Flag.sgrep_mode2
-               then (minus_file,"+++ /tmp/nothing")
-               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 " "
@@ -511,7 +519,7 @@ let sp_contain_typed_metavar_z toplevel_list_list =
   let combiner =
     Visitor_ast.combiner bind option_default
       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
   in
@@ -568,7 +576,9 @@ let (includes_to_parse:
     Flag_cocci.I_UNSPECIFIED -> failwith "not possible"
   | Flag_cocci.I_NO_INCLUDES -> []
   | x ->
-      let all_includes = x =*= Flag_cocci.I_ALL_INCLUDES in
+      let all_includes =
+       List.mem x
+         [Flag_cocci.I_ALL_INCLUDES; Flag_cocci.I_REALLY_ALL_INCLUDES] in
       xs +> List.map (fun (file, cs) ->
        let dir = Common.dirname file in
 
@@ -581,15 +591,20 @@ let (includes_to_parse:
             | 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 f) && all_includes
                  then
-                   interpret_include_path relpath
-                 else Some attempt2
-               else Some f
+                   let attempt2 = Filename.concat dir (Common.last xs) in
+                     if not (Sys.file_exists attempt2) && all_includes
+                     then
+                       interpret_include_path relpath
+                     else Some attempt2
+                 else
+                   if all_includes then interpret_include_path relpath
+                   else None
 
             | Ast_c.NonLocal xs ->
                let relpath = Common.join "/" xs in
@@ -602,7 +617,7 @@ let (includes_to_parse:
                  )
          | _ -> None))
        +> List.concat
-       +> Common.uniq
+       +> (fun x -> (List.rev (Common.uniq (List.rev x)))) (*uniq keeps last*)
 
 let rec interpret_dependencies local global = function
     Ast_cocci.Dep s      -> List.mem s local
@@ -754,15 +769,24 @@ type toplevel_c_info = {
   (* 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_rulename: string;
   scr_ast_rule:
-      string * (string * Ast_cocci.meta_name * Ast_cocci.metavar) list *
+      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 = {
@@ -771,21 +795,17 @@ type toplevel_cocci_info_cocci_rule = {
   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"]
    *)
   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 =
@@ -853,15 +873,13 @@ let python_code =
     local_python_code ^
     "cocci = Cocci()\n"
 
-let make_init name rulenb lang deps code =
+let make_init lang code rule_info =
   let mv = [] in
   {
-  scr_rulename = name;
-  scr_ast_rule = (lang, mv, code);
+  scr_ast_rule = (lang, mv, [], code);
   language = lang;
-  scr_dependencies = deps;
-  scr_ruleid = rulenb;
-  script_code = (if lang = "python" then python_code else "") ^code
+  script_code = (if lang = "python" then python_code else "") ^code;
+  scr_rule_info = rule_info;
 }
 
 (* --------------------------------------------------------------------- *)
@@ -877,6 +895,13 @@ let prepare_cocci ctls free_var_lists negated_pos_lists
     (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 _
@@ -887,54 +912,45 @@ let prepare_cocci ctls free_var_lists negated_pos_lists
       then failwith "not handling multiple minirules";
 
       match ast with
-        Ast_cocci.ScriptRule (name,lang,deps,mv,code) ->
+        Ast_cocci.ScriptRule (name,lang,deps,mv,script_vars,code) ->
           let r =
-          {
-           scr_rulename = name;
-            scr_ast_rule = (lang, mv, code);
-            language = lang;
-            scr_dependencies = deps;
-            scr_ruleid = rulenb;
-            script_code = code;
-          }
+            {
+             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 name rulenb lang deps code in
+         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_rulename = name;
-            scr_ast_rule = (lang, mv, code);
-            language = lang;
-            scr_dependencies = deps;
-            scr_ruleid = rulenb;
-            script_code = code;
-          }
+            {
+              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,ruletype) ->
-          CocciRuleCocciInfo (
-          {
-            ctl = List.hd ctl_toplevel_list;
-            metavars = metavars;
-            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 ua) @ (List.hd fua);
-            positions = List.hd positions_list;
-            ruleid = rulenb;
-           ruletype = ruletype;
-            was_matched = ref false;
-          })
+            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 =
@@ -1023,63 +1039,75 @@ let rebuild_info_c_and_headers ccs isexp =
       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 ("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 choose_includes : file_info list =
   let cprograms = List.map cprogram_of_file_cached files 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 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
 
 (*****************************************************************************)
 (* Processing the ctls and toplevel C elements *)
@@ -1159,33 +1187,55 @@ let contains_binding e (_,(r,m),_) =
     true
   with Not_found -> false
 
-let python_application mv ve r =
-  Pycocci.build_classes (List.map (function (x,y) -> x) ve);
-  Pycocci.construct_variables mv ve;
-  let _ = Pycocci.pyrun_simplestring (local_python_code ^r.script_code) in
-  !Pycocci.inc_match
-
-let ocaml_application mv ve r =
-  Run_ocamlcocci.run mv ve r.scr_rulename r.script_code;
-  !Coccilib.inc_match
+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.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.inc_match
+    then Some script_vals
+    else None
+  with e -> (pr2 ("Failure in " ^ r.scr_rule_info.rulename); raise e)
 
 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_ruleid;
+  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)
     end
   else
     begin
-      let (_, mv, _) = r.scr_ast_rule in
+      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
@@ -1197,43 +1247,70 @@ let apply_script_rule r cache newes e rules_that_have_matched
              (function ((re,rm),_) ->
                List.exists (function (_,(r,m),_) -> r =*= re && m =$= rm) mv)
              e in
-         if List.mem relevant_bindings cache
-         then
-           begin
-             print_dependencies
-               "dependencies for script satisfied, but cached:"
-               rules_that_have_matched
-               !rules_that_have_ever_matched
-               r.scr_dependencies;
-             show_or_not_binding "in" e;
-             (cache,newes)
-           end
-         else
+         (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_rule_info.dependencies;
+               show_or_not_binding "in" e;
+             (* 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,merge_env [(new_e, rules_that_have_matched)] newes)
+         with Not_found ->
            begin
              print_dependencies "dependencies for script satisfied:"
                rules_that_have_matched
                !rules_that_have_ever_matched
-               r.scr_dependencies;
+               r.scr_rule_info.dependencies;
              show_or_not_binding "in" e;
-             let new_cache = relevant_bindings :: cache in
-             if script_application mv ve r
-             then (new_cache, merge_env [(e, rules_that_have_matched)] newes)
-             else (new_cache, newes)
-           end
+             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),
+                  merge_env
+                    [(new_e,
+                      r.scr_rule_info.rulename :: rules_that_have_matched)]
+                    newes)
+           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, merge_env [(e, rules_that_have_matched)] newes))
     end)
 
 let rec 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;
+  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
@@ -1245,17 +1322,20 @@ let rec apply_cocci_rule r rules_that_have_ever_matched es
          function ((e,rules_that_have_matched),relevant_bindings) ->
            if not(interpret_dependencies rules_that_have_matched
                     !rules_that_have_ever_matched
-                    r.dependencies)
+                    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),
+                  [(e +>
+                    List.filter
+                      (fun (s,v) -> List.mem s r.rule_info.used_after),
                     rules_that_have_matched)]
                   newes)
              end
@@ -1265,10 +1345,11 @@ let rec apply_cocci_rule r rules_that_have_ever_matched es
                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;
+                     r.rule_info.dependencies;
                    show_or_not_binding "in" e;
                    show_or_not_binding "relevant in" relevant_bindings;
 
@@ -1305,7 +1386,9 @@ let rec apply_cocci_rule r rules_that_have_ever_matched es
 
              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
@@ -1335,20 +1418,20 @@ let rec apply_cocci_rule r rules_that_have_ever_matched es
                                (* see comment before combine_pos *)
                                (s,Ast_c.MetaPosValList []) -> false
                              | (s,v) ->
-                                 List.mem s r.used_after &&
+                                 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;
+    if !(r.rule_info.was_matched)
+    then Common.push2 r.rule_info.rulename rules_that_have_ever_matched;
 
     es := newes;
 
@@ -1446,7 +1529,7 @@ and process_a_generated_a_env_a_toplevel2 r env = function
       let free_vars =
        List.filter
          (function
-             (rule,_) when rule =$= r.rulename -> false
+             (rule,_) when rule =$= r.rule_info.rulename -> false
            | (_,"ARGS") -> false
            | _ -> true)
          r.free_vars in
@@ -1454,7 +1537,7 @@ and process_a_generated_a_env_a_toplevel2 r env = function
       let metavars =
        List.filter
          (function md ->
-           let (rl,_) = Ast_cocci.get_meta_name md in rl =$= r.rulename)
+           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
@@ -1477,7 +1560,7 @@ and process_a_ctl_a_env_a_toplevel2 r e c f =
       (* !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 CCI.mysat model_ctl r.ctl (r.rule_info.used_after, e)
     )
   in
   if not returned_any_states
@@ -1487,9 +1570,10 @@ and process_a_ctl_a_env_a_toplevel2 r e c f =
     show_or_not_trans_info trans_info;
     List.iter (show_or_not_binding "out") newbindings;
 
-    r.was_matched := true;
+    r.rule_info.was_matched := true;
 
-    if not (null trans_info)
+    if not (null trans_info) &&
+      not (!Flag.sgrep_mode2 && not !Flag_cocci.show_diff)
     then begin
       c.was_modified := true;
       try
@@ -1499,7 +1583,7 @@ and process_a_ctl_a_env_a_toplevel2 r e c f =
          * trasformation au fichier concerne. *)
 
         (* modify ast via side effect *)
-        ignore(Transformation_c.transform r.rulename r.dropped_isos
+        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;
@@ -1531,10 +1615,11 @@ let rec bigloop2 rs (ccs: file_info list) =
 
           adjust_pp_with_indent (fun () ->
             Format.force_newline();
-            let (l,mv,code) = r.scr_ast_rule in
-           let deps = r.scr_dependencies in
+            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 ("",l,deps,mv,code)));
+             (Ast_cocci.ScriptRule (nm,l,deps,mv,script_vars,code)));
        end;
 
        if !Flag.show_misc then print_endline "RESULT =";
@@ -1561,7 +1646,11 @@ let rec bigloop2 rs (ccs: file_info list) =
                     (cache, newes))
             ([],[]) !es in
 
-        es := (if newes = [] then init_es else newes);
+       (if !(r.scr_rule_info.was_matched)
+       then
+         Common.push2 r.scr_rule_info.rulename rules_that_have_ever_matched);
+
+        es := newes (*(if newes = [] then init_es else newes)*);
     | CocciRuleCocciInfo r ->
        apply_cocci_rule r rules_that_have_ever_matched
          es ccs);
@@ -1596,7 +1685,7 @@ let initial_final_bigloop2 ty rebuild r =
 
       adjust_pp_with_indent (fun () ->
        Format.force_newline();
-       Pretty_print_cocci.unparse(rebuild r.scr_ast_rule r.scr_dependencies));
+       Pretty_print_cocci.unparse(rebuild r.scr_ast_rule r.scr_rule_info.dependencies));
     end;
 
   match r.language with
@@ -1612,8 +1701,8 @@ let initial_final_bigloop2 ty rebuild r =
       let _ = apply_script_rule r [] [] [] [] (ref []) ocaml_application in
       ()
   | _ ->
-      Printf.printf "Unknown language for initial/final script: %s\n"
-       r.language
+      failwith ("Unknown language for initial/final script: "^
+               r.language)
 
 let initial_final_bigloop a b c =
   Common.profile_code "initial_final_bigloop"
@@ -1638,7 +1727,7 @@ let pre_engine2 (coccifile, isofile) =
   (* useful opti when use -dir *)
   let (metavars,astcocci,
        free_var_lists,negated_pos_lists,used_after_lists,
-       positions_lists,toks,_) =
+       positions_lists,(toks,_,_)) =
       sp_of_file coccifile isofile in
   let ctls = ctls_of_ast astcocci used_after_lists positions_lists in
 
@@ -1673,12 +1762,12 @@ let pre_engine2 (coccifile, isofile) =
                then
                 failwith
                   ("double initializer found for "^r.language));
-              if interpret_dependencies [] [] r.scr_dependencies
+              if interpret_dependencies [] [] r.scr_rule_info.dependencies
               then
                 begin
                   initial_final_bigloop Initial
-                    (fun (x,_,y) -> fun deps ->
-                      Ast_cocci.InitialScriptRule(r.scr_rulename,x,deps,y))
+                    (fun (x,_,_,y) -> fun deps ->
+                      Ast_cocci.InitialScriptRule(r.scr_rule_info.rulename,x,deps,y))
                     r;
                   r.language::languages
                 end
@@ -1689,15 +1778,20 @@ let pre_engine2 (coccifile, isofile) =
   let uninitialized_languages =
     List.filter
       (fun used -> not (List.mem used initialized_languages))
-      used_languages
-  in
-    List.iter (fun lgg ->
-                initial_final_bigloop Initial
-                  (fun (x,_,y) -> fun deps ->
-                    Ast_cocci.InitialScriptRule("",x,deps,y))
-                  (make_init "" (-1) lgg Ast_cocci.NoDep "");
-             )
-      uninitialized_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
+      initial_final_bigloop Initial
+       (fun (x,_,_,y) -> fun deps ->
+         Ast_cocci.InitialScriptRule("",x,deps,y))
+       (make_init lgg "" rule_info))
+    uninitialized_languages;
 
   (cocci_infos,toks)
 
@@ -1777,8 +1871,8 @@ let post_engine2 (cocci_infos,_) =
              (if 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_rulename,x,deps,y))
+               (fun (x,_,_,y) -> fun deps ->
+                 Ast_cocci.FinalScriptRule(r.scr_rule_info.rulename,x,deps,y))
                r;
              r.language::languages
          | _ -> languages)