(* * Copyright 2012, INRIA * Julia Lawall, Gilles Muller * Copyright 2010-2011, INRIA, University of Copenhagen * Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix * This file is part of Coccinelle. * * Coccinelle is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, according to version 2 of the License. * * Coccinelle is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Coccinelle. If not, see . * * The authors reserve the right to distribute this or future versions of * Coccinelle under other licenses. *) # 0 "./command_line.ml" (* * Copyright 2012, INRIA * Julia Lawall, Gilles Muller * Copyright 2010-2011, INRIA, University of Copenhagen * Julia Lawall, Rene Rydhof Hansen, Gilles Muller, Nicolas Palix * Copyright 2005-2009, Ecole des Mines de Nantes, University of Copenhagen * Yoann Padioleau, Julia Lawall, Rene Rydhof Hansen, Henrik Stuart, Gilles Muller, Nicolas Palix * This file is part of Coccinelle. * * Coccinelle is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, according to version 2 of the License. * * Coccinelle is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Coccinelle. If not, see . * * The authors reserve the right to distribute this or future versions of * Coccinelle under other licenses. *) # 0 "./command_line.ml" (* ---------------------------------------------------------------------- *) (* useful functions *) let starts_with c s = if String.length s > 0 && String.get s 0 = c then Some (String.sub s 1 ((String.length s) - 1)) else None let ends_with c s = if String.length s > 0 && String.get s ((String.length s) - 1) = c then Some (String.sub s 0 ((String.length s) - 1)) else None let split_when fn l = let rec loop acc = function | [] -> raise Not_found | x::xs -> (match fn x with Some x -> List.rev acc, x, xs | None -> loop (x :: acc) xs) in loop [] l (* ---------------------------------------------------------------------- *) (* make a semantic patch from a string *) let find_metavariables tokens = let rec loop env = function [] -> (env,[]) | x :: xs -> (* single upper case letter is a metavariable *) let (x,xs,env) = (* Testing for uppercase and length is not enough as "+" is a single character identical in upper/lower case. *) (* The ":" delimiter could not be used two times 1) Str.split 2) split_when (ends_with ...) Otherwise split_when will raise a Not_found exception. *) match Str.bounded_split (Str.regexp ":") x 2 with [before;after] -> let (ty,endty,afterty) = split_when (ends_with ':') (after::xs) in let decl = Printf.sprintf "%s %s;\n" (String.concat "" (ty@[endty])) before in (try if decl = List.assoc before env then (before,afterty,env) else failwith (before^" already declared with another type") with Not_found -> let env = (before, decl) :: env in (before,afterty,env)) | _ -> if Str.string_match (Str.regexp "[A-Z]") x 0 then begin try let _ = Some(List.assoc x env) in (x,xs,env) with Not_found -> let env = (x,(Printf.sprintf "metavariable %s;\n" x)) :: env in (x,xs,env) end else (x,xs,env) in let (env,sp) = loop env xs in (env,x::sp) in loop [] tokens let find_when_dots tokens = let rec loop = function [] -> [] | "when !=" :: e :: rest -> "when != " :: e :: "\n" :: (loop rest) | "when ==" :: e :: rest -> "when == " :: e :: "\n" :: (loop rest) | "when" :: " " :: e :: rest -> "when" :: " " :: e :: "\n" :: (loop rest) | "..." :: "when" :: rest -> "\n" :: "..." :: (loop ("when" :: rest)) | "..." :: rest -> "\n" :: "..." :: "\n" :: (loop rest) | x::xs -> x::(loop xs) in loop tokens let add_stars tokens = let rec loop = function [] -> [] | "." :: "." :: "." :: rest -> "..." :: skip rest | "<" :: "." :: "." :: "." :: rest -> "<..." :: skip rest | "<" :: "+" :: "." :: "." :: "." :: rest -> "<+..." :: skip rest | "\n" :: rest -> "\n" :: loop rest | x :: xs -> ("* " ^ x) :: (skip xs) and skip = function [] -> [] | "\n" :: rest -> "\n" :: loop rest | x :: xs -> x :: skip xs in loop tokens let rec add_spaces = function [] -> [] | x :: "\n" :: rest -> x :: "\n" :: (add_spaces rest) | "\n" :: rest -> "\n" :: (add_spaces rest) | x :: rest -> x :: " " :: (add_spaces rest) let reparse tokens = let (env,code) = find_metavariables tokens in let env = String.concat "" (List.map snd env) in let code = find_when_dots code in let code = add_stars code in let code = String.concat "" code in let res = "@@\n"^env^"@@\n"^code in Printf.printf "%s\n\n" res; let out = Common.new_temp_file "sp" ".cocci" in let o = open_out out in Printf.fprintf o "%s\n" res; close_out o; out let tokenize first = let lexbuf = Lexing.from_string first in let rec loop b = let tok = Lexer_cli.token b in if not (tok = Lexer_cli.EOF) then let s = Lexer_cli.pretty_print tok in s :: loop b else [] in loop lexbuf (* ---------------------------------------------------------------------- *) (* entry point *) let command_line args = let info = try Some (Common.split_when (function x -> List.mem x ["-sp";"--sp"]) args) with Not_found -> None in match info with None -> args | Some(pre_args,sp,post_args) -> (match post_args with first::post_args -> pre_args @ "--sp-file" :: (reparse (tokenize first)) :: post_args | [] -> failwith "--sp needs an argument")