15.9 Command-Line Parsing (original) (raw)

15.9 Command-Line Parsing🔗

(command-line optional-name-expr optional-argv-expr flag-clause ... finish-clause)
optional-name-expr = | #:program name-expr optional-argv-expr = #:argv argv-expr flag-clause = #:multi flag-spec ... #:once-each flag-spec ... #:once-any flag-spec ... #:final flag-spec ... #:usage-help string ... #:help-labels string ... #:ps string ... flag-spec = (flags id ... help-spec body ...+) (flags => handler-expr help-expr) flags = flag-string (flag-string ...+) help-spec = string (string-expr ...+) finish-clause = #:args arg-formals body ...+ #:handlers handlers-exprs arg-formals = rest-id (arg ...) (arg ...+ . rest-id) arg = id [id default-expr] handlers-exprs = finish-expr arg-strings-expr finish-expr arg-strings-expr help-expr finish-expr arg-strings-expr help-exprunknown-expr

Parses a command line according to the specification in theflag-clauses.

The name-expr, if provided, should produce a path or string to be used as the program name for reporting errors when the command-line is ill-formed. It defaults to (find-system-path 'run-file). When a path is provided, only the last element of the path is used to report an error.

The argv-expr, if provided, must evaluate to a list or a vector of strings. It defaults to(current-command-line-arguments).

The command-line is disassembled into flags, each possibly with flag-specific arguments, followed by (non-flag) arguments. Command-line strings starting with - or+ are parsed as flags, but arguments to flags are never parsed as flags, and integers and decimal numbers that start with- or + are not treated as flags. Non-flag arguments in the command-line must appear after all flags and the flags’ arguments. No command-line string past the first non-flag argument is parsed as a flag. The built-in -- flag signals the end of command-line flags; any command-line string past the --flag is parsed as a non-flag argument.

A #:multi, #:once-each, #:once-any, or#:final clause introduces a set of command-line flag specifications. The clause tag indicates how many times the flag can appear on the command line:

A normal flag specification has four parts:

A flag specification using => escapes to a more general method of specifying the handler and help strings. In this case, the handler procedure and help string list returned byhandler-expr and help-expr are used as in thetable argument of parse-command-line.

A #:usage-help clause inserts text lines immediately after the usage line. Each string in the clause provides a separate line of text.

A #:help-labels clause inserts text lines into the help table of command-line flags. Each string in the clause provides a separate line of text.

A #:ps clause inserts text lines at the end of the help output. Each string in the clause provides a separate line of text.

After the flag clauses, a final clause handles command-line arguments that are not parsed as flags:

Example:

(define verbose-mode (make-parameter #f))
(define profiling-on (make-parameter #f))
(define optimize-level (make-parameter 0))
(define link-flags (make-parameter null))
(define file-to-compile
(command-line
#:program "compiler"
#:once-each
[("-v" "--verbose") "Compile with verbose messages"
(verbose-mode #t)]
[("-p" "--profile") "Compile with profiling"
(profiling-on #t)]
#:once-any
[("-o" "--optimize-1") "Compile with optimization level 1"
(optimize-level 1)]
["--optimize-2" (; show help on separate lines
"Compile with optimization level 2,"
"which includes all of level 1")
(optimize-level 2)]
#:multi
[("-l" "--link-flags") lf ; flag takes one argument
"Add a flag for the linker"
(link-flags (cons lf (link-flags)))]
#:args (filename) ; expect one command-line argument:
; return the argument as a filename to compile
filename))

Parses a command-line using the specification in table. For an overview of command-line parsing, see the command-lineform, which provides a more convenient notation for most purposes.

The table argument to this procedural form encodes the information in command-line’s clauses, except for theargs clause. Instead, arguments are handled by thefinish-proc procedure, and help information about non-flag arguments is provided in arg-help-strs. In addition, thefinish-proc procedure receives information accumulated while parsing flags. The help-proc and unknown-procarguments allow customization that is not possible withcommand-line.

When there are no more flags, finish-proc is called with a list of information accumulated for command-line flags (see below) and the remaining non-flag arguments from the command-line. The arity offinish-proc determines the number of non-flag arguments accepted and required from the command-line. For example, iffinish-proc accepts either two or three arguments, then either one or two non-flag arguments must be provided on the command-line. The finish-proc procedure can have any arity (see procedure-arity) except 0 or a list of0s (i.e., the procedure must at least accept one or more arguments).

The arg-help-strs argument is a list of strings identifying the expected (non-flag) command-line arguments, one for each argument. If an arbitrary number of arguments are allowed, the last string in arg-help-strs represents all of them.

The help-proc procedure is called with a help string if the-h or --help flag is included on the command line. If an unknown flag is encountered, the unknown-proc procedure is called just like a flag-handling procedure (as described below); it must at least accept one argument (the unknown flag), but it may also accept more arguments. The default help-proc displays the string and exits and the default unknown-proc raises theexn:fail exception.

A table is a list of flag specification sets. Each set is represented as a pair of two items: a mode symbol and a list of either help strings or flag specifications. A mode symbol is one of'once-each, 'once-any, 'multi,'final, 'help-labels, 'usage-help, or'ps with the same meanings as the corresponding clause tags in command-line. For the 'help-labels,'usage-help or 'ps mode, a list of help strings is provided. For the other modes, a list of flag specifications is provided, where each specification maps a number of flags to a single handler procedure. A specification is a list of three items:

The following example is the same as the core example forcommand-line, translated to the procedural form:

(parse-command-line "compile" (current-command-line-arguments)
`((once-each
[("-v" "--verbose")
,(lambda (flag) (verbose-mode #t))
("Compile with verbose messages")]
[("-p" "--profile")
,(lambda (flag) (profiling-on #t))
("Compile with profiling")])
(once-any
[("-o" "--optimize-1")
,(lambda (flag) (optimize-level 1))
("Compile with optimization level 1")]
[("--optimize-2")
,(lambda (flag) (optimize-level 2))
(("Compile with optimization level 2,"
"which implies all optimizations of level 1"))])
(multi
[("-l" "--link-flags")
,(lambda (flag lf) (link-flags (cons lf (link-flags))))
("Add a flag for the linker" "lf")]))
(lambda (flag-accum file) file)
'("filename"))