blob: bc095af69b4d1db11fa29cb3a11b9cd9901a2e3e (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
(* *********************************************************************)
(* *)
(* 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)
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 usage 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 ->
if s <> "-help" && s <> "--help"
then eprintf "Unknown argument `%s'\n" s
else printf "%s" usage;
exit 2
| 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
eprintf "Option `%s' expects an argument\n" s; exit 2
end
| Some(Integer fn) ->
if i + 1 <= last then begin
let n =
try
int_of_string argv.(i+1)
with Failure _ ->
eprintf "Argument to option `%s' must be an integer\n" s;
exit 2
in
fn n; parse (i+2)
end else begin
eprintf "Option `%s' expects an argument\n" s; exit 2
end
end
in parse first
let parse_cmdline spec usage =
parse_array spec usage Sys.argv 1 (Array.length Sys.argv - 1)
|