Arguments

Command-line argument parser. Simple usage is:

auto args = new Arguments;
args.parse ("-a -b", true);
auto a = args("a");
auto b = args("b");
if (a.set && b.set)
    ...

Argument parameters are assigned to the last known target, such that multiple parameters accumulate:

args.parse ("-a=1 -a=2 foo", true);
assert (args('a').assigned().length is 3);

That example results in argument 'a' assigned three parameters. Two parameters are explicitly assigned using '=', while a third is implicitly assigned(). Implicit parameters are often useful for collecting filenames or other parameters without specifying the associated argument:

args.parse ("thisfile.txt thatfile.doc -v", true);
assert (args(null).assigned().length is 2);

The 'null' argument is always defined and acts as an accumulator for parameters left uncaptured by other arguments. In the above instance it was assigned both parameters.

Examples thus far have used 'sloppy' argument declaration, via the second argument of parse() being set true. This allows the parser to create argument declaration on-the-fly, which can be handy for trivial usage. However, most features require the a- priori declaration of arguments:

args = new Arguments;
args('x').required;
if (! args.parse("-x"))
      // x not supplied!

Sloppy arguments are disabled in that example, and a required argument 'x' is declared. The parse() method will fail if the pre-conditions are not fully met. Additional qualifiers include specifying how many parameters are allowed for each individual argument, default parameters, whether an argument requires the presence or exclusion of another, etc. Qualifiers are typically chained together and the following example shows argument "foo" being made required, with one parameter, aliased to 'f', and dependent upon the presence of another argument "bar":

args("foo").required.params(1).aliased('f').requires("bar");
args("help").aliased('?').aliased('h');

Parameters can be constrained to a set of matching text values, and the parser will fail on mismatched input:

args("greeting").restrict("hello", "yo", "gday");
args("enabled").restrict("true", "false", "t", "f", "y", "n");

A set of declared arguments may be configured in this manner and the parser will return true only where all conditions are met. Where a error condition occurs you may traverse the set of arguments to find out which argument has what error. This can be handled like so, where arg.error holds a defined code:

if (! args.parse (...))
      foreach (arg; args)
               if (arg.error)
                   ...

Error codes are as follows:

None:           ok (zero)
ParamLo:        too few params for an argument
ParamHi:        too many params for an argument
Required:       missing argument is required 
Requires:       depends on a missing argument
Conflict:       conflicting argument is present
Extra:          unexpected argument (see sloppy)
Option:         parameter does not match options

A simpler way to handle errors is to invoke an internal format routine, which constructs error messages on your behalf:

if (! args.parse (...))
      stderr (args.errors(&stderr.layout.sprint));

Note that messages are constructed via a layout handler and the messages themselves may be customized (for i18n purposes). See the two errors() methods for more information on this.

The parser make a distinction between a short and long prefix, in that a long prefix argument is always distinct while short prefix arguments may be combined as a shortcut:

args.parse ("--foo --bar -abc", true);
assert (args("foo").set);
assert (args("bar").set);
assert (args("a").set);
assert (args("b").set);
assert (args("c").set);

In addition, short-prefix arguments may be "smushed" with an associated parameter when configured to do so:

args('o').params(1).smush;
if (args.parse ("-ofile"))
    assert (args('o').assigned()[0] == "file");

There are two callback varieties supports, where one is invoked when an associated argument is parsed and the other is invoked as parameters are assigned(). See the bind() methods for delegate signature details.

You may change the argument prefix to be something other than "-" and "--" via the constructor. You might, for example, need to specify a "/" indicator instead, and use ':' for explicitly assigning parameters:

auto args = new Args ("/", "-", ':');
args.parse ("-foo:param -bar /abc");
assert (args("foo").set);
assert (args("bar").set);
assert (args("a").set);
assert (args("b").set);
assert (args("c").set);
assert (args("foo").assigned().length is 1);

Returning to an earlier example we can declare some specifics:

args('v').params(0);
assert (args.parse (`-v thisfile.txt thatfile.doc`));
assert (args(null).assigned().length is 2);

