Release of coccinelle 1.0.0-rc9
[bpt/coccinelle.git] / main.ml
diff --git a/main.ml b/main.ml
index 70cc10e..2dca9d2 100644 (file)
--- a/main.ml
+++ b/main.ml
@@ -1,3 +1,27 @@
+(*
+ * Copyright 2010, 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.
+ *)
+
+
 open Common
 module FC = Flag_cocci
 
@@ -47,7 +71,6 @@ let distrib_index = ref (None : int option)
 let distrib_max   = ref (None : int option)
 let mod_distrib   = ref false
 
-
 (*****************************************************************************)
 (* Profiles *)
 (*****************************************************************************)
@@ -156,6 +179,7 @@ let debug_profile = (
     FC.show_binding_in_out;
     FC.show_dependencies;
 
+    Flag_parsing_cocci.keep_ml_script;
     Flag_parsing_cocci.show_iso_failures;
 
     FC.verbose_cocci;
@@ -315,13 +339,17 @@ let short_options = [
 
   "-version",   Arg.Unit (fun () ->
     let withpython = if Pycocci.python_support then "with" else "without" in
-    pr2 (spf "spatch version %s %s Python support" Config.version withpython);
+    let whichregexp =
+      if !Regexp.pcre_support then "with PCRE support"
+      else "with Str regexp support "
+    in
+    pr2 (spf "spatch version %s %s Python support and %s" Config.version withpython whichregexp);
     exit 0;
   ),
     "  guess what";
 
   "-date",   Arg.Unit (fun () ->
-    pr2 "version: $Date: 2011/03/14 21:16:17 $";
+    pr2 "version: $Date$";
     raise (Common.UnixExit 0)
     ),
   "   guess what";
@@ -368,6 +396,8 @@ let other_options = [
   [
     "-show_diff"           , Arg.Set FC.show_diff, " ";
     "-no_show_diff"           , Arg.Clear FC.show_diff, " ";
+    "-force_diff"           , Arg.Set FC.force_diff,
+       "show diff even if only spacing changes";
     "-show_flow"              , Arg.Set FC.show_flow,        " ";
     (* works in conjunction with -show_ctl_text *)
     "-ctl_inline_let",
@@ -517,6 +547,11 @@ let other_options = [
     "   drop all back edges derived from looping constructs - unsafe";
     "-no_gotos",          Arg.Set Flag_parsing_c.no_gotos,
     "   drop all jumps derived from gotos - unsafe";
+    "-no_saved_typedefs", Arg.Clear Flag_cocci.use_saved_typedefs,
+    "   drop all inferred typedefs from one parse of some code to the next";
+
+    "-ocaml_regexps", Arg.Clear Regexp.pcre_support,
+    "   use OCaml Str regular expressions for constraints";
 
     "-l1",                Arg.Clear Flag_parsing_c.label_strategy_2, " ";
     "-ifdef_to_if",       Arg.Set FC.ifdef_to_if,
@@ -590,7 +625,16 @@ let other_options = [
   [
     "-use_cache", Arg.Set Flag_parsing_c.use_cache,
     "   use .ast_raw pre-parsed cached C file";
+    "-cache_prefix",
+    Arg.String (function s ->
+      Flag_parsing_c.cache_prefix := Some s;
+      Flag_parsing_c.use_cache := true),
+    "   directory of cached ASTs, sets -use_cache";
     (* could use Flag_parsing_c.options_pad instead *)
+    "-cache_limit",
+      Arg.Int (function n ->
+       Flag_parsing_c.cache_limit := Some n),
+    "   maximum number of cached ASTs, sets -use_cache";
   ];
 
 
@@ -665,9 +709,9 @@ let rec arg_parse_no_fail l f msg =
        raise Impossible  (* -help is specified in speclist *)
 
 (* copy paste of Arg.parse. Don't want the default -help msg *)
-let arg_parse2 l f msg =
+let arg_parse2 l f msg argv =
   (try
-    Arg.parse_argv Sys.argv l f msg;
+    Arg.parse_argv argv l f msg;
   with
   | Arg.Bad emsg -> (* eprintf "%s" msg; exit 2; *)
       if not !ignore_unknown_opt then
@@ -780,7 +824,13 @@ let get_files path =
     else [] in
   cpp @ ch
 
-let main_action xs =
+let rec main_action xs =
+  let (cocci_files,xs) =
+    List.partition (function nm -> Filename.check_suffix nm ".cocci") xs in
+  (match (!cocci_file,cocci_files) with
+    "",[fl] -> cocci_file := fl
+  | _,[] -> ()
+  | _ -> failwith "only one .cocci file allowed");
   Iteration.base_file_list := xs;
   let rec toploop = function
       [] -> raise Impossible
@@ -848,7 +898,14 @@ let main_action xs =
                  groups +> List.map (function Kbuild.Group xs -> xs)
                    )
           in
-         
+
+         (* make cache unique in parallel case *)
+         (match (!distrib_index,!Flag_parsing_c.cache_prefix) with
+           (Some index,Some str) ->
+             Flag_parsing_c.cache_prefix :=
+               Some (Printf.sprintf "%s/d%d" str index)
+         | _ -> ());
+
          let infiles =
            match (!distrib_index,!distrib_max) with
              (None,None) -> infiles
@@ -916,21 +973,26 @@ let main_action xs =
              (cocci_infos,res)) in
          let outfiles = List.concat outfiles in
          (match Iteration.get_pending_instance() with
-           None -> (x,xs,cocci_infos,outfiles)
+           None ->
+             (x,xs,cocci_infos,outfiles)
          | Some (files,virt_rules,virt_ids) ->
              if outfiles = [] or outfiles = [] or not !FC.show_diff
+                 or !inplace_modif
              then
                begin
+                 (if !inplace_modif then generate_outfiles outfiles x xs);
                  Flag.defined_virtual_rules := virt_rules;
                  Flag.defined_virtual_env := virt_ids;
                  Common.erase_temp_files();
                  Common.clear_pr2_once();
+                 distrib_index := None;
+                 distrib_max := None;
                  toploop files
                end
              else
                begin
                  Common.pr2
-                   "Transformation not compatible with iteration. Aborting.";
+                   "Out of place transformation not compatible with iteration. Aborting.\n consider using -no_show_diff or -in_place";
                  (x,xs,cocci_infos,outfiles)
                end) in
       let (x,xs,cocci_infos,outfiles) = toploop xs in
@@ -938,21 +1000,26 @@ let main_action xs =
       Cocci.post_engine cocci_infos;
       Common.profile_code "Main.result analysis" (fun () ->
        Ctlcocci_integration.print_bench();
-        let outfiles = Cocci.check_duplicate_modif outfiles in
-        outfiles +> List.iter (fun (infile, outopt) ->
-         outopt +> Common.do_option (fun outfile ->
-           if !inplace_modif
-           then begin
-             (match !backup_suffix with
-               Some backup_suffix ->
-                 Common.command2 ("cp "^infile^" "^infile^backup_suffix)
-             | None -> ());
-              Common.command2 ("cp "^outfile^" "^infile);
-           end;
-           
-           if !outplace_modif
-           then Common.command2 ("cp "^outfile^" "^infile^".cocci_res");
-           
+       generate_outfiles outfiles x xs;
+        if !compare_with_expected
+        then Testing.compare_with_expected outfiles)
+
+and generate_outfiles outfiles x (* front file *) xs (* other files *) =
+  let outfiles = Cocci.check_duplicate_modif outfiles in
+  outfiles +> List.iter (fun (infile, outopt) ->
+    outopt +> Common.do_option (fun outfile ->
+      if !inplace_modif
+      then begin
+       (match !backup_suffix with
+         Some backup_suffix ->
+           Common.command2 ("cp "^infile^" "^infile^backup_suffix)
+       | None -> ());
+        Common.command2 ("cp "^outfile^" "^infile);
+      end;
+      
+      if !outplace_modif
+      then Common.command2 ("cp "^outfile^" "^infile^".cocci_res")
+      
              (* potential source of security pb if the /tmp/ file is
                 * a symlink, so simpler to not produce any regular file
                 * (files created by Common.new_temp_file are still ok)
@@ -967,27 +1034,24 @@ let main_action xs =
                 end
               *)
            ));
-        if !output_file <> "" && not !compat_mode then
-         (match outfiles with
-         | [infile, Some outfile] when infile =$= x && null xs ->
-              Common.command2 ("cp " ^outfile^ " " ^ !output_file);
-         | [infile, None] when infile =$= x && null xs ->
-              Common.command2 ("cp " ^infile^ " " ^ !output_file);
-         | _ ->
-              failwith
-                ("-o can not be applied because there are multiple " ^
-                 "modified files");
-             );
-        if !compare_with_expected
-        then Testing.compare_with_expected outfiles)
-       
-       
+  if !output_file <> "" && not !compat_mode then
+    (match outfiles with
+    | [infile, Some outfile] when infile =$= x && null xs ->
+        Common.command2 ("cp " ^outfile^ " " ^ !output_file)
+    | [infile, None] when infile =$= x && null xs ->
+        Common.command2 ("cp " ^infile^ " " ^ !output_file)
+    | _ ->
+        failwith
+          ("-o can not be applied because there are multiple " ^
+           "modified files"))
+
 (*****************************************************************************)
 (* The coccinelle main entry point *)
 (*****************************************************************************)
 let main () =
   begin
     let arglist = Array.to_list Sys.argv in
+    let arglist = Command_line.command_line arglist in
     
     if not (null (Common.inter_set arglist
                    ["-cocci_file";"-sp_file";"-sp";"-test";"-testall";
@@ -999,7 +1063,8 @@ let main () =
     (* Gc.set {(Gc.get ()) with Gc.stack_limit = 1024 * 1024};*)
     
     (* this call can set up many global flag variables via the cmd line *)
-    arg_parse2 (Arg.align all_options) (fun x -> args := x::!args) usage_msg;
+    arg_parse2 (Arg.align all_options) (fun x -> args := x::!args) usage_msg
+      (Array.of_list arglist);
     
     (* julia hack so that one can override directories specified on
        * the command line. *)