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
|
structure Opts =
struct
datatype 'a optDesc = BoolOpt of bool -> unit
| StringOpt of string -> unit
structure StringMap = Map(type k = string val cmp = String.compare)
fun error (msg : string) : 'a =
(print msg ;
OS.Process.exit (OS.Process.failure))
fun boolFromString s =
case s of
"1" => true
| "t" => true
| "T" => true
| "true" => true
| "TRUE" => true
| "True" => true
| "0" => false
| "f" => false
| "F" => false
| "false" => false
| "FALSE" => false
| "False" => false
| _ => error "invalid boolean value"
fun getOpt (desc : (string * 'a optDesc) list) : string list =
let
val parsers = StringMap.fromList desc
fun go [] = []
| go (arg :: args) =
if arg = "-" orelse not (String.isPrefix "-" arg)
then arg :: args
else if arg = "--"
then args
else
let
val name =
if String.isPrefix "--" arg
then String.extract (arg, 2, NONE)
else String.extract (arg, 1, NONE)
val _ =
if String.isPrefix "-" name orelse String.isPrefix "=" name
then error "bad flag syntax"
else ()
(* It's a flag. Does it have an argument? *)
val (name', value) =
case CharVector.findi (fn (_, x) => x = #"=") name of
SOME (i, _) => (substring (name, 0, i), String.extract (name, i + 1, NONE))
| NONE => (name, "")
val parser =
case StringMap.lookup name' parsers of
SOME x => x
| NONE => error ("flag provided but not defined: " ^ String.toString name')
in
case parser of
BoolOpt func =>
if value = ""
then
(func true ;
go args)
else
(func (boolFromString value) ;
go args)
| StringOpt func =>
(* It must have a value, which might be the next argument. *)
if value = "" andalso not (null args)
then
(func (hd args) ;
go (tl args))
else if value = ""
then error ("flag needs an argument: " ^ String.toString name')
else
(func value ;
go args)
end
in
go (CommandLine.arguments ())
end
end
|