Note that the -v flag is now in front of the implicit parameters but ignores them because it is declared to consume none. That is, implicit parameters are assigned to arguments from right to left, according to how many parameters said arguments may consume. Each sloppy argument consumes parameters by default, so those implicit parameters would have been assigned to -v without the declaration shown. On the other hand, an explicit assignment (via '=') always associates the parameter with that argument even when an overflow would occur (though will cause an error to be raised).

Certain parameters are used for capturing comments or other plain text from the user, including whitespace and other special chars. Such parameter values should be quoted on the commandline, and be assigned explicitly rather than implicitly:

args.parse (`--comment="-- a comment --"`);

Without the explicit assignment, the text content might otherwise be considered the start of another argument (due to how argv/argc values are stripped of original quotes).

Lastly, all subsequent text is treated as paramter-values after a "--" token is encountered. This notion is applied by unix systems to terminate argument processing in a similar manner. Such values are considered to be implicit, and are assigned to preceding args in the usual right to left fashion (or to the null argument):

args.parse (`-- -thisfile --thatfile`);
assert (args(null).assigned().length is 2);

Constructors

this
this(const(char)[] sp, const(char)[] lp, char eq)

Construct with the specific short & long prefixes, and the given assignment character (typically ':' on Windows but we set the defaults to look like unix instead)

Members

Aliases

opCall
alias opCall = get
Undocumented in source.
opIndex
alias opIndex = get
Undocumented in source.

Classes

Argument
class Argument

A specific argument instance. You get one of these from Arguments.get() and visit them via Arguments.opApply()

Functions

clear
Arguments clear()

Clear parameter assignments, flags and errors. Note this does not remove any Arguments

errors
Arguments errors(const(char[])[] errors)

Use this method to replace the default error messages. Note that arguments are passed to the formatter in the following order, and these should be indexed appropriately by each of the error messages (see examples in errmsg above):

errors
char[] errors(char[] delegate(char[] buf, const(char)[] fmt, ...) dg)

Construct a string of error messages, using the given delegate to format the output. You would typically pass the system formatter here, like so:

get
Argument get(char name)

Obtain an argument reference, creating an new instance where necessary. Use array indexing or opCall syntax if you prefer

get
Argument get(const(char)[] name)

Obtain an argument reference, creating an new instance where necessary. Use array indexing or opCall syntax if you prefer.

help
Arguments help(void delegate(const(char)[] arg, const(char)[] help) dg)

Expose the configured set of help text, via the given delegate

opApply
int opApply(int delegate(ref Argument) dg)

Traverse the set of arguments

parse
bool parse(const(char)[] input, bool sloppy)

Parse string[] into a set of Argument instances. The 'sloppy' option allows for unexpected arguments without error.

parse
bool parse(const(char[])[] input, bool sloppy)

Parse a string into a set of Argument instances. The 'sloppy' option allows for unexpected arguments without error.

Examples

