1 /*******************************************************************************
2 
3     Module to manage command-line arguments.
4 
5     ____________________________________________________________________________
6 
7     Simple usage:
8 
9     ---
10 
11         int main ( istring[] cl_args )
12         {
13             // Create an object to parse command-line arguments
14             auto args = new Arguments;
15 
16             // Setup what arguments are valid
17             // (these can be configured in various ways as will be demonstrated
18             // later in the documentation)
19             args("alpha");
20             args("bravo");
21 
22             // Parse the actual command-line arguments given to the application
23             // (the first element is the application name, so that should not be
24             // passed to the 'parse()' function)
25             auto args_ok = args.parse(cl_args[1 .. $]);
26 
27             if ( args_ok )
28             {
29                 // Proceed with rest of the application
30                 ...
31             }
32             else
33             {
34                 // Discover what caused the error and handle appropriately
35             }
36         }
37 
38     ---
39 
40     ____________________________________________________________________________
41 
42 
43     For the sake of brevity, the rest of this documentation will not show the
44     'main()' function or the creation of the 'args' object. Also, setting up of
45     arguments will be shown only where necessary. Moreover, the 'args.parse()'
46     function will be called with a custom string representing the command-line
47     arguments. This is as shown in the following example:
48 
49     ---
50 
51         args.parse("--alpha --bravo");
52 
53         if ( args("alpha").set )
54         {
55             // This will be reached as '--alpha' was given
56         }
57 
58         if ( args("bravo").set )
59         {
60             // This will be reached as '--bravo' was given
61         }
62 
63         if ( args("charlie").set )
64         {
65             // This will *not* be reached as '--charlie' was not given
66         }
67 
68     ---
69 
70     ____________________________________________________________________________
71 
72 
73     When arguments are being set up, normally all arguments that an application
74     supports are explicitly declared and suitably configured. But sometimes, it
75     may be desirable to use on-the-fly arguments that are not set up but
76     discovered during parsing. Such arguments are called 'sloppy arguments'.
77     Support for sloppy arguments is disabled by default, but can be enabled when
78     calling the 'parse()' function, as shown below:
79 
80     ---
81 
82         args("alpha");
83 
84         args.parse("--alpha --bravo");
85             // This will result in an error because only 'alpha' was declared,
86             // but not 'bravo'.
87 
88         args.parse("--alpha --bravo", true);
89             // This, on the other hand would work. Space for 'bravo' (and
90             // potentially any of its parameters) would be allocated when
91             // 'bravo' gets discovered during parsing.
92 
93     ---
94 
95     ____________________________________________________________________________
96 
97 
98     Arguments can be configured to have aliases. This is a convenient way to
99     represent arguments with long names. Aliases are always exactly one
100     character long. An argument can have multiple aliases. Aliases are always
101     given on the command-line using the short prefix.
102 
103     ---
104 
105         args("alpha").aliased('a');
106         args("help").aliased('?').aliased('h'); // multiple aliases allowed
107 
108         args.parse("-a -?");
109 
110     ---
111 
112     ____________________________________________________________________________
113 
114 
115     Arguments can be configured to be mandatorily present, by calling the
116     'required()' function as follows:
117 
118     ---
119 
120         args("alpha").required();
121 
122         args.parse("--bravo");
123             // This will fail because the required argument 'alpha' was not
124             // given.
125 
126     ---
127 
128     ____________________________________________________________________________
129 
130 
131     An argument can be configured to depend upon another, by calling the
132     'requires()' function as follows:
133 
134     ---
135 
136         args("alpha");
137         args("bravo").requires("alpha");
138 
139         args.parse("--bravo");
140             // This will fail because 'bravo' needs 'alpha', but 'alpha' was not
141             // given.
142 
143         args.parse("--alpha --bravo");
144             // This, on the other hand, will succeed.
145 
146     ---
147 
148     ____________________________________________________________________________
149 
150 
151     An argument can be configured to conflict with another, by calling the
152     'conflicts()' function as follows:
153 
154     ---
155 
156         args("alpha");
157         args("bravo").conflicts("alpha");
158 
159         args.parse("--alpha --bravo");
160             // This will fail because 'bravo' conflicts with 'alpha', so both of
161             // them can't be present together.
162 
163     ---
164 
165     ____________________________________________________________________________
166 
167 
168     By default arguments don't have any associated parameters. When setting up
169     arguments, they can be configured to have zero or more associated
170     parameters. Parameters assigned to an argument can be accessed using that
171     argument's 'assigned[]' array at consecutive indices. The number of
172     parameters assigned to an argument must exactly match the number of
173     parameters it has been set up to have, or else parsing will fail. Dealing
174     with parameters is shown in the following example:
175 
176     ---
177 
178         args("alpha");
179         args("bravo").params(0);
180             // Doing `params(0)` is redundant
181         args("charlie").params(1);
182             // 'charlie' must have exactly one associated parameter
183 
184         args.parse("--alpha --bravo --charlie=chaplin");
185             // the parameter assigned to 'charlie' (i.e. 'chaplin') can be
186             // accessed using `args("charlie").assigned[0]`
187 
188     ---
189 
190     ____________________________________________________________________________
191 
192 
193     Parameter assignment can be either explicit or implicit. Explicit assignment
194     is done using an assignment symbol (defaults to '=', can be changed),
195     whereas implicit assignment happens when a parameter is found after a
196     whitespace.
197     Implicit assignment always happens to the last known argument target, such
198     that multiple parameters accumulate (until the configured parameters count
199     for that argument is reached). Any extra parameters encountered after that
200     are assigned to a special 'null' argument. The 'null' argument is always
201     defined and acts as an accumulator for parameters left uncaptured by other
202     arguments.
203 
204     Please note:
205         * if sloppy arguments are supported, and if a sloppy argument happens to
206           be the last known argument target, then implicit assignment of any
207           extra parameters will happen to that sloppy argument.
208           [example 2 below]
209 
210         * explicit assignment to an argument always associates the parameter
211           with that argument even if that argument's parameters count has been
212           reached. In this case, 'parse()' will fail.
213           [example 3 below]
214 
215     ---
216 
217         args("alpha").params(3);
218 
219         // Example 1
220         args.parse("--alpha=one --alpha=two three four");
221             // In this case, 'alpha' would have 3 parameters assigned to it (so
222             // its 'assigned' array would be `["one", "two", "three"]`), and the
223             // null argument would have 1 parameter (with its 'assigned' array
224             // being `["four"]`).
225             // Here's why:
226             // Two of these parameters ('one' & 'two') were assigned explicitly.
227             // The next parameter ('three') was assigned implicitly since
228             // 'alpha' was the last known argument target. At this point,
229             // alpha's parameters count is reached, so no more implicit
230             // assignment will happen to 'alpha'.
231             // So the last parameter ('four') is assigned to the special 'null'
232             // argument.
233 
234         // Example 2
235         // (sloppy arguments supported by passing 'true' as the second parameter
236         // to 'parse()')
237         args.parse("--alpha one two three four --xray five six", true);
238             // In this case, 'alpha' would get its 3 parameters ('one', 'two' &
239             // 'three') by way of implicit assignment.
240             // Parameter 'four' would be assigned to the 'null' argument (since
241             // implicit assignment to the last known argument target 'alpha' is
242             // not possible as alpha's parameter count has been reached).
243             // The sloppy argument 'xray' now becomes the new last known
244             // argument target and hence gets the last two parameters ('five' &
245             // 'six').
246 
247         // Example 3
248         args.parse("--alpha one two three --alpha=four");
249             // As before, 'alpha' would get its 3 parameters ('one', 'two' &
250             // 'three') by way of implicit assignment.
251             // Since 'four' is being explicitly assigned to 'alpha', parsing
252             // will fail here as 'alpha' has been configured to have at most 3
253             // parameters.
254 
255     ---
256 
257     ____________________________________________________________________________
258 
259 
260     An argument can be configured to have one or more default parameters. This
261     means that if the argument was not given on the command-line, it would still
262     contain the configured parameter(s).
263     It is, of course, possible to have no default parameters configured. But if
264     one or more default parameters have been configured, then their number must
265     exactly match the number of parameters configured.
266 
267     Please note:
268         * Irrespective of whether default parameters have been configured or not,
269           if an argument was not given on the command-line, its 'set()' function
270           would return 'false'.
271           [example 1 below]
272 
273         * Irrespective of whether default parameters have been configured or not,
274           if an argument is given on the command-line, it must honour its
275           configured number of parameters.
276           [example 2 below]
277 
278     ---
279 
280         args("alpha").params(1).defaults("one");
281 
282         // Example 1
283         args.parse("--bravo");
284             // 'alpha' was not given, so `args("alpha").set` would return false
285             // but still `args("alpha").assigned[0]` would contain 'one'
286 
287         // Example 2
288         args.parse("--alpha");
289             // this will fail because 'alpha' expects a parameter and that was
290             // not given. In this case, the configured default parameter will
291             // *not* be picked up.
292 
293     ---
294 
295     ____________________________________________________________________________
296 
297 
298     Parameters of an argument can be restricted to a pre-defined set of
299     acceptable values. In this case, argument parsing will fail on an attempt to
300     assign a value from outside the set:
301 
302     ---
303 
304         args("greeting").restrict(["hello", "namaste", "ahoj", "hola"]);
305         args("enabled").restrict(["true", "false", "t", "f", "y", "n"]);
306 
307         args.parse("--greeting=bye");
308             // This will fail since 'bye' is not among the acceptable values
309 
310     ---
311 
312     ____________________________________________________________________________
313 
314 
315     The parser makes a distinction between long prefix arguments and short
316     prefix arguments. Long prefix arguments start with two hyphens (--argument),
317     while short prefix arguments start with a single hyphen (-a) [the prefixes
318     themselves are configurable, as shown in later documentation]. Within a
319     short prefix argument, each character represents an individual argument.
320     Long prefix arguments must always be distinct, while short prefix arguments
321     may be combined together.
322 
323     ---
324 
325         args.parse("--alpha -b");
326             // The argument 'alpha' will be set.
327             // The argument represented by 'b' will be set (note that 'b' here
328             // could be an alias to another argument, or could be the argument
329             // name itself)
330 
331     ---
332 
333     ____________________________________________________________________________
334 
335 
336     When assigning parameters to an argument using the argument's short prefix
337     version, it is possible to "smush" the parameter with the argument. Smushing
338     refers to omitting the explicit assignment symbol ('=' by default) or
339     whitespace (when relying on implicit assignment) that separates an argument
340     from its parameter. The ability to smush an argument with its parameter in
341     this manner has to be explicitly enabled using the 'smush()' function.
342 
343     Please note:
344         * smushing cannot be done with the long prefix version of an argument
345           [example 2 below]
346 
347         * smushing is irrelevant if an argument has no parameters
348           [example 3 below]
349 
350         * if an argument has more than one parameter, and smushing is desired,
351           then the short prefix version of the argument needs to be repeated as
352           many times as the number of parameters to be assigned (this is because
353           one smush can only assign one parameter at a time)
354           [example 4 below]
355 
356         * smushing cannot be used if the parameter contains the explicit
357           assignment symbol ('=' by default). In this case, either explicit or
358           implicit assignment should be used. This limitation is due to how
359           argv/argc values are stripped of original quotes.
360           [example 5 below]
361 
362     ---
363 
364         // Example 1
365         args("alpha").aliased('a').params(1).smush;
366         args.parse("-aparam");
367             // OK - this is equivalent to `args.parse("-a param");`
368 
369         // Example 2
370         args("bravo").params(1).smush;
371         args.parse("--bravoparam");
372             // ERROR - 'param' cannot be smushed with 'bravo'
373 
374         // Example 3
375         args("charlie").smush;
376             // irrelevant smush as argument has no parameters
377 
378         // Example 4
379         args('d').params(2).smush;
380         args.parse("-dfile1 -dfile2");
381             // smushing multiple parameters requires the short prefix version of
382             // the argument to be repeated. This could have been done without
383             // smushing as `args.parse("-d file1 file2);`
384 
385         // Example 5
386         args("e").params(1).smush;
387         args.parse("-e'foo=bar'");
388             // The parameter 'foo=bar' cannot be smushed with the argument as
389             // the parameter contains '=' within. Be especially careful of this
390             // as the 'parse()' function will not fail in this case, but may
391             // result in unexpected behaviour.
392             // The proper way to assign a parameter containing the explicit
393             // assignment symbol is to use one of the following:
394             //     args.parse("-e='foo=bar'"); // explicit assignment
395             //     args.parse("-e 'foo=bar'"); // implicit assignment
396 
397     ---
398 
399     ____________________________________________________________________________
400 
401 
402     The prefixes used for the long prefix and the short prefix version of the
403     arguments default to '--' & '-' respectively, but they are configurable. To
404     change these, the desired prefix strings need to be passed to the
405     constructor as shown below:
406 
407     ---
408 
409         // Change short prefix to '/' & long prefix to '%'
410         auto args = new Arguments(null, null, null, null, "/", "%");
411 
412         args.parse("%alpha=param %bravo /abc");
413             // arguments 'alpha' & 'bravo' set using the long prefix version
414             // arguments represented by the characters 'a', 'b' & 'c' set using
415             // the short prefix version
416 
417     ---
418 
419     Note that it is also possible to disable both prefixes by passing 'null' as
420     the constructor parameters.
421 
422     ____________________________________________________________________________
423 
424 
425     We noted in the documentation earlier that a parameter following a
426     whitespace gets assigned to the last known target (implicit assignment). On
427     the other hand, the symbol used for explicitly assigning a parameter to an
428     argument defaults to '='. This symbol is also configurable, and can be
429     changed by passing the desired symbol character to the constructor as
430     shown below:
431 
432     ---
433 
434         // Change the parameter assignment symbol to ':'
435         // (the short prefix and long prefix need to be passed as their default
436         // values since we're not changing them)
437         auto args = new Arguments(null, null, null, null, "-", "--", ':');
438 
439         args.parse("--alpha:param");
440             // argument 'alpha' will be assigned parameter 'param' using
441             // explicit assignment
442 
443     ---
444 
445     ____________________________________________________________________________
446 
447 
448     All text following a "--" token are treated as parameters (even if they
449     start with the long prefix or the short prefix). This notion is applied by
450     unix systems to terminate argument processing in a similar manner.
451 
452     These parameters are always assigned to the special 'null' argument.
453 
454     ---
455 
456         args("alpha").params(1);
457 
458         args.parse("--alpha one -- -two --three");
459             // 'alpha' gets one parameter ('one')
460             // the null argument gets two parameters ('-two' & '--three')
461             // note how 'two' & 'three' are prefixed by the short and long
462             // prefixes respectively, but the prefixes don't play any part as
463             // these are just parameters now
464 
465     ---
466 
467     ____________________________________________________________________________
468 
469 
470     When configuring the command-line arguments, qualifiers can be chained
471     together as shown in the following example:
472 
473     ---
474 
475         args("alpha")
476             .required
477             .params(1)
478             .aliased('a')
479             .requires("bravo")
480             .conflicts("charlie")
481             .defaults("one");
482 
483     ---
484 
485     ____________________________________________________________________________
486 
487     The full help message for the application (which includes the configured
488     usage, long & short descriptions as well as the help text of each of the
489     arguments) can be displayed using the 'displayHelp()' function as follows:
490 
491     ---
492 
493         auto args = new Arguments(
494             "my_app",
495             "{0} : this is a short description",
496             "this is the usage string",
497             "this is a long description on how to make '{0}' work");
498 
499         args("alpha")
500             .aliased('a')
501             .params(1,3)
502             .help("help for alpha");
503         args("bravo")
504             .aliased('b')
505             .params(1)
506             .defaults("val")
507             .help("help for bravo");
508 
509         args.displayHelp();
510 
511     ---
512 
513     Doing this, would produce the following help message:
514 
515         my_app : this is a short description
516 
517         Usage:  this is the usage string
518 
519         this is a long description on how to make 'my_app' work
520 
521         Program options:
522           -a, --alpha  help for alpha (1-3 params)
523           -b, --bravo  help for bravo (1 param, default: [val])
524 
525     ____________________________________________________________________________
526 
527 
528     The 'parse()' function will return true only where all conditions are met.
529     If an error occurs, the parser will set an error code and return false.
530 
531     The error codes (which indicate the nature of the error) are as follows:
532 
533         None     : ok (no error)
534         ParamLo  : too few parameters were assigned to this argument
535         ParamHi  : too many parameters were assigned to this argument
536         Required : this is a required argument, but was not given
537         Requires : this argument depends on another argument which was not given
538         Conflict : this argument conflicts with another given argument
539         Extra    : unexpected argument (will not trigger an error if sloppy
540                    arguments are enabled)
541         Option   : parameter assigned is not one of the acceptable options
542 
543 
544     A simple way to handle errors is to invoke an internal format routine, which
545     constructs error messages on your behalf. The messages are constructed using
546     a layout handler and the messages themselves may be customized (for i18n
547     purposes). See the two 'errors()' methods for more information on this. The
548     following example shows this way of handling errors:
549 
550     ---
551 
552         if ( ! args.parse (...) )
553         {
554             stderr(args.errors(&stderr.layout.sprint));
555         }
556 
557     ---
558 
559 
560     Another way of handling argument parsing errors, is to traverse the set of
561     arguments, to find out exactly which argument has the error, and what is the
562     error code. This is as shown in the following example:
563 
564     ---
565 
566         if ( ! args.parse (...) )
567         {
568             foreach ( arg; args )
569             {
570                 if ( arg.error )
571                 {
572                     // 'arg.error' contains one of the above error-codes
573 
574                     ...
575                 }
576             }
577         }
578 
579     ---
580 
581     ____________________________________________________________________________
582 
583 
584     The following two types of callbacks are supported:
585         - a callback called when an argument is parsed
586         - a callback called whenever a parameter gets assigned to an argument
587     (see the 'bind()' methods for the signatures of these delegates).
588 
589     ____________________________________________________________________________
590 
591     Copyright:
592         Copyright (c) 2009 Kris.
593         Some parts copyright (c) 2009-2016 dunnhumby Germany GmbH.
594         All rights reserved.
595 
596     License:
597         Tango Dual License: 3-Clause BSD License / Academic Free License v3.0.
598         See LICENSE_TANGO.txt for details.
599 
600 *******************************************************************************/
601 
602 module ocean.text.Arguments;
603 
604 
605 
606 
607 import ocean.transition;
608 
609 import ocean.io.Stdout;
610 import ocean.io.stream.Format : FormatOutput;
611 import ocean.math.Math;
612 import ocean.text.Util;
613 import ocean.text.convert.Formatter;
614 import ocean.text.convert.Integer;
615 import ocean.util.container.SortedMap;
616 import ocean.util.container.more.Stack;
617 import ocean.core.Verify;
618 
619 version(UnitTest) import ocean.core.Test;
620 
621 /*******************************************************************************
622 
623     The main arguments container class.
624 
625 *******************************************************************************/
626 
627 public class Arguments
628 {
629     import ocean.core.Enforce : enforce;
630 
631     /***************************************************************************
632 
633         Convenience aliases to access a specific argument instance
634 
635     ***************************************************************************/
636 
637     public alias get opCall;  // args("name")
638     public alias get opIndex; // args["name"]
639 
640 
641     /***************************************************************************
642 
643         Convenience alias to get the value of a boolean argument
644 
645     ***************************************************************************/
646 
647     public alias getBool exists;
648 
649 
650     /***************************************************************************
651 
652         Application's name to use in help messages.
653 
654     ***************************************************************************/
655 
656     public istring app_name;
657 
658 
659     /***************************************************************************
660 
661         Application's short usage description (as a format string).
662 
663         This is used as a format string to print the usage. The first parameter
664         to the format string is the application's name. This string should
665         describe how to invoke the application.
666 
667         If the usage description spans multiple lines, then it's better to start
668         each line with a tab character (\t).
669 
670         Examples:
671 
672         ---
673 
674             args.usage = "{0} [OPTIONS] SOMETHING FILE";
675             args.usage = "{0} [OPTIONS] SOMETHING FILE\n"
676                          "\t{0} --version";
677 
678         ---
679 
680     ***************************************************************************/
681 
682     public istring usage = "{0} [OPTIONS] [ARGS]";
683 
684 
685     /***************************************************************************
686 
687         One line description of what the application does (as a format string).
688 
689         This is used as a format string to print a short description of what the
690         application does. The first argument is the name of the application (but
691         the name shouldn't normally be used in the description).
692 
693     ***************************************************************************/
694 
695     public istring short_desc;
696 
697 
698     /***************************************************************************
699 
700         Long description about the application and how to use it (as a format
701         string).
702 
703         This is used as a format string to print a long description of what the
704         application does and how to use it. The first argument is the name of
705         the application.
706 
707     ***************************************************************************/
708 
709     public istring long_desc;
710 
711 
712     /***************************************************************************
713 
714         Stack used to help in assigning implicitly assigned parameters to
715         arguments during parsing.
716 
717         This stack contains argument instances of only those arguments that can
718         have one or more associated parameters. Implicit parameters always get
719         assigned to the topmost argument in the stack. Once the number of
720         parameters of the topmost argument in the stack reaches its maximum
721         configured value, that argument gets popped off the stack. Future
722         implicit assignments will then happen to the new topmost argument in the
723         stack.
724 
725         The null argument is always the first one that gets pushed onto the
726         stack. This ensures that it is able to "catch" all unclaimed parameters
727         at the end.
728 
729     ***************************************************************************/
730 
731     private Stack!(Argument) stack;
732 
733 
734     /***************************************************************************
735 
736         All argument instances. A sorted map (indexed by the argument name) is
737         used to store these so that the arguments appear in a sorted manner in
738         the help text output
739 
740     ***************************************************************************/
741 
742     private SortedMap!(cstring, Argument) args;
743 
744 
745     /***************************************************************************
746 
747         Argument instances that have aliases. A sorted map (indexed by the
748         argument aliases) is used to store these so that the arguments appear in
749         a sorted manner in the help text output
750 
751     ***************************************************************************/
752 
753     private SortedMap!(cstring, Argument) aliases;
754 
755 
756     /***************************************************************************
757 
758         Character to be used as the explicit assignment symbol
759 
760     ***************************************************************************/
761 
762     private char eq;
763 
764 
765     /***************************************************************************
766 
767         The short prefix string
768 
769     ***************************************************************************/
770 
771     private istring sp;
772 
773 
774     /***************************************************************************
775 
776         The long prefix string
777 
778     ***************************************************************************/
779 
780     private istring lp;
781 
782 
783     /***************************************************************************
784 
785         Error messages
786 
787     ***************************************************************************/
788 
789     private Const!(istring)[] msgs;
790 
791 
792     /***************************************************************************
793 
794         Format strings of all default errors
795 
796     ***************************************************************************/
797 
798     private static immutable istring[] errmsg = [
799         "argument '{0}' expects {2} parameter(s) but has {1}\n",
800         "argument '{0}' expects {3} parameter(s) but has {1}\n",
801         "argument '{0}' is missing\n",
802         "argument '{0}' requires '{4}'\n",
803         "argument '{0}' conflicts with '{4}'\n",
804         "unexpected argument '{0}'\n",
805         "argument '{0}' expects one of {5}\n",
806         "invalid parameter for argument '{0}': {4}\n",
807     ];
808 
809 
810     /***************************************************************************
811 
812         Internal string used for spacing of the full help message
813 
814     ***************************************************************************/
815 
816     private mstring spaces;
817 
818 
819     /***************************************************************************
820 
821         Temporary formatting buffer
822 
823     ***************************************************************************/
824 
825     private mstring tmp_buf;
826 
827 
828     /***************************************************************************
829 
830         Maximum width of the column showing argument aliases in the full help
831         message
832 
833     ***************************************************************************/
834 
835     private size_t aliases_width;
836 
837 
838     /***************************************************************************
839 
840         Maximum width of the column showing argument names in the full help
841         message
842 
843     ***************************************************************************/
844 
845     private size_t long_name_width;
846 
847 
848     /***************************************************************************
849 
850         Constructor.
851 
852         Params:
853             app_name = name of the application (to show in the help message)
854             short_desc = short description of what the application does (should
855                 be one line only, preferably less than 80 characters long)
856             usage = how the application is supposed to be invoked
857             long_desc = long description of what the application does and how to
858                 use it
859             sp = string to use as the short prefix (defaults to '-')
860             lp = string to use as the long prefix (defaults to '--')
861             eq = character to use as the explicit assignment symbol
862                  (defaults to '=')
863 
864     ***************************************************************************/
865 
866     public this ( istring app_name = null, istring short_desc = null,
867         istring usage = null, istring long_desc = null, istring sp = "-",
868         istring lp = "--", char eq = '=' )
869     {
870         this.msgs = this.errmsg;
871 
872         this.app_name = app_name;
873         this.short_desc = short_desc;
874         this.long_desc = long_desc;
875         this.sp = sp;
876         this.lp = lp;
877         this.eq = eq;
878 
879         this.args = new typeof(this.args)();
880         this.aliases = new typeof(this.aliases)();
881 
882         if ( usage.length > 0 )
883         {
884             this.usage = usage;
885         }
886 
887         this.get(null).params; // set null argument to consume params
888     }
889 
890 
891     /***************************************************************************
892 
893         Parses the command-line arguments into a set of Argument instances. The
894         command-line arguments are expected to be passed in a string.
895 
896         Params:
897             input = string to be parsed (contains command-line arguments)
898             sloppy = true if any unexpected arguments found during parsing
899                 should be accepted on-the-fly, false if unexpected arguments
900                 should be treated as error
901 
902         Returns:
903             true if parsing was successful, false otherwise
904 
905     ***************************************************************************/
906 
907     public bool parse ( istring input, bool sloppy = false )
908     {
909         istring[] tmp;
910 
911         foreach ( s; quotes(input, " ") )
912         {
913             tmp ~= s;
914         }
915 
916         return parse(tmp, sloppy);
917     }
918 
919 
920     /***************************************************************************
921 
922         Parses the command-line arguments into a set of Argument instances. The
923         command-line arguments are expected to be passed in an array of strings.
924 
925         Params:
926             input = array of strings to be parsed (contains command-line
927                 arguments)
928             sloppy = true if any unexpected arguments found during parsing
929                 should be accepted on-the-fly, false if unexpected arguments
930                 should be treated as error
931 
932         Returns:
933             true if parsing was successful, false otherwise
934 
935     ***************************************************************************/
936 
937     public bool parse ( Const!(istring)[] input, bool sloppy = false )
938     {
939         bool done;
940         int error;
941 
942         stack.push(this.get(null));
943 
944         foreach ( s; input )
945         {
946             if ( done is false )
947             {
948                 if ( s == "--" )
949                 {
950                     done = true;
951 
952                     stack.clear.push(this.get(null));
953 
954                     continue;
955                 }
956                 else
957                 {
958                     if ( argument(s, lp, sloppy, false) ||
959                          argument(s, sp, sloppy, true) )
960                     {
961                         continue;
962                     }
963                 }
964             }
965 
966             stack.top.append (s);
967         }
968 
969         foreach ( arg; args )
970         {
971             error |= arg.valid;
972         }
973 
974         return error is 0;
975     }
976 
977 
978     /***************************************************************************
979 
980         Unsets all configured arguments (as if they weren't given at all on the
981         command-line), clears all parameters that may have been assigned to
982         arguments and also clears any parsing errors that may have been
983         associated with any argument(s).
984 
985         Note that configured arguments are *not* removed.
986 
987         Returns:
988             this object for method chaining
989 
990     ***************************************************************************/
991 
992     public Arguments clear ( )
993     {
994         stack.clear;
995 
996         foreach ( arg; args )
997         {
998             arg.set = false;
999             arg.values = null;
1000             arg.error = arg.None;
1001         }
1002 
1003         return this;
1004     }
1005 
1006 
1007     /***************************************************************************
1008 
1009         Gets a reference to an argument, creating a new instance if necessary.
1010 
1011         Params:
1012             name = character representing the argument to be retrieved (this is
1013                 usually an alias to the argument, but could also be the argument
1014                 name if the argument name is exactly one character long)
1015 
1016         Returns:
1017             a reference to the argument
1018 
1019     ***************************************************************************/
1020 
1021     public Argument get ( char name )
1022     {
1023         return get(cast(cstring)(&name)[0 .. 1]);
1024     }
1025 
1026 
1027     /***************************************************************************
1028 
1029         Gets a reference to an argument, creating a new instance if necessary.
1030 
1031         Params:
1032             name = string containing the argument name (pass null to access the
1033                 special 'null' argument)
1034 
1035         Returns:
1036             a reference to the argument
1037 
1038     ***************************************************************************/
1039 
1040     public Argument get ( cstring name )
1041     {
1042         auto a = name in args;
1043 
1044         if ( a is null )
1045         {
1046             auto _name = idup(name);
1047 
1048             auto arg = new Argument(_name);
1049 
1050             args[_name] = arg;
1051 
1052             return arg;
1053         }
1054 
1055         return *a;
1056     }
1057 
1058 
1059     /***************************************************************************
1060 
1061         Enables 'foreach' iteration over the set of configured arguments.
1062 
1063         Params:
1064             dg = delegate called for each argument
1065 
1066     ***************************************************************************/
1067 
1068     public int opApply ( scope int delegate(ref Argument) dg )
1069     {
1070         int result;
1071 
1072         foreach ( arg; args )
1073         {
1074             if ( (result = dg(arg)) != 0 )
1075             {
1076                 break;
1077             }
1078         }
1079 
1080         return result;
1081     }
1082 
1083     /***************************************************************************
1084 
1085         Constructs a string of error messages.
1086 
1087         Returns:
1088             formatted error message string
1089 
1090     ***************************************************************************/
1091 
1092     public istring errors ()
1093     {
1094         mstring result;
1095 
1096         foreach (arg; args)
1097         {
1098             if (arg.error)
1099             {
1100                 sformat(
1101                     result, msgs[arg.error-1], arg.name,
1102                     arg.values.length, arg.min, arg.max, arg.bogus,
1103                     arg.options);
1104             }
1105         }
1106 
1107         return assumeUnique(result);
1108     }
1109 
1110 
1111     /***************************************************************************
1112 
1113         Replaces the default error messages with the given string.
1114         Note that arguments are passed to the formatter in the following order,
1115         and these should be indexed appropriately by each of the error messages
1116         (see the 'errmsg' variable for the format string):
1117 
1118             index 0: the argument name
1119             index 1: number of parameters
1120             index 2: configured minimum parameters
1121             index 3: configured maximum parameters
1122             index 4: conflicting/dependent argument (or invalid param)
1123             index 5: array of configured parameter options
1124 
1125         Params:
1126             errors = string to replace the default error messages with
1127 
1128         Returns:
1129             this object for method chaining
1130 
1131     ***************************************************************************/
1132 
1133     public Arguments errors ( Const!(istring)[] errors )
1134     {
1135         if ( errors.length is errmsg.length )
1136         {
1137             msgs = errors;
1138         }
1139         else
1140         {
1141             verify(false);
1142         }
1143 
1144         return this;
1145     }
1146 
1147 
1148     /***************************************************************************
1149 
1150         Exposes the configured help text for each of the configured arguments,
1151         via the given delegate. Note that the delegate will be called only for
1152         those arguments for which a help text has been configured.
1153 
1154         Params:
1155             dg = delegate that will be called for each argument having a help
1156                 text (the argument name and the help text itself will be sent as
1157                 parameters to the delegate)
1158 
1159         Returns:
1160             this object for method chaining
1161 
1162     ***************************************************************************/
1163 
1164     public Arguments help ( scope void delegate ( istring arg, istring help ) dg )
1165     {
1166         foreach ( arg; args )
1167         {
1168             if ( arg.text.ptr )
1169             {
1170                 dg(arg.name, arg.text);
1171             }
1172         }
1173 
1174         return this;
1175     }
1176 
1177 
1178     /***************************************************************************
1179 
1180         Displays the full help message for the application.
1181 
1182         Params:
1183             output = stream where to print the help message (Stderr by default)
1184 
1185     ***************************************************************************/
1186 
1187     public void displayHelp ( FormatOutput output = Stderr )
1188     {
1189         if ( this.short_desc.length > 0 )
1190         {
1191             output.formatln(this.short_desc, this.app_name);
1192             output.newline;
1193         }
1194 
1195         output.formatln("Usage:\t" ~ this.usage, this.app_name);
1196         output.newline;
1197 
1198         if ( this.long_desc.length > 0 )
1199         {
1200             output.formatln(this.long_desc, this.app_name);
1201             output.newline;
1202         }
1203 
1204         foreach ( arg; this.args )
1205         {
1206             this.calculateSpacing(arg);
1207         }
1208 
1209         output.formatln("Program options:");
1210 
1211         foreach ( arg; this.args )
1212         {
1213             // Skip the null argument
1214             if ( arg.name.length == 0 )
1215             {
1216                 continue;
1217             }
1218 
1219             output.formatln("{}", this.formatArgumentHelp(arg, this.tmp_buf));
1220         }
1221 
1222         output.newline;
1223     }
1224 
1225 
1226     /***************************************************************************
1227 
1228         Displays any errors that occurred.
1229 
1230         Params:
1231             output = stream where to print the errors (Stderr by default)
1232 
1233     ***************************************************************************/
1234 
1235     public void displayErrors ( FormatOutput output = Stderr )
1236     {
1237         output.format("{}", this.errors());
1238     }
1239 
1240 
1241     /***************************************************************************
1242 
1243         Convenience method to check whether an argument is set or not (i.e.
1244         whether it was found during parsing of the command-line arguments).
1245 
1246         Params:
1247             name = name of the argument
1248 
1249         Returns:
1250             true if the argument is set, false otherwise
1251 
1252     ***************************************************************************/
1253 
1254     public bool getBool ( cstring name )
1255     {
1256         auto arg = this.get(name);
1257 
1258         if ( arg )
1259         {
1260             return arg.set;
1261         }
1262         else
1263         {
1264             return false;
1265         }
1266     }
1267 
1268 
1269     /***************************************************************************
1270 
1271         Convenience method to get the integer value of the parameter assigned to
1272         an argument. This is valid only if the argument has been assigned
1273         exactly one parameter.
1274 
1275         Params:
1276             T = type of integer to return
1277             name = name of the argument
1278 
1279         Returns:
1280             integer value of the parameter assigned to the argument
1281             0 if value is missing or not a valid integer
1282 
1283     ***************************************************************************/
1284 
1285     public T getInt ( T ) ( cstring name )
1286     {
1287         auto arg = this.get(name);
1288 
1289         cstring value;
1290 
1291         if ( arg && arg.assigned.length == 1 )
1292         {
1293             value = arg.assigned[0];
1294         }
1295 
1296         T num;
1297         if (toInteger(value, num))
1298             return num;
1299         else
1300             return 0;
1301     }
1302 
1303 
1304     /***************************************************************************
1305 
1306         Convenience method to get the string parameter assigned to an argument.
1307         This is valid only if the argument has been assigned exactly one
1308         parameter.
1309 
1310         Params:
1311             name = name of the argument
1312 
1313         Returns:
1314             parameter assigned to the argument
1315 
1316     ***************************************************************************/
1317 
1318     public istring getString ( cstring name )
1319     {
1320         auto arg = this.get(name);
1321 
1322         istring value;
1323 
1324         if ( arg && arg.assigned.length == 1 )
1325         {
1326             value = arg.assigned[0];
1327         }
1328 
1329         return value;
1330     }
1331 
1332 
1333     /***************************************************************************
1334 
1335         Tests for the presence of a switch (long/short prefix) and enables the
1336         associated argument if found. Also looks for and handles explicit
1337         parameter assignment.
1338 
1339         Params:
1340             s = An individual string from the command-line arguments (includes
1341                 the long/short prefix if it is an argument string)
1342             p = the prefix string (whether this is the long prefix or the short
1343                 prefix is indicated by the 'flag' parameter)
1344             sloppy = true if any unexpected arguments found during parsing
1345                 should be accepted on-the-fly, false if unexpected arguments
1346                 should be treated as error
1347             flag = true if the prefix string given is the short prefix, false if
1348                 it is the long prefix
1349 
1350         Returns:
1351             true if the given string was an argument, false if it was a
1352             parameter
1353 
1354     ***************************************************************************/
1355 
1356     private bool argument ( istring s, istring p, bool sloppy, bool flag )
1357     {
1358         if ( s.length >= p.length && s[0 .. p.length] == p )
1359         {
1360             s = s[p.length .. $];
1361 
1362             auto i = locate(s, eq);
1363 
1364             if ( i < s.length )
1365             {
1366                 enable(s[0 .. i], sloppy, flag).append(s[i + 1 .. $], true);
1367             }
1368             else
1369             {
1370                 // trap empty arguments; attach as param to null-arg
1371                 if ( s.length )
1372                 {
1373                     enable(s, sloppy, flag);
1374                 }
1375                 else
1376                 {
1377                     this.get(null).append(p, true);
1378                 }
1379             }
1380 
1381             return true;
1382         }
1383 
1384         return false;
1385     }
1386 
1387 
1388     /***************************************************************************
1389 
1390         Indicates the existence of an argument, and handles sloppy arguments
1391         along with multiple-flags and smushed parameters. Note that sloppy
1392         arguments are configured with parameters enabled.
1393 
1394         Params:
1395             elem = an argument name found during parsing (does not contain the
1396                 long/short prefix)
1397             sloppy = true if any unexpected arguments found during parsing
1398                 should be accepted on-the-fly, false if unexpected arguments
1399                 should be treated as error
1400             flag = true if the argument name was preceded by the short prefix,
1401                 false if it was preceded by the long prefix
1402 
1403         Returns:
1404             the configured argument instance
1405 
1406     ***************************************************************************/
1407 
1408     private Argument enable ( istring elem, bool sloppy, bool flag = false )
1409     {
1410         if ( flag && elem.length > 1 )
1411         {
1412             // locate arg for first char
1413             auto arg = enable(elem[0 .. 1], sloppy);
1414 
1415             elem = elem[1 .. $];
1416 
1417             // drop further processing of this flag where in error
1418             if ( arg.error is arg.None )
1419             {
1420                 // smush remaining text or treat as additional args
1421                 if ( arg.cat )
1422                 {
1423                     arg.append(elem, true);
1424                 }
1425                 else
1426                 {
1427                     arg = enable(elem, sloppy, true);
1428                 }
1429             }
1430 
1431             return arg;
1432         }
1433 
1434         // if not in args, or in aliases, then create new arg
1435         auto a = elem in args;
1436 
1437         if ( a is null )
1438         {
1439             if ( (a = elem in aliases) is null )
1440             {
1441                 return this.get(elem).params.enable(!sloppy);
1442             }
1443         }
1444 
1445         return a.enable;
1446     }
1447 
1448 
1449     /***************************************************************************
1450 
1451         Calculates the width required to display all the aliases based on the
1452         given number of aliases (in the aliases string, each character is an
1453         individual argument alias).
1454 
1455         Params:
1456             aliases = number of argument aliases
1457 
1458         Returns:
1459             width required to display all the aliases
1460 
1461     ***************************************************************************/
1462 
1463     private size_t aliasesWidth ( size_t aliases )
1464     {
1465         auto width = aliases * 2; // *2 for a '-' before each alias
1466 
1467         if ( aliases > 1 )
1468         {
1469             width += (aliases - 1) * 2; // ', ' after each alias except the last
1470         }
1471 
1472         return width;
1473     }
1474 
1475 
1476     /***************************************************************************
1477 
1478         Calculates the maximum width required to display the given argument name
1479         and its aliases.
1480 
1481         Params:
1482             arg = the argument instance
1483 
1484     ***************************************************************************/
1485 
1486     private void calculateSpacing ( Argument arg )
1487     {
1488         this.long_name_width = max(this.long_name_width, arg.name.length);
1489 
1490         this.aliases_width = max(this.aliases_width,
1491             this.aliasesWidth(arg.aliases.length));
1492     }
1493 
1494 
1495     /***************************************************************************
1496 
1497         Formats the help text for a single argument.
1498 
1499         Params:
1500             arg = argument instance for which the help text is to be formatted
1501             buf = buffer into which to format the help text
1502 
1503         Returns:
1504             the formatted help text
1505 
1506     ***************************************************************************/
1507 
1508     private mstring formatArgumentHelp ( Argument arg, ref mstring buf )
1509     {
1510         buf.length = 0;
1511         enableStomping(buf);
1512 
1513         sformat(buf, "  ");
1514 
1515         foreach ( i, al; arg.aliases )
1516         {
1517             sformat(buf, "-{}", al);
1518 
1519             if ( i != arg.aliases.length - 1 || arg.name.length )
1520             {
1521                 sformat(buf, ", ");
1522             }
1523         }
1524 
1525         // there is no trailing ", " in this case, so add two spaces instead.
1526         if ( arg.aliases.length == 0 )
1527         {
1528             sformat(buf, "  ");
1529         }
1530 
1531         sformat(buf, "{}",
1532             this.space(this.aliases_width -
1533                        this.aliasesWidth(arg.aliases.length)));
1534 
1535         sformat(buf, "--{}{}  ",
1536             arg.name, this.space(this.long_name_width - arg.name.length));
1537 
1538         if ( arg.text.length )
1539         {
1540             sformat(buf, "{}", arg.text);
1541         }
1542 
1543         uint extras;
1544 
1545         bool params = arg.min > 0 || arg.max > 0;
1546 
1547         if ( params )              extras++;
1548         if ( arg.options.length )  extras++;
1549         if ( arg.deefalts.length ) extras++;
1550 
1551         if ( extras )
1552         {
1553             // comma separate sections if more info to come
1554             void next ( )
1555             {
1556                 extras--;
1557 
1558                 if ( extras )
1559                 {
1560                     sformat(buf, ", ");
1561                 }
1562             }
1563 
1564             sformat(buf, " (");
1565 
1566             if ( params )
1567             {
1568                 if ( arg.min == arg.max )
1569                 {
1570                     sformat(buf, "{} param{}", arg.min,
1571                         arg.min == 1 ? "" : "s");
1572                 }
1573                 else
1574                 {
1575                     sformat(buf, "{}-{} params", arg.min, arg.max);
1576                 }
1577 
1578                 next();
1579             }
1580 
1581             if ( arg.options.length )
1582             {
1583                 sformat(buf, "{}", arg.options);
1584 
1585                 next();
1586             }
1587 
1588             if ( arg.deefalts.length )
1589             {
1590                 sformat(buf, "default: {}", arg.deefalts);
1591 
1592                 next();
1593             }
1594 
1595             sformat(buf, ")");
1596         }
1597 
1598         return buf;
1599     }
1600 
1601 
1602     /***************************************************************************
1603 
1604         Creates a string with the specified number of spaces.
1605 
1606         Params:
1607             width = desired number of spaces
1608 
1609         Returns:
1610             string with desired number of spaces.
1611 
1612     ***************************************************************************/
1613 
1614     private cstring space ( size_t width )
1615     {
1616         if ( width == 0 )
1617         {
1618             return "";
1619         }
1620 
1621         this.spaces.length = width;
1622         enableStomping(this.spaces);
1623 
1624         this.spaces[] = ' ';
1625 
1626         return this.spaces;
1627     }
1628 
1629 
1630     /***************************************************************************
1631 
1632         Class that declares a specific argument instance.
1633         One of these is instantiated using one of the outer class' `get()`
1634         methods. All existing argument instances can be iterated over using the
1635         outer class' `opApply()` method.
1636 
1637     ***************************************************************************/
1638 
1639     private class Argument
1640     {
1641         /***********************************************************************
1642 
1643             Enumeration of all error identifiers
1644 
1645         ***********************************************************************/
1646 
1647         public enum
1648         {
1649             None,     // ok (no error)
1650 
1651             ParamLo,  // too few parameters were assigned to this argument
1652 
1653             ParamHi,  // too many parameters were assigned to this argument
1654 
1655             Required, // this is a required argument, but was not given
1656 
1657             Requires, // this argument depends on another argument which was not
1658                       // given
1659 
1660             Conflict, // this argument conflicts with another given argument
1661 
1662             Extra,    // unexpected argument (will not trigger an error if
1663                       // sloppy arguments are enabled)
1664 
1665             Option,   // parameter assigned is not one of the acceptable options
1666 
1667             Invalid   // invalid error
1668         }
1669 
1670 
1671         /***********************************************************************
1672 
1673             Convenience aliases
1674 
1675         ***********************************************************************/
1676 
1677         public alias void    delegate ( )               Invoker;
1678         public alias istring delegate ( istring value ) Inspector;
1679 
1680 
1681         /***********************************************************************
1682 
1683             Minimum number of parameters for this argument
1684 
1685         ***********************************************************************/
1686 
1687         public int min;
1688 
1689 
1690         /***********************************************************************
1691 
1692             Maximum number of parameters for this argument
1693 
1694         ***********************************************************************/
1695 
1696         public int max;
1697 
1698 
1699         /***********************************************************************
1700 
1701             The error code for this argument (0 => no error)
1702 
1703         ***********************************************************************/
1704 
1705         public int error;
1706 
1707 
1708         /***********************************************************************
1709 
1710             Flag to indicate whether this argument is present or not
1711 
1712         ***********************************************************************/
1713 
1714         public bool set;
1715 
1716 
1717         /***********************************************************************
1718 
1719             String in which each character is an alias for this argument
1720 
1721         ***********************************************************************/
1722 
1723         public istring aliases;
1724 
1725 
1726         /***********************************************************************
1727 
1728             The name of the argument
1729 
1730         ***********************************************************************/
1731 
1732         public istring name;
1733 
1734 
1735         /***********************************************************************
1736 
1737             The help text of the argument
1738 
1739         ***********************************************************************/
1740 
1741         public istring text;
1742 
1743 
1744         /***********************************************************************
1745 
1746             Allowed parameters for this argument (there is no restriction on the
1747             acceptable parameters if this array is empty)
1748 
1749         ***********************************************************************/
1750 
1751         public Const!(istring)[] options;
1752 
1753 
1754         /***********************************************************************
1755 
1756             Default parameters for this argument
1757 
1758         ***********************************************************************/
1759 
1760         public Const!(istring)[] deefalts;
1761 
1762 
1763         /***********************************************************************
1764 
1765             Flag to indicate whether this argument is required or not
1766 
1767         ***********************************************************************/
1768 
1769         private bool req;
1770 
1771 
1772         /***********************************************************************
1773 
1774             Flag to indicate whether this argument is smushable or not
1775 
1776         ***********************************************************************/
1777 
1778         private bool cat;
1779 
1780 
1781         /***********************************************************************
1782 
1783             Flag to indicate whether this argument can accept implicit
1784             parameters or not
1785 
1786         ***********************************************************************/
1787 
1788         private bool exp;
1789 
1790 
1791         /***********************************************************************
1792 
1793             Flag to indicate whether this argument has failed parsing or not
1794 
1795         ***********************************************************************/
1796 
1797         private bool fail;
1798 
1799 
1800         /***********************************************************************
1801 
1802             The name of the argument that conflicts with this argument
1803 
1804         ***********************************************************************/
1805 
1806         private istring bogus;
1807 
1808 
1809         /***********************************************************************
1810 
1811             Parameters assigned to this argument
1812 
1813         ***********************************************************************/
1814 
1815         private istring[] values;
1816 
1817 
1818         /***********************************************************************
1819 
1820             Invocation callback
1821 
1822         ***********************************************************************/
1823 
1824         private Invoker invoker;
1825 
1826 
1827         /***********************************************************************
1828 
1829             Inspection callback
1830 
1831         ***********************************************************************/
1832 
1833         private Inspector inspector;
1834 
1835 
1836         /***********************************************************************
1837 
1838             Argument instances that are required by this argument
1839 
1840         ***********************************************************************/
1841 
1842         private Argument[] dependees;
1843 
1844 
1845         /***********************************************************************
1846 
1847             Argument instances that this argument conflicts with
1848 
1849         ***********************************************************************/
1850 
1851         private Argument[] conflictees;
1852 
1853 
1854         /***********************************************************************
1855 
1856             Constructor.
1857 
1858             Params:
1859                 name = name of the argument
1860 
1861         ***********************************************************************/
1862 
1863         public this ( istring name )
1864         {
1865             this.name = name;
1866         }
1867 
1868 
1869         /***********************************************************************
1870 
1871             Returns:
1872                 the name of this argument
1873 
1874         ***********************************************************************/
1875 
1876         public override istring toString ( )
1877         {
1878             return name;
1879         }
1880 
1881 
1882         /***********************************************************************
1883 
1884             Returns:
1885                 parameters assigned to this argument, or the default parameters
1886                 if this argument was not present on the command-line
1887 
1888         ***********************************************************************/
1889 
1890         public Const!(istring)[] assigned ( )
1891         {
1892             return values.length ? values : deefalts;
1893         }
1894 
1895 
1896         /***********************************************************************
1897 
1898             Sets an alias for this argument.
1899 
1900             Params:
1901                 name = character to be used as an alias for this argument
1902 
1903             Returns:
1904                 this object for method chaining
1905 
1906         ***********************************************************************/
1907 
1908         public Argument aliased ( char name )
1909         {
1910             if ( auto arg = cast(cstring)((&name)[0..1]) in this.outer.aliases )
1911             {
1912                 verify(
1913                     false,
1914                     "Argument '" ~ this.name ~ "' cannot " ~
1915                         "be assigned alias '" ~ name ~ "' as it has " ~
1916                         "already been assigned to argument '"
1917                         ~ arg.name ~ "'."
1918                 );
1919             }
1920 
1921             this.outer.aliases[idup((&name)[0 .. 1])] = this;
1922 
1923             this.aliases ~= name;
1924 
1925             return this;
1926         }
1927 
1928 
1929         /***********************************************************************
1930 
1931             Makes this a mandatory argument.
1932 
1933             Returns:
1934                 this object for method chaining
1935 
1936         ***********************************************************************/
1937 
1938         public Argument required ( )
1939         {
1940             this.req = true;
1941 
1942             return this;
1943         }
1944 
1945 
1946         /***********************************************************************
1947 
1948             Sets this argument to depend upon another argument.
1949 
1950             Params:
1951                 arg = argument instance which is to be set as a dependency
1952 
1953             Returns:
1954                 this object for method chaining
1955 
1956         ***********************************************************************/
1957 
1958         public Argument requires ( Argument arg )
1959         {
1960             dependees ~= arg;
1961 
1962             return this;
1963         }
1964 
1965 
1966         /***********************************************************************
1967 
1968             Sets this argument to depend upon another argument.
1969 
1970             Params:
1971                 other = name of the argument which is to be set as a dependency
1972 
1973             Returns:
1974                 this object for method chaining
1975 
1976         ***********************************************************************/
1977 
1978         public Argument requires ( istring other )
1979         {
1980             return requires(this.outer.get(other));
1981         }
1982 
1983 
1984         /***********************************************************************
1985 
1986             Sets this argument to depend upon another argument.
1987 
1988             Params:
1989                 other = alias of the argument which is to be set as a dependency
1990 
1991             Returns:
1992                 this object for method chaining
1993 
1994         ***********************************************************************/
1995 
1996         public Argument requires ( char other )
1997         {
1998             return requires(cast(istring)(&other)[0 .. 1]);
1999         }
2000 
2001 
2002         /***********************************************************************
2003 
2004             Sets this argument to conflict with another argument.
2005 
2006             Params:
2007                 arg = argument instance with which this argument should conflict
2008 
2009             Returns:
2010                 this object for method chaining
2011 
2012         ***********************************************************************/
2013 
2014         public Argument conflicts ( Argument arg )
2015         {
2016             conflictees ~= arg;
2017 
2018             return this;
2019         }
2020 
2021 
2022         /***********************************************************************
2023 
2024             Sets this argument to conflict with another argument.
2025 
2026             Params:
2027                 other = name of the argument with which this argument should
2028                     conflict
2029 
2030             Returns:
2031                 this object for method chaining
2032 
2033         ***********************************************************************/
2034 
2035         public Argument conflicts ( istring other )
2036         {
2037             return conflicts(this.outer.get(other));
2038         }
2039 
2040 
2041         /***********************************************************************
2042 
2043             Sets this argument to conflict with another argument.
2044 
2045             Params:
2046                 other = alias of the argument with which this argument should
2047                     conflict
2048 
2049             Returns:
2050                 this object for method chaining
2051 
2052         ***********************************************************************/
2053 
2054         public Argument conflicts ( char other )
2055         {
2056             return conflicts(cast(istring)(&other)[0 .. 1]);
2057         }
2058 
2059 
2060         /***********************************************************************
2061 
2062             Enables parameter assignment for this argument. The minimum and
2063             maximum number of parameters are set to 0 and 42 respectively.
2064 
2065             Returns:
2066                 this object for method chaining
2067 
2068         ***********************************************************************/
2069 
2070         public Argument params ( )
2071         {
2072             return params(0, 42);
2073         }
2074 
2075 
2076         /***********************************************************************
2077 
2078             Enables parameter assignment for this argument and sets an exact
2079             count for the number of parameters required.
2080 
2081             Params:
2082                 count = the number of parameters to be set
2083 
2084             Returns:
2085                 this object for method chaining
2086 
2087         ***********************************************************************/
2088 
2089         public Argument params ( int count )
2090         {
2091             return params(count, count);
2092         }
2093 
2094 
2095         /***********************************************************************
2096 
2097             Enables parameter assignment for this argument and sets the counts
2098             of both the minimum and maximum parameters required.
2099 
2100             Params:
2101                 min = minimum number of parameters required
2102                 max = maximum number of parameters required
2103 
2104             Returns:
2105                 this object for method chaining
2106 
2107         ***********************************************************************/
2108 
2109         public Argument params ( int min, int max )
2110         {
2111             this.min = min;
2112 
2113             this.max = max;
2114 
2115             return this;
2116         }
2117 
2118 
2119         /***********************************************************************
2120 
2121             Adds a default parameter for this argument.
2122 
2123             Params:
2124                 values = default parameter to be added
2125 
2126             Returns:
2127                 this object for method chaining
2128 
2129         ***********************************************************************/
2130 
2131         public Argument defaults ( istring values )
2132         {
2133             this.deefalts ~= values;
2134 
2135             return this;
2136         }
2137 
2138 
2139         /***********************************************************************
2140 
2141             Sets an inspector for this argument. The inspector delegate gets
2142             fired when a parameter is appended to this argument.
2143             The appended parameter gets sent to the delegate as the input
2144             parameter. If the appended parameter is ok, the delegate should
2145             return null. Otherwise, it should return a text string describing
2146             the issue. A non-null return value from the delegate will trigger an
2147             error.
2148 
2149             Params:
2150                 inspector = delegate to be called when a parameter is appended
2151                     to this argument
2152 
2153             Returns:
2154                 this object for method chaining
2155 
2156         ***********************************************************************/
2157 
2158         public Argument bind ( scope Inspector inspector )
2159         {
2160             this.inspector = inspector;
2161 
2162             return this;
2163         }
2164 
2165 
2166         /***********************************************************************
2167 
2168             Sets an invoker for this argument. The invoker delegate gets
2169             fired when this argument is found during parsing.
2170 
2171             Params:
2172                 invoker = delegate to be called when this argument's declaration
2173                     is seen
2174 
2175             Returns:
2176                 this object for method chaining
2177 
2178         ***********************************************************************/
2179 
2180         public Argument bind ( scope Invoker invoker )
2181         {
2182             this.invoker = invoker;
2183 
2184             return this;
2185         }
2186 
2187 
2188         /***********************************************************************
2189 
2190             Enables/disables smushing for this argument.
2191 
2192             Smushing refers to omitting the explicit assignment symbol ('=' by
2193             default) or whitespace (when relying on implicit assignment) that
2194             separates an argument from its parameter. Note that smushing is
2195             possible only when assigning parameters to an argument using the
2196             argument's short prefix version.
2197 
2198             Params:
2199                 yes = true to enable smushing, false to disable
2200 
2201             Returns:
2202                 this object for method chaining
2203 
2204         ***********************************************************************/
2205 
2206         public Argument smush ( bool yes = true )
2207         {
2208             cat = yes;
2209 
2210             return this;
2211         }
2212 
2213 
2214         /***********************************************************************
2215 
2216             Disables implicit parameter assignment to this argument.
2217 
2218             Returns:
2219                 this object for method chaining
2220 
2221         ***********************************************************************/
2222 
2223         public Argument explicit ( )
2224         {
2225             exp = true;
2226 
2227             return this;
2228         }
2229 
2230 
2231         /***********************************************************************
2232 
2233             Changes the name of this argument (can be useful for naming the
2234             default argument).
2235 
2236             Params:
2237                 name = new name of this argument
2238 
2239             Returns:
2240                 this object for method chaining
2241 
2242         ***********************************************************************/
2243 
2244         public Argument title ( istring name )
2245         {
2246             this.name = name;
2247 
2248             return this;
2249         }
2250 
2251 
2252         /***********************************************************************
2253 
2254             Sets the help text for this argument.
2255 
2256             Params:
2257                 text = the help text to set
2258 
2259             Returns:
2260                 this object for method chaining
2261 
2262         ***********************************************************************/
2263 
2264         public Argument help ( istring text )
2265         {
2266             this.text = text;
2267 
2268             return this;
2269         }
2270 
2271 
2272         /***********************************************************************
2273 
2274             Fails the parsing immediately upon encountering this argument. This
2275             can be used for managing help text.
2276 
2277             Returns:
2278                 this object for method chaining
2279 
2280         ***********************************************************************/
2281 
2282         public Argument halt ( )
2283         {
2284             this.fail = true;
2285 
2286             return this;
2287         }
2288 
2289 
2290         /***********************************************************************
2291 
2292             Restricts parameters of this argument to be in the given set.
2293 
2294             Allocates copy of `options`
2295 
2296             Params:
2297                 options = array containing the set of acceptable parameters
2298 
2299             Returns:
2300                 this object for method chaining
2301 
2302         ***********************************************************************/
2303 
2304         public Argument restrict ( Const!(istring)[] options... )
2305         {
2306             this.options = options.dup;
2307 
2308             return this;
2309         }
2310 
2311 
2312         /***********************************************************************
2313 
2314             Sets the flag that indicates that this argument was found during
2315             parsing. Also calls the invoker delegate, if configured. If the
2316             argument is unexpected (i.e. was not pre-configured), then an
2317             appropriate error condition gets set.
2318 
2319             Params:
2320                 unexpected = true if this is an unexpected argument, false
2321                     otherwise
2322 
2323             Returns:
2324                 this object for method chaining
2325 
2326         ***********************************************************************/
2327 
2328         private Argument enable ( bool unexpected = false )
2329         {
2330             this.set = true;
2331 
2332             if ( max > 0 )
2333             {
2334                 this.outer.stack.push(this);
2335             }
2336 
2337             if ( invoker )
2338             {
2339                 invoker();
2340             }
2341 
2342             if ( unexpected )
2343             {
2344                 error = Extra;
2345             }
2346 
2347             return this;
2348         }
2349 
2350 
2351         /***********************************************************************
2352 
2353             Appends the given parameter to this argument. Also calls the
2354             inspector delegate, if configured.
2355 
2356             Params:
2357                 value = parameter to be appended
2358                 explicit = true if the parameter was explicitly assigned to this
2359                     argument, false otherwise (defaults to false)
2360 
2361         ***********************************************************************/
2362 
2363         private void append ( istring value, bool explicit = false )
2364         {
2365             // pop to an argument that can accept implicit parameters?
2366             if ( explicit is false )
2367             {
2368                 auto s = &(this.outer.stack);
2369 
2370                 while ( s.top.exp && s.size > 1 )
2371                 {
2372                     s.pop;
2373                 }
2374             }
2375 
2376             this.set = true; // needed for default assignments
2377 
2378             values ~= value; // append new value
2379 
2380             if ( error is None )
2381             {
2382                 if ( inspector )
2383                 {
2384                     if ( (bogus = inspector(value)).length )
2385                     {
2386                         error = Invalid;
2387                     }
2388                 }
2389 
2390                 if ( options.length )
2391                 {
2392                     error = Option;
2393 
2394                     foreach ( option; options )
2395                     {
2396                         if ( option == value )
2397                         {
2398                             error = None;
2399                         }
2400                     }
2401                 }
2402             }
2403 
2404             // pop to an argument that can accept parameters
2405             auto s = &(this.outer.stack);
2406 
2407             while ( s.top.values.length >= max && s.size > 1 )
2408             {
2409                 s.pop;
2410             }
2411         }
2412 
2413 
2414         /***********************************************************************
2415 
2416             Tests whether an error condition occurred for this argument during
2417             parsing, and if so the appropriate error code is set.
2418 
2419             Returns:
2420                 the error code for this argument (0 => no error)
2421 
2422         ***********************************************************************/
2423 
2424         private int valid ( )
2425         {
2426             if ( error is None )
2427             {
2428                 if ( req && !set )
2429                 {
2430                     error = Required;
2431                 }
2432                 else
2433                 {
2434                     if ( set )
2435                     {
2436                         // short circuit?
2437                         if ( fail )
2438                         {
2439                             return -1;
2440                         }
2441 
2442                         if ( values.length < min )
2443                         {
2444                             error = ParamLo;
2445                         }
2446                         else
2447                         {
2448                             if ( values.length > max )
2449                             {
2450                                 error = ParamHi;
2451                             }
2452                             else
2453                             {
2454                                 foreach ( arg; dependees )
2455                                 {
2456                                     if ( ! arg.set )
2457                                     {
2458                                         error = Requires;
2459                                         bogus = arg.name;
2460                                     }
2461                                 }
2462 
2463                                 foreach ( arg; conflictees )
2464                                 {
2465                                     if ( arg.set )
2466                                     {
2467                                         error = Conflict;
2468                                         bogus = arg.name;
2469                                     }
2470                                 }
2471                             }
2472                         }
2473                     }
2474                 }
2475             }
2476 
2477             return error;
2478         }
2479     }
2480 }
2481 
2482 
2483 
2484 /*******************************************************************************
2485 
2486     Unit tests
2487 
2488 *******************************************************************************/
2489 
2490 unittest
2491 {
2492     auto args = new Arguments;
2493 
2494     // basic
2495     auto x = args['x'];
2496     test(args.parse(""));
2497     x.required;
2498     test(args.parse("") is false);
2499     test(args.clear.parse("-x"));
2500     test(x.set);
2501 
2502     // alias
2503     x.aliased('X');
2504     test(args.clear.parse("-X"));
2505     test(x.set);
2506 
2507     // unexpected arg (with sloppy)
2508     test(args.clear.parse("-y") is false);
2509     test(args.clear.parse("-y") is false);
2510     test(args.clear.parse("-y", true) is false);
2511     test(args['y'].set);
2512     test(args.clear.parse("-x -y", true));
2513 
2514     // parameters
2515     x.params(0);
2516     test(args.clear.parse("-x param"));
2517     test(x.assigned.length is 0);
2518     test(args(null).assigned.length is 1);
2519     x.params(1);
2520     test(args.clear.parse("-x=param"));
2521     test(x.assigned.length is 1);
2522     test(x.assigned[0] == "param");
2523     test(args.clear.parse("-x param"));
2524     test(x.assigned.length is 1);
2525     test(x.assigned[0] == "param");
2526 
2527     // too many args
2528     x.params(1);
2529     test(args.clear.parse("-x param1 param2"));
2530     test(x.assigned.length is 1);
2531     test(x.assigned[0] == "param1");
2532     test(args(null).assigned.length is 1);
2533     test(args(null).assigned[0] == "param2");
2534 
2535     // now with default params
2536     test(args.clear.parse("param1 param2 -x=blah"));
2537     test(args[null].assigned.length is 2);
2538     test(args(null).assigned.length is 2);
2539     test(x.assigned.length is 1);
2540     x.params(0);
2541     test(!args.clear.parse("-x=blah"));
2542 
2543     // args as parameter
2544     test(args.clear.parse("- -x"));
2545     test(args[null].assigned.length is 1);
2546     test(args[null].assigned[0] == "-");
2547 
2548     // multiple flags, with alias and sloppy
2549     test(args.clear.parse("-xy"));
2550     test(args.clear.parse("-xyX"));
2551     test(x.set);
2552     test(args['y'].set);
2553     test(args.clear.parse("-xyz") is false);
2554     test(args.clear.parse("-xyz", true));
2555     auto z = args['z'];
2556     test(z.set);
2557 
2558     // multiple flags with trailing arg
2559     test(args.clear.parse("-xyz=10"));
2560     test(z.assigned.length is 1);
2561 
2562     // again, but without sloppy param declaration
2563     z.params(0);
2564     test(!args.clear.parse("-xyz=10"));
2565     test(args.clear.parse("-xzy=10"));
2566     test(args('y').assigned.length is 1);
2567     test(args('x').assigned.length is 0);
2568     test(args('z').assigned.length is 0);
2569 
2570     // x requires y
2571     x.requires('y');
2572     test(args.clear.parse("-xy"));
2573     test(args.clear.parse("-xz") is false);
2574     test!("==")(args.errors(), "argument 'x' requires 'y'\n");
2575 
2576     // defaults
2577     z.defaults("foo");
2578     test(args.clear.parse("-xy"));
2579     test(z.assigned.length is 1);
2580 
2581     // long names, with params
2582     test(args.clear.parse("-xy --foobar") is false);
2583     test(args.clear.parse("-xy --foobar", true));
2584     test(args["y"].set && x.set);
2585     test(args["foobar"].set);
2586     test(args.clear.parse("-xy --foobar=10"));
2587     test(args["foobar"].assigned.length is 1);
2588     test(args["foobar"].assigned[0] == "10");
2589 
2590     // smush argument z, but not others
2591     z.params;
2592     test(args.clear.parse("-xy -zsmush") is false);
2593     test(x.set);
2594     z.smush;
2595     test(args.clear.parse("-xy -zsmush"));
2596     test(z.assigned.length is 1);
2597     test(z.assigned[0] == "smush");
2598     test(x.assigned.length is 0);
2599     z.params(0);
2600 
2601     // conflict x with z
2602     x.conflicts(z);
2603     test(args.clear.parse("-xyz") is false);
2604 
2605     // word mode, with prefix elimination
2606     args = new Arguments(null, null, null, null, null, null);
2607     test(args.clear.parse("foo bar wumpus") is false);
2608     test(args.clear.parse("foo bar wumpus wombat", true));
2609     test(args("foo").set);
2610     test(args("bar").set);
2611     test(args("wumpus").set);
2612     test(args("wombat").set);
2613 
2614     // use '/' instead of '-'
2615     args = new Arguments(null, null, null, null, "/", "/");
2616     test(args.clear.parse("/foo /bar /wumpus") is false);
2617     test(args.clear.parse("/foo /bar /wumpus /wombat", true));
2618     test(args("foo").set);
2619     test(args("bar").set);
2620     test(args("wumpus").set);
2621     test(args("wombat").set);
2622 
2623     // use '/' for short and '-' for long
2624     args = new Arguments(null, null, null, null, "/", "-");
2625     test(args.clear.parse("-foo -bar -wumpus -wombat /abc", true));
2626     test(args("foo").set);
2627     test(args("bar").set);
2628     test(args("wumpus").set);
2629     test(args("wombat").set);
2630     test(args("a").set);
2631     test(args("b").set);
2632     test(args("c").set);
2633 
2634     // "--" makes all subsequent be implicit parameters
2635     args = new Arguments;
2636     args('f').params(0);
2637     test(args.parse("-f -- -bar -wumpus -wombat --abc"));
2638     test(args('f').assigned.length is 0);
2639     test(args(null).assigned.length is 4);
2640 
2641     // Confirm arguments are stored in a sorted manner
2642     args = new Arguments;
2643     test(args.clear.parse("--beta --alpha --delta --echo --charlie", true));
2644     size_t index;
2645     foreach (arg; args)
2646     {
2647         switch ( index++ )
2648         {
2649             case 0: continue;
2650             case 1: test("alpha"   == arg.name); continue;
2651             case 2: test("beta"    == arg.name); continue;
2652             case 3: test("charlie" == arg.name); continue;
2653             case 4: test("delta"   == arg.name); continue;
2654             case 5: test("echo"    == arg.name); continue;
2655             default: test(0);
2656         }
2657     }
2658 
2659     // Test that getInt() works as expected
2660     args = new Arguments;
2661     args("num").params(1);
2662     test(args.parse("--num 100"));
2663     test(args.getInt!(uint)("num") == 100);
2664 
2665     args = new Arguments;
2666     args("num").params(1);
2667     test(args.parse("--num 18446744073709551615"));
2668     test(args.getInt!(ulong)("num") == ulong.max);
2669 
2670     args = new Arguments;
2671     args("num").params(1);
2672     test(args.getInt!(ulong)("num") == 0);
2673 }
2674 
2675 // Test for D2 'static immutable'
2676 unittest
2677 {
2678     static immutable istring name_ = "encode";
2679     static immutable istring conflicts_ = "decode";
2680     static immutable istring[] restrict_ = [ "json", "yaml" ];
2681     static immutable istring requires_ = "input";
2682     static immutable istring help_ = "Convert from native format to JSON/Yaml";
2683 
2684     auto args = new Arguments;
2685     args(name_)
2686         .params(1)
2687         .conflicts(conflicts_)
2688         .restrict(restrict_)
2689         .requires(requires_)
2690         .help(help_);
2691 
2692 }