ref: 3a5ddf0610add4ea0663c4bf2d7f569ac723ad81
dir: /doc/api/libstd/cli.txt/
{ title: CLI Parsing description: libstd: CLI Parsing } Command Line Parsing -------------------- Command line parsing is something that nearly every program needs. This section of libstd provides simple command line parsing with autogenerated help. pkg std = type optdef = struct argdesc : byte[:] /* the description for the usage */ minargs : std.size /* the minimum number of positional args */ maxargs : std.size /* the maximum number of positional args (0 = unlimited) */ noargs : std.bool /* whether we accept args at all */ opts : optdesc[:] /* the description of the options */ ;; type optdesc = struct opt : char arg : byte[:] desc : byte[:] optional : bool ;; type optparsed = struct opts : (char, byte[:])[:] args : byte[:][:] ;; const optparse : (optargs : byte[:][:], def : optdef# -> optparsed) const optusage : (prog : byte[:], def : optdef# -> void) ;; Syntax ------- A command line is composed of a list of words, known as. These arguments may be options that the program can act on, known as "flags". These flags may take up to one argument. To avoid confusing with the top level arguments, this document will refer to them as "values". Anything that is not a flag is a "positional argument", or simply an "argument". In general, the POSIX syntax for arguments is followed, with a few minor enhancements. Myrddin program will use the following semantics for command line options: - Arguments are groupls of flags if they follow a '-'. A flag is any single unicode character, potentially followed by a single value. This value may be optional. - Flags that take values will consume the remainder of the argument as the value. If the remainder of the argument is empty, then the next argument is consumed as the value. For example, `-foo` and `-f oo` are equivalent. - Any flags that do not take arguments may be placed before other flags within the same argument. For example, `-x -y -z` is equivalent to `-xyz`, as long as `-x` and `-y` have no optional arguments. - The first '--' stops flags from being recognized, and treats them as arguments. - Flags may be supplied in any order, intermingled with arguments, and repeated as many times as desired. An unrecognized flag is an error, and will trigger a usage message. Types ------ The API provided for command line parsing is relatively declarative, with the options specified in a struct passed to the parsing. type optdef = struct argdesc : byte[:] minargs : std.size maxargs : std.size noargs : std.bool opts : optdesc[:] ;; The optdef is the top level structure describing the command line arguments. It contains the following fields: <dl> <dt><code>argdesc</code></dt> <dd> <p>Argdesc is a string describing the positional arguments passed to the program. It doesn't change the way that the arguments are parsed, but is used to document the arguments to the user.</p> <p>In general, this should be a summary of any expected argument. If a variable number of them are expected, the argument should be followed with a <code>...</code>.</p> <p>For example, a program that takes an output and a list of inputs may provide the following for <code>argdesc</code>:</p> <p><code>"output inputs..."</code></p> <p>When the help string is generated, the output would look like:</p> <p><code>myprog [-o option] output inputs...</code></p> </dd> <dt><code>minargs</code></dt> <dd> <p>This argument limits the minimum number of arguments that the program will accept without error. If at minimum 3 inputs are needed, for example, then this value should be set to 3. This does not count flags, nor does it count the program name.</p> <p> If set to 0, this value is ignored. This is the default value.</p> </dd> <dt><code>maxargs</code></dt> <dd> <p>This argument limits the maximum number of arguments that the program will accept without error. If the program takes at most 1 argument, for example, example, then this value should be set to 3. Just like <code>maxargs</code>, this does not count flags or the program name. </p> <p> If set to 0, this value is ignored. This is the default value.</p> </dd> <dt><code>noargs</code></dt> <dd> <p>This argument causes the program to reject any arguments at all.</p> </dd> <dt><code>opts</code></dt> <dd><p>This is a list of descriptions of the options that this program takes. This list may be empty, at which point this api still provides a good way of checking that no invalid arguments are passed.</p> </dd> </dl> type optdesc = struct opt : char arg : byte[:] desc : byte[:] optional : bool ;; This is a description of a command line argument. It contains the following fields to be set by the user: <dl> <dt><code>opt</code></dt> <dd> <p>This is a single unicode character that is used for the option flag.</p> </dd> <dt><code>arg</code></dt> <dd> <p>This is a single word description of the argument. If it is not present or has zero length, this indicates that the flag takes no value. Otherwise, the value is mandatory, unless the <code>optional</code> flag is set.</p> </dd> <dt><code>optional</code></dt> <dd> <p>This is a boolean that allows for the value <code>arg</code> to be optionally omitted when using the flag. It is disabled by default. </p> </dd> <dt><code>desc</code></dt> <dd> <p>This is a short sentence describing <code>arg</code>. It has no semantic effect on the option parsing, and is only used in generating help output for the arguments. </p> </dd> </dl> type optparsed = struct opts : (char, byte[:])[:] args : byte[:][:] prog : byte[:] ;; This is the final result of parsing the options. The `opts` member contains a list of options in the form of `(opt, val)` pairs. The option `opt` will be repeated once for every time that the flag `opt` is seen within the command line. If there is no value passed with the flag, then the string will be the empty string. Otherwise, it will contain the string passed. The `args` member contains the arguments, collected for easy iteration, and the `prog` member contains the binary name. Functions ---------- const optparse : (optargs : byte[:][:], def : optdef# -> optparsed) Optparse takes an array `optargs` containing the command line arguments passed to the program, as well as an `optdef` pointer describing the expected arguments, and spits out out an `optparsed`. The arguments `optargs` are expected to contain the program name. const optusage : (prog : byte[:], def : optdef# -> void) Optusage takes the string `prog` containing the program name, and an `def` containing an `optdef` which describes the arguments to provide help for. It prints these out on `stderr` (fd 1), and returns. Examples: -------- This example is a trivial one, which parses no flags, and merely errors if given any. const main = {args var cmd cmd = std.optparse(args, &[ .argdesc = "vals", ]) for arg in cmd.args std.put("arg: {}\n", arg) ;; } This example shows some more advanced usage, and is extracted from mbld. const main = {args var dumponly var targname var bintarg var cmd var libpath cmd = std.optparse(args, &[ .argdesc = "[inputs...]", .opts = [ [.opt='t', .desc="list all available targets"], [.opt='T', .arg="tag", .desc="build with specified systag"], [.opt='S', .desc="generate assembly when building"], [.opt='d', .desc="dump debugging information for mbld"], [.opt='I', .arg="inc", .desc="add 'inc' to your include path"], [.opt='R', .arg="root", .desc="install into 'root'"], [.opt='b', .arg="bin", .desc="compile binary named 'bin' from inputs"], [.opt='l', .arg="lib", .desc="compile lib named 'lib' from inputs"], [.opt='r', .arg="rt", .desc="link against runtime 'rt' instead of default"], [.opt='C', .arg="mc", .desc="compile with 'mc' instead of the default compiler"], [.opt='M', .arg="mu", .desc="merge uses with 'mu' instead of the default muse"], ][:] ]) targname = "" tags = [][:] for opt in cmd.opts match opt | ('t', ""): dumponly = true | ('S', ""): bld.opt_genasm = true | ('I', arg): bld.opt_incpaths = std.slpush(bld.opt_incpaths, arg) | ('R', arg): bld.opt_instroot = arg | ('T', tag): tags = std.slpush(tags, tag) | ('b', arg): targname = arg bintarg = true | ('l', arg): targname = arg bintarg = false | ('r', arg): if std.sleq(arg, "none") bld.opt_runtime = "" else bld.opt_runtime = arg ;; /* internal undocumented args; used by compiler suite for building with an uninstalled compiler. */ | ('d', arg): bld.opt_debug = true | ('C', arg): bld.opt_mc = arg | ('M', arg): bld.opt_muse = arg | _: std.die("unreachable\n") ;; ;; for arg in cmd.args /* build stuff */ ;; }