1 auto args = new Arguments;
2 
3 // basic 
4 auto x = args['x'];
5 assert (args.parse (""));
6 x.required;
7 assert (args.parse ("") is false);
8 assert (args.clear().parse ("-x"));
9 assert (x.set);
10 
11 // alias
12 x.aliased('X');
13 assert (args.clear().parse ("-X"));
14 assert (x.set);
15 
16 // unexpected arg (with sloppy)
17 assert (args.clear().parse ("-y") is false);
18 assert (args.clear().parse ("-y") is false);
19 assert (args.clear().parse ("-y", true) is false);
20 assert (args['y'].set);
21 assert (args.clear().parse ("-x -y", true));
22 
23 // parameters
24 x.params(0);
25 assert (args.clear().parse ("-x param"));
26 assert (x.assigned().length is 0);
27 assert (args(null).assigned().length is 1);
28 x.params(1);
29 assert (args.clear().parse ("-x=param"));
30 assert (x.assigned().length is 1);
31 assert (x.assigned()[0] == "param");
32 assert (args.clear().parse ("-x param"));
33 assert (x.assigned().length is 1);
34 assert (x.assigned()[0] == "param");
35 
36 // too many args
37 x.params(1);
38 assert (args.clear().parse ("-x param1 param2"));
39 assert (x.assigned().length is 1);
40 assert (x.assigned()[0] == "param1");
41 assert (args(null).assigned().length is 1);
42 assert (args(null).assigned()[0] == "param2");
43 
44 // now with default params
45 assert (args.clear().parse ("param1 param2 -x=blah"));
46 assert (args[null].assigned().length is 2);
47 assert (args(null).assigned().length is 2);
48 assert (x.assigned().length is 1);
49 x.params(0);
50 assert (!args.clear().parse ("-x=blah"));
51 
52 // args as parameter
53 assert (args.clear().parse ("- -x"));
54 assert (args[null].assigned().length is 1);
55 assert (args[null].assigned()[0] == "-");
56 
57 // multiple flags, with alias and sloppy
58 assert (args.clear().parse ("-xy"));
59 assert (args.clear().parse ("-xyX"));
60 assert (x.set);
61 assert (args['y'].set);
62 assert (args.clear().parse ("-xyz") is false);
63 assert (args.clear().parse ("-xyz", true));
64 auto z = args['z'];
65 assert (z.set);
66 
67 // multiple flags with trailing arg
68 assert (args.clear().parse ("-xyz=10"));
69 assert (z.assigned().length is 1);
70 
71 // again, but without sloppy param declaration
72 z.params(0);
73 assert (!args.clear().parse ("-xyz=10"));
74 assert (args.clear().parse ("-xzy=10"));
75 assert (args('y').assigned().length is 1);
76 assert (args('x').assigned().length is 0);
77 assert (args('z').assigned().length is 0);
78 
79 // x requires y
80 x.requires('y');
81 assert (args.clear().parse ("-xy"));
82 assert (args.clear().parse ("-xz") is false);
83 
84 // defaults
85 z.defaults("foo");
86 assert (args.clear().parse ("-xy"));
87 assert (z.assigned().length is 1);
88 
89 // long names, with params
90 assert (args.clear().parse ("-xy --foobar") is false);
91 assert (args.clear().parse ("-xy --foobar", true));
92 assert (args["y"].set && x.set);
93 assert (args["foobar"].set);
94 assert (args.clear().parse ("-xy --foobar=10"));
95 assert (args["foobar"].assigned().length is 1);
96 assert (args["foobar"].assigned()[0] == "10");
97 
98 // smush argument z, but not others
99 z.params();
100 assert (args.clear().parse ("-xy -zsmush") is false);
101 assert (x.set);
102 z.smush();
103 assert (args.clear().parse ("-xy -zsmush"));
104 assert (z.assigned().length is 1);
105 assert (z.assigned()[0] == "smush");
106 assert (x.assigned().length is 0);
107 z.params(0);
108 
109 // conflict x with z
110 x.conflicts(z);
111 assert (args.clear().parse ("-xyz") is false);
112 
113 // word mode, with prefix elimination
114 args = new Arguments (null, null);
115 assert (args.clear().parse ("foo bar wumpus") is false);
116 assert (args.clear().parse ("foo bar wumpus wombat", true));
117 assert (args("foo").set);
118 assert (args("bar").set);
119 assert (args("wumpus").set);
120 assert (args("wombat").set);
121 
122 // use '/' instead of '-'
123 args = new Arguments ("/", "/");
124 assert (args.clear().parse ("/foo /bar /wumpus") is false);
125 assert (args.clear().parse ("/foo /bar /wumpus /wombat", true));
126 assert (args("foo").set);
127 assert (args("bar").set);
128 assert (args("wumpus").set);
129 assert (args("wombat").set);
130 
131 // use '/' for short and '-' for long
132 args = new Arguments ("/", "-");
133 assert (args.clear().parse ("-foo -bar -wumpus -wombat /abc", true));
134 assert (args("foo").set);
135 assert (args("bar").set);
136 assert (args("wumpus").set);
137 assert (args("wombat").set);
138 assert (args("a").set);
139 assert (args("b").set);
140 assert (args("c").set);
141 
142 // "--" makes all subsequent be implicit parameters
143 args = new Arguments;
144 version (dashdash)
145         {
146         args('f').params(0);
147         assert (args.parse ("-f -- -bar -wumpus -wombat --abc"));
148         assert (args('f').assigned().length is 0);
149         assert (args(null).assigned().length is 4);
150         }
151      else
152         {
153         args('f').params(2);
154         assert (args.parse ("-f -- -bar -wumpus -wombat --abc"));
155         assert (args('f').assigned().length is 2);
156         assert (args(null).assigned().length is 2);
157         }

Meta