Release coccinelle-0.2.1-rc1
[bpt/coccinelle.git] / cocci.ml
index 97cabba..089297f 100644 (file)
--- a/cocci.ml
+++ b/cocci.ml
@@ -1,5 +1,5 @@
 (*
- * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen
+ * Copyright 2005-2010, 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.
  *
@@ -28,7 +28,7 @@ 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
@@ -42,20 +42,20 @@ module Ast_to_flow = Control_flow_c_build
 (* --------------------------------------------------------------------- *)
 (* C related *)
 (* --------------------------------------------------------------------- *)
-let cprogram_of_file file = 
+let cprogram_of_file file =
   let (program2, _stat) = Parse_c.parse_c_and_cpp file in
-  program2 
+  program2
 
-let cprogram_of_file_cached file = 
+let cprogram_of_file_cached file =
   let (program2, _stat) = Parse_c.parse_cache file in
   if !Flag_cocci.ifdef_to_if
-  then 
-    program2 +> Parse_c.with_program2 (fun asts -> 
+  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 = 
+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 *)
@@ -68,35 +68,35 @@ let _hctl = Hashtbl.create 101
 let sp_of_file2 file iso   =
   Common.memoized _hparse (file, iso) (fun () ->
     Parse_cocci.process file iso false)
-let sp_of_file file iso    = 
+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)
 
 
@@ -130,13 +130,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);
@@ -145,12 +145,12 @@ 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 show_or_not_diff2 cfile outfile show_only_minus =
   if !Flag_cocci.show_diff then begin
     match Common.fst(Compare_c.compare_to_original cfile outfile) with
       Compare_c.Correct -> () (* diff only in spacing, etc *)
@@ -204,17 +204,17 @@ let show_or_not_diff2 cfile outfile show_only_minus =
                           (String.concat ":" l1) (String.concat ":" l2)) in
              diff_line::minus_line::plus_line::rest
          | _ -> res in
-       xs +> List.iter (fun s -> 
+       xs +> List.iter (fun s ->
          if s =~ "^\\+" && show_only_minus
          then ()
          else pr s)
   end
-let show_or_not_diff a b c  = 
+let show_or_not_diff a b c  =
   Common.profile_code "show_xxx" (fun () -> show_or_not_diff2 a b c)
-    
-    
+
+
 (* the derived input *)
-    
+
 let show_or_not_ctl_tex2 astcocci ctls =
   if !Flag_cocci.show_ctl_tex then begin
     Ctltotex.totex ("/tmp/__cocci_ctl.tex") astcocci ctls;
@@ -222,11 +222,10 @@ let show_or_not_ctl_tex2 astcocci ctls =
                     "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.show_transinfo or !Flag_cocci.show_binding_in_out
@@ -254,19 +253,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 () -> 
+    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 "";
@@ -277,19 +276,19 @@ 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 = namefuncs;},_) -> 
+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 (name, _);}, _], _)) -> 
+       (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 = namefuncs},_) -> 
+  (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)
@@ -303,12 +302,12 @@ 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 = 
+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
@@ -318,18 +317,18 @@ let show_or_not_trans_info2 trans_info =
       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;
             );
           )
@@ -337,18 +336,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)
 
 
@@ -357,7 +356,7 @@ 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 *)
@@ -365,15 +364,15 @@ let worth_trying cfiles tokens =
   if not !Flag_cocci.windows && not (null tokens)
   then
    (* 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]*$" -> 
+    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_]" -> 
+      | _ when s =~ "^[A-Za-z_]" ->
           "\\b" ^ s
 
-      | _ when s =~ ".*[A-Za-z_]$" -> 
+      | _ when s =~ ".*[A-Za-z_]$" ->
           s ^ "\\b"
       | _ -> s
 
@@ -389,9 +388,9 @@ let worth_trying cfiles tokens =
     )
   else true
 
-let check_macro_in_sp_and_adjust tokens = 
+let check_macro_in_sp_and_adjust tokens =
   let tokens = Common.union_all tokens in
