X-Git-Url: http://git.hcoop.net/bpt/coccinelle.git/blobdiff_plain/ae4735db5e7e9386036cf7b496ebdc994514dc53..6756e19d8b45188ff250016a494aafe46dec86c5:/main.ml diff --git a/main.ml b/main.ml index f5780a6..70cc10e 100644 --- a/main.ml +++ b/main.ml @@ -1,25 +1,3 @@ -(* - * 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. - * - * 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 . - * - * The authors reserve the right to distribute this or future versions of - * Coccinelle under other licenses. - *) - - open Common module FC = Flag_cocci @@ -35,10 +13,13 @@ module FC = Flag_cocci let cocci_file = ref "" let output_file = ref "" -let inplace_modif = ref false (* but keeps a .cocci_orig *) +let inplace_modif = ref false (* but keeps nothing *) +let backup_suffix = + ref (None : string option) (* suffix for backup if one is desired *) let outplace_modif = ref false (* generates a .cocci_res *) let preprocess = ref false (* run the C preprocessor before cocci *) let compat_mode = ref false +let ignore_unknown_opt = ref false (* somehow obsolete now *) let dir = ref false @@ -268,9 +249,11 @@ let short_options = [ "-o", Arg.Set_string output_file, " the output file"; - "-inplace", Arg.Set inplace_modif, + "-in_place", Arg.Set inplace_modif, " do the modification on the file directly"; - "-outplace", Arg.Set outplace_modif, + "-backup_suffix", Arg.String (function s -> backup_suffix := Some s), + " suffix to use when making a backup for inplace"; + "-out_place", Arg.Set outplace_modif, " store modifications in a .cocci_res file"; "-U", Arg.Int (fun n -> Flag_parsing_c.diff_lines := Some (i_to_s n)), @@ -285,18 +268,25 @@ let short_options = [ "-macro_file_builtins", Arg.Set_string Config.std_h, " (default=" ^ !Config.std_h ^ ")"; + "-recursive_includes", + Arg.Unit (function _ -> FC.include_options := FC.I_REALLY_ALL_INCLUDES), + " causes all available include files, both those included in the C file(s) and those included in header files, to be used"; "-all_includes", Arg.Unit (function _ -> FC.include_options := FC.I_ALL_INCLUDES), - " causes all available include files to be used"; + " causes all available include files included in the C file(s) to be used"; "-no_includes", Arg.Unit (function _ -> FC.include_options := FC.I_NO_INCLUDES), " causes not even local include files to be used"; "-local_includes", Arg.Unit (function _ -> FC.include_options := FC.I_NORMAL_INCLUDES), " causes local include files to be used"; + "-ignore_unknown_options", Arg.Set ignore_unknown_opt, + " For integration in a toolchain (must be set before the first unknown option)"; "-include_headers", Arg.Set include_headers, " process header files independently"; - "-I", Arg.String (function x -> FC.include_path := Some x), + "-I", Arg.String (fun x -> + FC.include_path:= x::!FC.include_path + ), " containing the header files (optional)"; "-preprocess", Arg.Set preprocess, @@ -311,7 +301,10 @@ let short_options = [ " works with -dir, use info generated by glimpseindex"; "-use_google", Arg.String (function s -> Flag.scanner := Flag.Google s), " find relevant files using google code search"; - "-patch", Arg.String (function s -> Flag.patch := Some s), + "-use_idutils", Arg.Unit (function s -> Flag.scanner := Flag.IdUtils), + " find relevant files using id-utils"; + "-patch", + Arg.String (function s -> Flag.patch := Some (Cocci.normalize_path s)), (" path name with respect to which a patch should be created\n"^ " \"\" for a file in the current directory"); "-kbuild_info", Arg.Set_string kbuild_info, @@ -328,7 +321,7 @@ let short_options = [ " guess what"; "-date", Arg.Unit (fun () -> - pr2 "version: $Date: 2010/01/26 06:01:55 $"; + pr2 "version: $Date: 2011/03/14 21:16:17 $"; raise (Common.UnixExit 0) ), " guess what"; @@ -479,6 +472,11 @@ let other_options = [ " disable limit on max depth of iso application"; "-track_iso", Arg.Set Flag.track_iso_usage, " gather information about isomorphism usage"; + "-disable_iso", + Arg.String + (fun s -> Flag_parsing_cocci.disabled_isos := + s :: !Flag_parsing_cocci.disabled_isos), + " disable a specific isomorphism"; "-profile_iso", Arg.Unit (function () -> @@ -560,6 +558,8 @@ let other_options = [ " spacing of + code follows the semantic patch"; "-D", Arg.String Flag.set_defined_virtual_rules, " indicate that a virtual rule should be considered to be matched"; + "-c++", Arg.Set Flag.c_plus_plus, + " make a small attempt to parse C++ files" ]; "misc options", @@ -638,17 +638,48 @@ let all_options = let arg_align2 xs = Arg.align xs +> List.rev +> Common.drop 2 +> List.rev +(* + Ignore unknown option + + This simplifies the integration of Coccinelle in toolchain. For + instance, spatch can then be used as a checker in the Linux build + system. + +*) +let check_include_path () = + let opt = Array.get Sys.argv !Arg.current in + let is_include_re = Str.regexp "-I\\(.*\\)" in + if Str.string_match is_include_re opt 0 then + let path = Str.matched_group 1 opt in + FC.include_path:= path::!FC.include_path + else () + +let rec arg_parse_no_fail l f msg = + try + check_include_path (); + Arg.parse_argv Sys.argv l f msg; + with + | Arg.Bad emsg -> + arg_parse_no_fail l f msg + | Arg.Help msg -> (* printf "%s" msg; exit 0; *) + 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 = (try Arg.parse_argv Sys.argv l f msg; with - | Arg.Bad msg -> (* eprintf "%s" msg; exit 2; *) - let xs = Common.lines msg in - (* take only head, it's where the error msg is *) - pr2 (List.hd xs); - !short_usage_func(); - raise (Common.UnixExit (2)) + | Arg.Bad emsg -> (* eprintf "%s" msg; exit 2; *) + if not !ignore_unknown_opt then + begin + let xs = Common.lines emsg in + (* take only head, it's where the error msg is *) + pr2 (List.hd xs); + !short_usage_func(); + raise (Common.UnixExit (2)) + end + else + arg_parse_no_fail l f msg; | Arg.Help msg -> (* printf "%s" msg; exit 0; *) raise Impossible (* -help is specified in speclist *) ) @@ -674,272 +705,319 @@ let _ = long_usage_func := long_usage (* Helpers *) (*****************************************************************************) -let adjust_stdin cfile k = - if !dir - then k() - else - let newin = - try - let (dir, base, ext) = Common.dbe_of_filename cfile in - let varfile = Common.filename_of_dbe (dir, base, "var") in - if ext =$= "c" && Common.lfile_exists varfile - then Some varfile - else None - with Invalid_argument("Filename.chop_extension") -> None - in - Common.redirect_stdin_opt newin k +(* for fresh identifier information *) +let adjust_stdin cfiles k = + match cfiles with + [] -> failwith "not possible" + | cfile::_ -> + let newin = + try + let (dir, base, ext) = Common.dbe_of_filename cfile in + let varfile = Common.filename_of_dbe (dir, base, "var") in + if ext =$= "c" && Common.lfile_exists varfile + then Some varfile + else None + with Invalid_argument("Filename.chop_extension") -> None in + Common.redirect_stdin_opt newin k let glimpse_filter (coccifile, isofile) dir = let (_metavars,astcocci,_free_var_lists,_negated_positions, - _used_after_lists,_positions_lists,_,query) = + _used_after_lists,_positions_lists,(_,query,_)) = + Cocci.sp_of_file coccifile (Some isofile) in + match query with + None -> pr2 "no inferred glimpse keywords"; None + | Some queries -> + let suffixes = if !include_headers then ["c";"h"] else ["c"] in + let rec loop = function + [] -> None (* error, eg due to pattern too big *) + | query::queries -> + Printf.fprintf stderr "%s\n" ("glimpse request = " ^ query); + let command = spf "glimpse -y -H %s -N -W -w '%s'" dir query in + let (glimpse_res,stat) = Common.cmd_to_list_and_status command in + match stat with + Unix.WEXITED(0) | Unix.WEXITED(1) -> + Printf.fprintf stderr "got files\n"; flush stderr; + Some + (glimpse_res +> + List.filter + (fun file -> List.mem (Common.filesuffix file) suffixes)) + | _ -> loop queries (* error, eg due to pattern too big *) in + loop queries + +let idutils_filter (coccifile, isofile) dir = + let (_metavars,astcocci,_free_var_lists,_negated_positions, + _used_after_lists,_positions_lists,(_,_,query)) = Cocci.sp_of_file coccifile (Some isofile) in match query with - None -> pr2 "no glimpse keyword inferred from snippet"; None - | Some [query] -> - (let suffixes = if !include_headers then ["c";"h"] else ["c"] in - pr2 ("glimpse request = " ^ query); - let command = spf "glimpse -y -H %s -N -W -w '%s'" dir query in - let (glimpse_res,stat) = Common.cmd_to_list_and_status command in - match stat with - Unix.WEXITED(0) | Unix.WEXITED(1) -> - Some - (glimpse_res +> - List.filter - (fun file -> List.mem (Common.filesuffix file) suffixes)) - | _ -> None (* error, eg due to pattern too big *)) - | _ -> failwith "not possible" + None -> pr2 "no inferred idutils keywords"; None + | Some query -> + let suffixes = if !include_headers then ["c";"h"] else ["c"] in + let files = Id_utils.interpret dir query in + Printf.fprintf stderr "got files\n"; flush stderr; + Some + (files +> + List.filter (fun file -> List.mem (Common.filesuffix file) suffixes)) (*****************************************************************************) (* Main action *) (*****************************************************************************) -let main_action xs = - match xs with - | x::xs -> +let get_files path = + let ch = + Common.cmd_to_list (* same as "true, "", _" case *) + (if !include_headers + (* FIXME : Could we remove xs ? + -use_glimpse requires a singleton. + This is checked some lines before. + then ("find "^(join " " (x::xs))^" -name \"*.[ch]\"") + else ("find "^(join " " (x::xs))^" -name \"*.c\"") + *) + then ("find "^ path ^" -name \"*.[ch]\"") + else ("find "^ path ^" -name \"*.c\"")) in + let cpp = + if !Flag.c_plus_plus + then Common.cmd_to_list ("find "^ path ^" -name \"*.cpp\"") + else [] in + cpp @ ch +let main_action xs = + Iteration.base_file_list := xs; + let rec toploop = function + [] -> raise Impossible + | x::xs -> (* a more general solution would be to use * Common.files_of_dir_or_files (x::xs) * as some elements in xs may also be directories, or individual * files. *) - if Common.is_directory x - then dir := true; - - adjust_stdin x (fun () -> - if !cocci_file =$= "" - then failwith "I need a cocci file, use -sp_file "; - - if !dir && !Flag.patch =*= None - then - (match xs with - | [] -> Flag.patch := Some x - | _ -> - pr2 - ("warning: patch output can only be created when only one\n"^ - "directory is specified or when the -patch flag is used") - ); - - let infiles = - Common.profile_code "Main.infiles computation" (fun () -> - match !dir, !kbuild_info, !Flag.scanner = Flag.Glimpse with + dir := (Common.is_directory x); + + if !cocci_file =$= "" + then failwith "I need a cocci file, use -sp_file "; + + if !dir && !Flag.patch =*= None + then + (match xs with + | [] -> Flag.patch := Some (Cocci.normalize_path x) + | _ -> + pr2 + ("warning: patch output can only be created when only one\n"^ + "directory is specified or when the -patch flag is used") + ); + Flag.dir := x; + + let infiles = + Common.profile_code "Main.infiles computation" (fun () -> + match !dir, !kbuild_info, !Flag.scanner with (* glimpse *) - | false, _, true -> - failwith "-use_glimpse works only with -dir" - | true, s, true when s <> "" -> - failwith "-use_glimpse does not work with -kbuild" - | true, "", true -> - if not (null xs) - then failwith "-use_glimpse can accept only one dir"; - - Flag.dir := x; - let files = - match glimpse_filter (!cocci_file, !Config.std_iso) x with - None -> - Common.cmd_to_list (* same as "true, "", _" case *) - (if !include_headers - (* FIXME : Could we remove xs ? - -use_glimpse requires a singleton. - This is checked some lines before. - then ("find "^(join " " (x::xs))^" -name \"*.[ch]\"") - else ("find "^(join " " (x::xs))^" -name \"*.c\"")) - *) - then ("find "^ x ^" -name \"*.[ch]\"") - else ("find "^ x ^" -name \"*.c\"")) - | Some files -> files in - files +> List.map (fun x -> [x]) + | false, _, (Flag.Glimpse|Flag.IdUtils) -> [x::xs] + | true, s, (Flag.Glimpse|Flag.IdUtils) when s <> "" -> + failwith + "-use_glimpse or -id_utils does not work with -kbuild" + | true, "", Flag.Glimpse -> + (if not (null xs) + then failwith "-use_glimpse can accept only one dir"); + + let files = + match glimpse_filter (!cocci_file, !Config.std_iso) x with + None -> get_files x + | Some files -> files in + files +> List.map (fun x -> [x]) + | true, "", Flag.IdUtils -> + (if not (null xs) + then failwith "-id_utils can accept only one dir"); + + let files = + match idutils_filter (!cocci_file, !Config.std_iso) x with + None -> get_files x + | Some files -> files in + files +> List.map (fun x -> [x]) (* normal *) - | false, _, _ -> [x::xs] - | true, "", _ -> - Common.cmd_to_list - (if !include_headers - then ("find "^(join " " (x::xs))^" -name \"*.[ch]\"") - else ("find "^(join " " (x::xs))^" -name \"*.c\"")) - +> List.map (fun x -> [x]) - + | false, _, _ -> [x::xs] + | true, "", _ -> + get_files (join " " (x::xs)) +> List.map (fun x -> [x]) + (* kbuild *) - | true, kbuild_info_file,_ -> - let dirs = - Common.cmd_to_list ("find "^(join " " (x::xs))^" -type d") - in - let info = Kbuild.parse_kbuild_info kbuild_info_file in - let groups = Kbuild.files_in_dirs dirs info in - - groups +> List.map (function Kbuild.Group xs -> xs) - ) - in - - let infiles = - match (!distrib_index,!distrib_max) with - (None,None) -> infiles - | (Some index,Some max) -> - (if index >= max - then - failwith "index starts at 0, and so must be less than max"); - if !mod_distrib - then - let rec loop ct = function - [] -> [] - | x::xs -> - if (ct mod max) =|= index - then x::(loop (ct+1) xs) - else loop (ct+1) xs in - loop 0 infiles - else - begin - let all_files = List.length infiles in - let regions = (all_files + (max - 1)) / max in - let this_min = index * regions in - let this_max = (index+1) * regions in + | true, kbuild_info_file,_ -> + let dirs = + Common.cmd_to_list ("find "^(join " " (x::xs))^" -type d") + in + let info = Kbuild.parse_kbuild_info kbuild_info_file in + let groups = Kbuild.files_in_dirs dirs info in + + groups +> List.map (function Kbuild.Group xs -> xs) + ) + in + + let infiles = + match (!distrib_index,!distrib_max) with + (None,None) -> infiles + | (Some index,Some max) -> + (if index >= max + then + failwith "index starts at 0, and so must be less than max"); + if !mod_distrib + then let rec loop ct = function - [] -> [] + [] -> [] | x::xs -> - if this_min <= ct && ct < this_max + if (ct mod max) =|= index then x::(loop (ct+1) xs) else loop (ct+1) xs in loop 0 infiles - end - | _ -> failwith "inconsistent distribution information" in - - let outfiles = - Common.profile_code "Main.outfiles computation" (fun () -> - let cocci_infos = - Cocci.pre_engine (!cocci_file, !Config.std_iso) in - let res = - infiles +> List.map (fun cfiles -> - pr2 ("HANDLING: " ^ (join " " cfiles)); - Common.timeout_function_opt !FC.timeout (fun () -> - Common.report_if_take_time 10 (join " " cfiles) (fun () -> - (*let s = profile_diagnostic() in*) - (* Unix.sleep 1; *) - try - let optfile = - if !output_file <> "" && !compat_mode then - Some !output_file - else - None - in - Common.redirect_stdout_opt optfile (fun () -> + else + begin + let all_files = List.length infiles in + let regions = (all_files + (max - 1)) / max in + let this_min = index * regions in + let this_max = (index+1) * regions in + let rec loop ct = function + [] -> [] + | x::xs -> + if this_min <= ct && ct < this_max + then x::(loop (ct+1) xs) + else loop (ct+1) xs in + loop 0 infiles + end + | _ -> failwith "inconsistent distribution information" in + + let (cocci_infos,outfiles) = + Common.profile_code "Main.outfiles computation" (fun () -> + let cocci_infos = + Cocci.pre_engine (!cocci_file, !Config.std_iso) in + let res = + infiles +> List.map (fun cfiles -> + pr2 ("HANDLING: " ^ (join " " cfiles)); + Common.timeout_function_opt !FC.timeout (fun () -> + Common.report_if_take_time 10 (join " " cfiles) (fun () -> + try + let optfile = + if !output_file <> "" && !compat_mode then + Some !output_file + else + None + in + adjust_stdin cfiles (fun () -> + Common.redirect_stdout_opt optfile (fun () -> (* this is the main call *) - Cocci.full_engine cocci_infos cfiles - ) - with + Cocci.full_engine cocci_infos cfiles + )) + with | Common.UnixExit x -> raise (Common.UnixExit x) + | Pycocci.Pycocciexception -> + raise Pycocci.Pycocciexception | e -> - (*pr2 "previous"; - pr2 s; - pr2 "new"; - pr2(profile_diagnostic());*) if !dir then begin pr2 ("EXN:" ^ Printexc.to_string e); [] (* *) end else raise e))) in - Cocci.post_engine cocci_infos; - res - ) +> List.concat - in - - 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 - Common.command2 ("cp "^infile^" "^infile^".cocci_orig"); - Common.command2 ("cp "^outfile^" "^infile); - end; - - if !outplace_modif - then Common.command2 ("cp "^outfile^" "^infile^".cocci_res"); - + (cocci_infos,res)) in + let outfiles = List.concat outfiles in + (match Iteration.get_pending_instance() with + None -> (x,xs,cocci_infos,outfiles) + | Some (files,virt_rules,virt_ids) -> + if outfiles = [] or outfiles = [] or not !FC.show_diff + then + begin + Flag.defined_virtual_rules := virt_rules; + Flag.defined_virtual_env := virt_ids; + Common.erase_temp_files(); + Common.clear_pr2_once(); + toploop files + end + else + begin + Common.pr2 + "Transformation not compatible with iteration. Aborting."; + (x,xs,cocci_infos,outfiles) + end) in + let (x,xs,cocci_infos,outfiles) = toploop xs in + + 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"); + (* 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) - * anymore in /tmp. - *) + * a symlink, so simpler to not produce any regular file + * (files created by Common.new_temp_file are still ok) + * anymore in /tmp. + *) (* - if !output_file =$= "" - then begin - let tmpfile = "/tmp/"^Common.basename infile in - pr2 (spf "One file modified. Result is here: %s" tmpfile); - Common.command2 ("cp "^outfile^" "^tmpfile); + if !output_file =$= "" + then begin + let tmpfile = "/tmp/"^Common.basename infile in + pr2 (spf "One file modified. Result is here: %s" tmpfile); + Common.command2 ("cp "^outfile^" "^tmpfile); 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 is multiple " ^ - "modified files"); - ); - if !compare_with_expected - then Testing.compare_with_expected outfiles)) - - | [] -> raise Impossible - - + 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) + + (*****************************************************************************) (* The coccinelle main entry point *) (*****************************************************************************) let main () = begin let arglist = Array.to_list Sys.argv in - + if not (null (Common.inter_set arglist - ["-cocci_file";"-sp_file";"-sp";"-test";"-testall"; + ["-cocci_file";"-sp_file";"-sp";"-test";"-testall"; "-test_okfailed";"-test_regression_okfailed"])) then run_profile quiet_profile; - + let args = ref [] in - + (* 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; - + (* julia hack so that one can override directories specified on - * the command line. *) + * the command line. *) (if !dir then let chosen_dir = - if List.length !args > 1 - then - begin - let chosen = List.hd !args in - pr2 ("ignoring all but the last specified directory: "^chosen); - args := [chosen]; - chosen - end - else List.hd !args in - if !FC.include_path =*= None - then FC.include_path := Some (Filename.concat chosen_dir "include")); + if List.length !args > 1 + then + begin + let chosen = List.hd !args in + Flag.dir := chosen; + pr2 ("ignoring all but the last specified directory: "^chosen); + args := [chosen]; + chosen + end + else List.hd !args in + if !FC.include_path =*= [] + then FC.include_path := [Filename.concat chosen_dir "include"]); args := List.rev !args; @@ -970,11 +1048,29 @@ let main () = (* The test framework. Works with tests/ or .ok and .failed *) (* --------------------------------------------------------- *) | [x] when !test_mode -> - FC.include_path := Some "tests/include"; - Testing.testone x !compare_with_expected + begin + let prefix = "tests/" in + let testfile = x ^ ".cocci" in + if Sys.file_exists (prefix ^ testfile) then + begin + (if !FC.include_path = [] + then FC.include_path := [prefix^"include"]); + Testing.testone prefix x !compare_with_expected + end + else + if Sys.file_exists testfile then + begin + (if !FC.include_path = [] + then FC.include_path := ["include"]); + Testing.testone "" x !compare_with_expected + end + else + pr2 (spf "ERROR: File %s does not exist" testfile) + end | [] when !test_all -> - FC.include_path := Some "tests/include"; + (if !FC.include_path = [] + then FC.include_path := ["tests/include"]); if !expected_score_file <> "" then Testing.testall ~expected_score_file:!expected_score_file () else Testing.testall () @@ -982,11 +1078,11 @@ let main () = | [] when !test_regression_okfailed -> Testing.test_regression_okfailed () - | x::xs when !test_okfailed -> + | ((x::xs) as cfiles) when !test_okfailed -> (* do its own timeout on FC.timeout internally *) FC.relax_include_path := true; - adjust_stdin x (fun () -> - Testing.test_okfailed !cocci_file (x::xs) + adjust_stdin cfiles (fun () -> + Testing.test_okfailed !cocci_file cfiles ) (* --------------------------------------------------------- *) @@ -997,7 +1093,7 @@ let main () = Common.do_action !action xs all_actions | [file] when !action =$= "-parse_cocci" -> - Testing.test_parse_cocci file + Testing.test_parse_cocci file (* I think this is used by some scripts in some Makefile for our * big-tests. So dont remove. @@ -1033,8 +1129,13 @@ let main_with_better_error_report () = try main () with - | Unix.Unix_error (_, "stat", filename) -> - pr2 (spf "ERROR: File %s does not exist" filename); + | Unix.Unix_error (e, "stat", filename) -> + pr2 + (spf "ERROR: File %s does not exist: %s" + filename (Unix.error_message e)); + raise (UnixExit (-1)) + | Parse_cocci.Bad_virt s -> + Common.pr2 (Printf.sprintf "virtual rule %s not supported" s); raise (UnixExit (-1)) (*****************************************************************************)