Define a structure for representing command line options, and a command-line parser that creates this structure.
(defoptions myopts :parents (myprogram) :short "Command line options for my program." :tag :myopts ((help booleanp "Print a help message and exit with status 0.") (outfile stringp "Where to write the output." :default "a.out")))
So far, this is identical to
But in addition to introducing an aggregate,
For
--help Print a help message and exit with status 0. --outfile=ARG Where to write the output.
So that's handy, and below we'll see how to customize this message a bit.
You can probably easily imagine incorporating this into your program's
Meanwhile, the parsing function,
(parse-myopts args &key (init '*default-myopts*)) --> (mv errmsg result extra)
The
Usually you won't care about the optional
Command-line parsing can fail because the user might type in something
crazy. For instance, they might try to run
(b* (((mv errmsg result extra) (parse-myopts '("--hlep"))) ((when errmsg) (cw "Error processing options!~%") (cw "~@0~%" errmsg) nil)) result)
Will print out:
Error processing options! Unrecognized option --hlep
When command-line processing is successful, the main return value,
(b* (((mv ?errmsg result extra) (parse-myopts '("foo.java" "--outfile" "report.txt" "bar.java")))) (list :result result :extra extra))
Will return:
(:RESULT (:MYOPTS (HELP) (OUTFILE . "report.txt")) :EXTRA ("foo.java" "bar.java"))
Ordinarily a program that takes options like
(defoptions myopts :parents (myprogram) :short "Command line options for my program." :tag :myopts ((help booleanp "Print a help message and exit with status 0." :alias #\h) (outfile stringp "Where to write the output." :default "a.out" :alias #\o)))
Note that the usage message gets automatically extended to take these
into account.
-h,--help Print a help message and exit with status 0. -o,--outfile=ARG Where to write the output.
The
If you need something fancier, you can write your own parser. See custom-parser for details. After writing your own
(outfile stringp "Where to write the output." :default "a.out" :alias #\o ;; redundant, but acceptable, to explicitly say to use the ;; default stringp parser :parser getopt::parse-string)
By default the option name is just automatically inferred from the field
name. In rare cases you might want to change this, e.g., perhaps you prefer to
use field-names like
(defoptions myopts :parents (myprogram) :short "Command line options for my program." :tag :myopts ((verbosep booleanp :longname "verbose" "Print excessive debugging information.") (help booleanp "Print a help message and exit with status 0." :alias #\h) (outfile stringp "Where to write the output." :default "a.out" :alias #\o)))
By default options are unmergeable, meaning that it is an error to try to specify them more than once. This is generally sensible behavior, e.g., you probably don't want to support things like:
myprog --username jared --username sol ...
But occasionally you want to have an option that "stacks" with other options. For instance, in our Verilog parsing stuff we often want a "search path" that is a list of directories.
To facilitate this, the
myprog --dir /dir1 --dir /dir2 ...
And turns them into a
(dirs string-listp :longname "dir" :parser getopt::parse-string :merge cons)
Note that this will actually accumulate the options in the reverse
order (because cons extends the front of a list). This is easily
corrected for by using some kind of
By default we reuse the xdoc documentation for a field as its usage
message. If you want to have a separate usage message instead, you can just
add one, e.g., via
For options that take arguments, you may occasionally want to name the argument. That is, by default, we will produce usage messages like:
--port ARG The port to connect to. --out ARG Where to write the output.
But maybe you'd rather have this print as:
--port PORT The port to connect to. --out FILE Where to write the output.
You can do this by adding, e.g.,