-  tokens +> List.iter (fun s -> 
+  tokens +> List.iter (fun s ->
     if Hashtbl.mem !Parse_c._defs s
     then begin
       if !Flag_cocci.verbose_cocci then begin
@@ -403,17 +402,17 @@ let check_macro_in_sp_and_adjust tokens =
   )
 
 
-let contain_loop gopt = 
+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
@@ -423,24 +422,23 @@ 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
       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
@@ -458,9 +456,9 @@ 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 interpret_include_path _ =
@@ -476,16 +474,16 @@ let (includes_to_parse:
   | Flag_cocci.I_NO_INCLUDES -> []
   | x ->
       let all_includes = x =*= Flag_cocci.I_ALL_INCLUDES in
-      xs +> List.map (fun (file, cs) -> 
+      xs +> List.map (fun (file, cs) ->
        let dir = Common.dirname file in
-       
-       cs +> Common.map_filter (fun (c,_info_item) -> 
+
+       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;})  -> 
+                {Ast_c.i_include = ((x,ii)); i_rel_pos = info_h_pos;})  ->
            (match x with
-            | Ast_c.Local xs -> 
+            | Ast_c.Local xs ->
                let f = Filename.concat dir (Common.join "/" xs) in
              (* for our tests, all the files are flat in the current dir *)
                if not (Sys.file_exists f) && !Flag_cocci.relax_include_path
@@ -497,10 +495,10 @@ let (includes_to_parse:
                  else Some attempt2
                else Some f
 
-            | Ast_c.NonLocal xs -> 
+            | Ast_c.NonLocal xs ->
                if all_includes ||
                Common.fileprefix (Common.last xs) =$= Common.fileprefix file
-               then 
+               then
                   Some (Filename.concat (interpret_include_path())
                           (Common.join "/" xs))
                else None
@@ -509,7 +507,7 @@ let (includes_to_parse:
          | _ -> None))
        +> List.concat
        +> Common.uniq
-      
+
 let rec interpret_dependencies local global = function
     Ast_cocci.Dep s      -> List.mem s local
   | Ast_cocci.AntiDep s  ->
@@ -529,7 +527,7 @@ let rec interpret_dependencies local global = function
       (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
@@ -569,30 +567,30 @@ let rec print_dependencies str local global dep =
 (* --------------------------------------------------------------------- *)
 (* #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
@@ -600,23 +598,23 @@ 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.Weird _ -> None
-        | _ -> 
-            if inifdef 
+        | _ ->
+            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)
@@ -626,36 +624,32 @@ let rec update_include_rel_pos cs =
   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;
 
@@ -665,7 +659,7 @@ type toplevel_c_info = {
 }
 
 type toplevel_cocci_info_script_rule = {
-  scr_ast_rule: string * (string * (string * string)) list * string;
+  scr_ast_rule: string * (string * Ast_cocci.meta_name) list * string;
   language: string;
   scr_dependencies: Ast_cocci.dependency;
   scr_ruleid: int;
@@ -681,7 +675,7 @@ type toplevel_cocci_info_cocci_rule = {
   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;
@@ -695,7 +689,7 @@ type toplevel_cocci_info_cocci_rule = {
   was_matched: bool ref;
 }
 
-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
@@ -703,8 +697,8 @@ type toplevel_cocci_info =
 
 type cocci_info = toplevel_cocci_info list * string list list (* tokens *)
 
-type kind_file = Header | Source 
-type file_info = { 
+type kind_file = Header | Source
+type file_info = {
   fname : string;
   full_fname : string;
   was_modified_once: bool ref;
@@ -713,25 +707,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 ->
@@ -749,6 +743,27 @@ 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 rulenb lang code =
+  let mv = [] in
+  let deps = Ast_cocci.NoDep in
+    {
+      scr_ast_rule = (lang, mv, code);
+      language = lang;
+      scr_dependencies = deps;
+      scr_ruleid = rulenb;
+      script_code = (if lang = "python" then python_code else "") ^code
+    }
 
 (* --------------------------------------------------------------------- *)
 let prepare_cocci ctls free_var_lists negated_pos_lists
@@ -759,10 +774,10 @@ let prepare_cocci ctls free_var_lists negated_pos_lists
                                  free_var_lists)
                   negated_pos_lists) ua) fua) fuas) positions_list)
   in
-  gathered +> List.map 
+  gathered +> List.map
     (fun (((((((((ctl_toplevel_list,metavars),ast),free_var_list),
-            negated_pos_list),ua),fua),fuas),positions_list),rulenb) -> 
-      
+            negated_pos_list),ua),fua),fuas),positions_list),rulenb) ->
+
       let is_script_rule r =
         match r with
          Ast_cocci.ScriptRule _
