diff options
author | Xavier Leroy <xavier.leroy@college-de-france.fr> | 2020-05-04 11:11:27 +0200 |
---|---|---|
committer | Xavier Leroy <xavierleroy@users.noreply.github.com> | 2020-05-05 14:03:52 +0200 |
commit | 4a676623badb718da4055b7f26ee05f5097f4e7b (patch) | |
tree | 63ae1519f97355b928ded3eb1092d5bee83a6f42 /lib/Commandline.ml | |
parent | b46c0c01379da17dd96fc0cb8f0458100b7b1e5e (diff) | |
download | compcert-kvx-4a676623badb718da4055b7f26ee05f5097f4e7b.tar.gz compcert-kvx-4a676623badb718da4055b7f26ee05f5097f4e7b.zip |
Move Commandline to the lib/ directory
The Commandline module is reusable in other projects, and its license
(GPL) allows such reuse, so its natural place is in lib/ rather
than in driver/
Diffstat (limited to 'lib/Commandline.ml')
-rw-r--r-- | lib/Commandline.ml | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/lib/Commandline.ml b/lib/Commandline.ml new file mode 100644 index 00000000..672ed834 --- /dev/null +++ b/lib/Commandline.ml @@ -0,0 +1,141 @@ +(* *********************************************************************) +(* *) +(* The Compcert verified compiler *) +(* *) +(* Xavier Leroy, INRIA Paris-Rocquencourt *) +(* *) +(* Copyright Institut National de Recherche en Informatique et en *) +(* Automatique. All rights reserved. This file is distributed *) +(* under the terms of the GNU General Public License as published by *) +(* the Free Software Foundation, either version 2 of the License, or *) +(* (at your option) any later version. This file is also distributed *) +(* under the terms of the INRIA Non-Commercial License Agreement. *) +(* *) +(* *********************************************************************) + +(* Parsing of command-line flags and arguments *) + +open Printf + +type pattern = + | Exact of string + | Prefix of string + | Suffix of string + | Regexp of Str.regexp + +let _Regexp re = Regexp (Str.regexp re) + +type action = + | Set of bool ref + | Unset of bool ref + | Self of (string -> unit) + | String of (string -> unit) + | Integer of (int -> unit) + | Ignore + | Unit of (unit -> unit) + +exception CmdError of string + +let match_pattern text = function + | Exact s -> + text = s + | Prefix pref -> + let lpref = String.length pref and ltext = String.length text in + lpref < ltext && String.sub text 0 lpref = pref + (* strict prefix: no match if pref = text. See below. *) + | Suffix suff -> + let lsuff = String.length suff and ltext = String.length text in + lsuff < ltext && String.sub text (ltext - lsuff) lsuff = suff + (* strict suffix: no match if suff = text, so that e.g. ".c" + causes an error rather than being treated as a C source file. *) + | Regexp re -> + Str.string_match re text 0 + +let rec find_action text = function + | [] -> None + | (pat, act) :: rem -> + if match_pattern text pat then Some act else find_action text rem + +let parse_array spec argv first last = + (* Split the spec into Exact patterns (in a hashtable) and other patterns *) + let exact_cases = (Hashtbl.create 29 : (string, action) Hashtbl.t) in + let rec split_spec = function + | [] -> [] + | (Exact s, act) :: rem -> Hashtbl.add exact_cases s act; split_spec rem + | (pat, act) :: rem -> (pat, act) :: split_spec rem in + let inexact_cases = split_spec spec in + (* Parse the vector of arguments *) + let rec parse i = + if i <= last then begin + let s = argv.(i) in + let optact = + try Some (Hashtbl.find exact_cases s) + with Not_found -> find_action s inexact_cases in + match optact with + | None -> + let msg = sprintf "unknown argument `%s'" s in + raise (CmdError msg) + | Some(Set r) -> + r := true; parse (i+1) + | Some(Unset r) -> + r := false; parse (i+1) + | Some(Self fn) -> + fn s; parse (i+1) + | Some(String fn) -> + if i + 1 <= last then begin + fn argv.(i+1); parse (i+2) + end else begin + let msg = sprintf "option `%s' expects an argument" s in + raise (CmdError msg) + end + | Some(Integer fn) -> + if i + 1 <= last then begin + let n = + try + int_of_string argv.(i+1) + with Failure _ -> + let msg = sprintf "argument to option `%s' must be an integer" s in + raise (CmdError msg) + in + fn n; parse (i+2) + end else begin + let msg = sprintf "option `%s' expects an argument" s in + raise (CmdError msg) + end + | Some (Ignore) -> + if i + 1 <= last then begin + parse (i+2) + end else begin + let msg = sprintf "option `%s' expects an argument" s in + raise (CmdError msg) + end + | Some (Unit f) -> f (); parse (i+1) + end + in parse first + +let argv = + try + Responsefile.expandargv Sys.argv + with Responsefile.Error msg | Sys_error msg -> + eprintf "Error while processing the command line: %s\n" msg; + exit 2 + +let parse_cmdline spec = + parse_array spec argv 1 (Array.length argv - 1) + +let long_int_action key s = + let ls = String.length s + and lkey = String.length key in + assert (ls > lkey); + let s = String.sub s (lkey + 1) (ls - lkey - 1) in + try + int_of_string s + with Failure _ -> + let msg = sprintf "argument to option `%s' must be an integer" key in + raise (CmdError msg) + +let longopt_int key f = + let act s = + let n = long_int_action key s in + f n in + Prefix (key ^ "="),Self act |