1 (* Copyright (C
) 2009,2017 Matthew Fluet
.
2 * Copyright (C
) 1999-2006 Henry Cejtin
, Matthew Fluet
, Suresh
3 * Jagannathan
, and Stephen Weeks
.
4 * Copyright (C
) 1997-2000 NEC Research Institute
.
6 * MLton is released under a BSD
-style license
.
7 * See the file MLton
-LICENSE for details
.
10 structure Popt
: POPT
=
15 | Digit
of int -> unit
18 | None
of unit
-> unit
19 |
Real of real -> unit
20 | SpaceString
of string -> unit
21 | SpaceString2
of string * string -> unit
22 |
String of string -> unit
23 |
Word of word -> unit
26 fun make
b (r
: bool ref
): t
= None (fn () => r
:= b
)
28 val trueRef
= make
true
29 val falseRef
= make
false
32 fun boolRef (r
: bool ref
): t
= Bool (fn b
=> r
:= b
)
34 fun intRef (r
: int ref
): t
= Int (fn n
=> r
:= n
)
36 fun stringRef (r
: string ref
): t
= String (fn s
=> r
:= s
)
38 fun wordRef (r
: word ref
): t
= Word (fn w
=> r
:= w
)
40 val trace
= ("trace", SpaceString (fn s
=>
43 val _
= debug
:= Out Out
.error
47 ; on (String.split (s
, #
",")))
50 fun memString (s
: string): int option
=
57 let val c
= String.sub (s
, i
)
58 fun done n
= SOME (n
* ac
)
63 case Char.digitToInt c
of
65 | SOME c
=> loop (i
+ 1, ac
* 10 + c
)
70 (* Parse the command line opts
and return any remaining args
. *)
71 fun parse
{switches
: string list
,
72 opts
: (string * t
) list
}: string list Result
.t
=
74 exception Error
of string
77 | switch
:: switches
=>
79 fun error s
= raise (Error s
)
81 case String.sub (switch
, 0) of
83 let val switch
= String.dropPrefix (switch
, 1)
84 in case List.peek (opts
, fn (switch
', _
) =>
88 (* Handle the switches
where there is no space
89 * separating the argument
.
92 fn [] => error (concat
["unknown switch: -",
94 |
(switch
', arg
) :: opts
=>
98 (switch
, {prefix
= switch
'})
99 then f (String.dropPrefix
100 (switch
, String.size switch
'))
108 error (concat
["invalid digit ", s
, " used with -", switch
])
111 then (case Char.digitToInt
112 (String.sub (s
, 0)) of
125 fun next (f
: 'a
-> unit
, get
, msg
) =
128 error (concat
["-", switch
, " requires an argument"])
129 | switch
' :: switches
=>
131 NONE
=> error (concat
["-", switch
, " requires ", msg
])
132 | SOME n
=> (f n
; loop switches
)
135 Bool f
=> next (f
, Bool.fromString
, "a boolean")
137 error (concat
["-", switch
, " requires a digit"])
138 |
Int f
=> next (f
, Int.fromString
, "an integer")
139 | Mem f
=> next (f
, memString
, "a memory amount")
140 | None f
=> (f (); loop switches
)
141 |
Real f
=> next (f
, Real.fromString
, "a real")
142 | SpaceString f
=> next (f
, SOME
, "")
145 s1
:: s2
:: switches
=>
146 (f (s1
, s2
); loop switches
)
147 | _
=> error (concat
["-", switch
, " requires two arguments"]))
148 |
String f
=> (f
""; loop switches
)
149 |
Word f
=> next (f
, Word.fromString
, "a word")
152 | _
=> switch
:: switches
155 Result
.Yes (loop switches
) handle Error s
=> Result
.No s
158 datatype optionStyle
= Normal | Expert
160 fun makeUsage
{mainUsage
, makeOptions
, showExpert
} =
162 val usageRef
: (string -> unit
) option ref
= ref NONE
163 fun usage (s
: string): unit
= valOf (!usageRef
) s
164 fun options () = makeOptions
{usage
= usage
}
171 fun message s
= Out
.outputl (out
, s
)
174 (rev (options ()), [],
175 fn ({arg
, desc
, opt
= _
, name
, style
}, rest
) =>
176 if style
= Normal
orelse showExpert ()
177 then [concat
[" -", name
, arg
, " "], desc
] :: rest
183 table
{columnHeads
= NONE
,
184 justs
= [Left
, Left
],
189 ; message (concat
["usage: ", mainUsage
])
190 ; List.foreach (table
, fn ss
=>
191 message (String.removeTrailing
192 (concat ss
, Char.isSpace
)))
193 ; let open OS
.Process
196 else Error
.bug
"Popt.makeUsage"
201 parse
{opts
= List.map (options (), fn {name
, opt
, ...} => (name
, opt
)),