@@ -774,7 +789,7 @@ let prepare_cocci ctls free_var_lists negated_pos_lists
 
       match ast with
         Ast_cocci.ScriptRule (lang,deps,mv,code) ->
-          let r = 
+          let r =
           {
             scr_ast_rule = (lang, mv, code);
             language = lang;
@@ -784,17 +799,8 @@ let prepare_cocci ctls free_var_lists negated_pos_lists
           }
           in ScriptRuleCocciInfo r
       | Ast_cocci.InitialScriptRule (lang,code) ->
-         let mv = [] in
-         let deps = Ast_cocci.NoDep in
-          let r =
-          {
-            scr_ast_rule = (lang, mv, code);
-            language = lang;
-            scr_dependencies = deps;
-            scr_ruleid = rulenb;
-            script_code = code;
-          }
-          in InitialScriptRuleCocciInfo r
+         let r = make_init rulenb lang code in
+           InitialScriptRuleCocciInfo r
       | Ast_cocci.FinalScriptRule (lang,code) ->
          let mv = [] in
          let deps = Ast_cocci.NoDep in
@@ -831,27 +837,27 @@ let prepare_cocci ctls free_var_lists negated_pos_lists
 
 (* --------------------------------------------------------------------- *)
 
-let build_info_program cprogram env = 
-  
-  let (cs, parseinfos) = 
+let build_info_program cprogram env =
+
+  let (cs, parseinfos) =
     Common.unzip cprogram in
 
-  let alltoks = 
+  let alltoks =
     parseinfos +> List.map (fun (s,toks) -> toks) +> List.flatten in
 
   (* I use cs' but really annotate_xxx work by doing side effects on cs *)
-  let cs' = 
+  let cs' =
     Comment_annotater_c.annotate_program alltoks cs in
-  let cs_with_envs = 
+  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 = 
+    let flow =
       ast_to_flow_with_error_messages c +>
-      Common.map_option (fun flow -> 
+      Common.map_option (fun flow ->
         let flow = Ast_to_flow.annotate_loop_nodes flow in
 
         (* remove the fake nodes for julia *)
@@ -872,7 +878,7 @@ let build_info_program cprogram env =
       flow = flow;
 
       contain_loop = contain_loop flow;
-  
+
       env_typing_before = enva;
       env_typing_after = envb;
 
@@ -883,19 +889,19 @@ let build_info_program cprogram env =
 
 
 (* 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
       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] 
+      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.
@@ -907,11 +913,11 @@ let rebuild_info_program cs file isexp =
 
 
 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 }
@@ -923,12 +929,12 @@ let rebuild_info_c_and_headers ccs isexp =
 
 
 
-let prepare_c files choose_includes : 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) choose_includes in
 
   (* todo?: may not be good to first have all the headers and then all the c *)
-  let all = 
+  let all =
     (includes +> List.map (fun hpath -> Right hpath))
     ++
     ((zip files cprograms) +> List.map (fun (file, asts) -> Left (file, asts)))
@@ -936,23 +942,23 @@ let prepare_c files choose_includes : file_info list =
 
   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 
+  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 
+        else
           let h_cs = cprogram_of_file_cached hpath in
           let info_h_cs = build_info_program h_cs !env in
-          env := 
+          env :=
             if null info_h_cs
             then !env
             else last_env_toplevel_c_info info_h_cs
           ;
-          Some { 
+          Some {
             fname = Common.basename hpath;
             full_fname = hpath;
             asts = info_h_cs;
@@ -960,12 +966,12 @@ let prepare_c files choose_includes : file_info list =
             fpath = hpath;
             fkind = Header;
           }
-    | Left (file, cprogram) -> 
+    | Left (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 { 
+        Some {
           fname = Common.basename file;
           full_fname = file;
           asts = cs;
@@ -973,9 +979,9 @@ let prepare_c files choose_includes : file_info list =
           fpath = file;
           fkind = Source;
         }
-  ) 
+  )
   in
-  ccs        
+  ccs
 
 
 (*****************************************************************************)
@@ -983,31 +989,31 @@ let prepare_c files choose_includes : file_info list =
 (*****************************************************************************)
 
 (* 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
@@ -1019,7 +1025,7 @@ let prepare_c files choose_includes : 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
@@ -1067,13 +1073,16 @@ let apply_python_rule r cache newes e rules_that_have_matched
   else
     begin
       let (_, mv, _) = r.scr_ast_rule in
-      let not_bound x = not (Pycocci.contains_binding e x) 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 (Pycocci.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
@@ -1094,12 +1103,9 @@ let apply_python_rule r cache newes e rules_that_have_matched
                  !rules_that_have_ever_matched
                  r.scr_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
+               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
                relevant_bindings :: cache
              end in
          if !Pycocci.inc_match
@@ -1116,7 +1122,7 @@ let apply_python_rule r cache newes e rules_that_have_matched
 
 let rec apply_cocci_rule r rules_that_have_ever_matched es
     (ccs:file_info list ref) =
-  Common.profile_code r.rulename (fun () -> 
+  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;
 
@@ -1164,8 +1170,8 @@ let rec apply_cocci_rule r rules_that_have_ever_matched es
                         .c and .h *)
                        List.rev
                          (concat_headers_and_c !ccs +>
-                          List.fold_left (fun children_e (c,f) -> 
-                            if c.flow <> None 
+                          List.fold_left (fun children_e (c,f) ->
+                            if c.flow <> None
                             then
                              (* does also some side effects on c and r *)
                               let processed =
@@ -1173,10 +1179,10 @@ let rec apply_cocci_rule r rules_that_have_ever_matched es
                                   relevant_bindings c f in
                               match processed with
                               | None -> children_e
-                              | Some newbindings -> 
+                              | Some newbindings ->
                                   newbindings +>
                                   List.fold_left
-                                    (fun children_e newbinding -> 
+                                    (fun children_e newbinding ->
                                       if List.mem newbinding children_e
                                       then children_e
                                       else newbinding :: children_e)
@@ -1330,46 +1336,45 @@ 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.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" 
+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 () -> 
+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 () -> 
+  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 
+  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;    
+    List.iter (show_or_not_binding "out") newbindings;
 
     r.was_matched := true;
 
     if not (null trans_info)
     then begin
       c.was_modified := true;
-      try 
+      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
@@ -1384,9 +1389,9 @@ and process_a_ctl_a_env_a_toplevel2 r e c f =
     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" 
+
+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)
 
 
@@ -1397,16 +1402,16 @@ let rec bigloop2 rs (ccs: file_info list) =
   let rules_that_have_ever_matched = ref [] in
 
   (* looping over the rules *)
-  rs +> List.iter (fun r -> 
+  rs +> List.iter (fun r ->
     match r with
       InitialScriptRuleCocciInfo r | FinalScriptRuleCocciInfo r -> ()
-    | ScriptRuleCocciInfo r -> 
+    | 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 () -> 
+
+          adjust_pp_with_indent (fun () ->
             Format.force_newline();
             let (l,mv,code) = r.scr_ast_rule in
            let deps = r.scr_dependencies in
@@ -1425,8 +1430,8 @@ let rec bigloop2 rs (ccs: file_info list) =
                    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 
+                   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)
@@ -1444,7 +1449,7 @@ let rec bigloop2 rs (ccs: file_info list) =
   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 
+     * 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
@@ -1456,17 +1461,17 @@ let rec bigloop2 rs (ccs: file_info list) =
   end;
   !ccs (* return final C asts *)
 
-let bigloop a b = 
+let bigloop a b =
   Common.profile_code "bigloop" (fun () -> bigloop2 a b)
 
-let initial_final_bigloop2 ty rebuild r = 
+let initial_final_bigloop2 ty rebuild r =
   if !Flag_cocci.show_ctl_text then
     begin
       Common.pr_xxxxxxxxxxxxxxxxx ();
       pr (ty ^ ": " ^ r.language);
       Common.pr_xxxxxxxxxxxxxxxxx ();
 
-      adjust_pp_with_indent (fun () -> 
+      adjust_pp_with_indent (fun () ->
        Format.force_newline();
        Pretty_print_cocci.unparse(rebuild r.scr_ast_rule));
     end;
@@ -1481,7 +1486,7 @@ let initial_final_bigloop2 ty rebuild r =
       Printf.printf "Unknown language for initial/final script: %s\n"
        r.language
 
-let initial_final_bigloop a b c = 
+let initial_final_bigloop a b c =
   Common.profile_code "initial_final_bigloop"
     (fun () -> initial_final_bigloop2 a b c)
 
@@ -1493,9 +1498,9 @@ let pre_engine2 (coccifile, isofile) =
   show_or_not_cocci coccifile isofile;
   Pycocci.set_coccifile coccifile;
 
-  let isofile = 
+  let isofile =
     if not (Common.lfile_exists isofile)
-    then begin 
+    then begin
       pr2 ("warning: Can't find default iso file: " ^ isofile);
       None
     end
@@ -1503,7 +1508,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
 
@@ -1517,33 +1522,57 @@ let pre_engine2 (coccifile, isofile) =
     prepare_cocci ctls free_var_lists negated_pos_lists
       used_after_lists positions_lists metavars astcocci in
 
-  let _ =
+  let used_languages =
     List.fold_left
       (function languages ->
-       function
-           InitialScriptRuleCocciInfo(r) ->
-             (if List.mem r.language languages
-             then failwith ("double initializer found for "^r.language));
-             initial_final_bigloop "initial"
-               (function(x,_,y) -> Ast_cocci.InitialScriptRule(x,y))
-               r;
-             r.language::languages
-         | _ -> languages)
+        function
+            ScriptRuleCocciInfo(r) ->
+              if List.mem r.language languages then
+                languages
+              else
+                r.language::languages
+          | _ -> languages)
       [] cocci_infos in
 
+  let initialized_languages =
+    List.fold_left
+      (function languages ->
+        function
+            InitialScriptRuleCocciInfo(r) ->
+              (if List.mem r.language languages
+               then failwith ("double initializer found for "^r.language));
+              initial_final_bigloop "initial"
+                (function(x,_,y) -> Ast_cocci.InitialScriptRule(x,y))
+                r;
+              r.language::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 ->
+                initial_final_bigloop "initial"
+                  (function(x,_,y) -> Ast_cocci.InitialScriptRule(x,y))
+                  (make_init (-1) lgg "");
+             )
+      uninitialized_languages;
+
   (cocci_infos,toks)
 
-let pre_engine a = 
+let pre_engine a =
   Common.profile_code "pre_engine" (fun () -> pre_engine2 a)
 
-let full_engine2 (cocci_infos,toks) cfiles = 
+let full_engine2 (cocci_infos,toks) cfiles =
 
   show_or_not_cfiles  cfiles;
 
   (* optimisation allowing to launch coccinelle on all the drivers *)
   if !Flag_cocci.worth_trying_opt && not (worth_trying cfiles toks)
   then
-    begin 
+    begin
       pr2 ("No matches found for " ^ (Common.join " " (Common.union_all toks))
           ^ "\nSkipping:" ^ (Common.join " " cfiles));
       cfiles +> List.map (fun s -> s, None)
@@ -1572,7 +1601,7 @@ let full_engine2 (cocci_infos,toks) cfiles =
       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 -> 
+      c_infos' +> List.map (fun c_or_h ->
        if !(c_or_h.was_modified_once)
        then
          begin
@@ -1594,7 +1623,7 @@ let full_engine2 (cocci_infos,toks) cfiles =
        else (c_or_h.fpath, None))
     end
 
-let full_engine a b = 
+let full_engine a b =
   Common.profile_code "full_engine"
     (fun () -> let res = full_engine2 a b in (*Gc.print_stat stderr; *)res)
 
@@ -1614,37 +1643,37 @@ let post_engine2 (cocci_infos,_) =
       [] cocci_infos in
   ()
 
-let post_engine a = 
+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 *)
   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
     | [res] -> Some (file, res)
-    | res::xs -> 
-        match res with 
-        | None -> 
+    | 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
@@ -1653,9 +1682,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)