Changeset 125

Show
Ignore:
Timestamp:
08/16/07 01:29:09 (1 year ago)
Author:
KirkMcDonald
Message:

Major refactoring of optparse.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • misc/optparse.d

    r124 r125  
    4040        return s.length; 
    4141    } 
     42    //alias char[] string; 
    4243} else { 
    4344    import std.stdio : writefln, writef; 
     
    169170        } 
    170171    } 
     172    private { 
     173        void storeArg(char[] name, char[] arg) { 
     174            opts[name] = [arg]; 
     175        } 
     176        void storeArg(char[] name, bool arg) { 
     177            if (arg) { 
     178                opts[name] = ["1"]; 
     179            } else { 
     180                opts[name] = ["0"]; 
     181            } 
     182        } 
     183        void appendArg(char[] name, char[] arg) { 
     184            opts[name] ~= arg; 
     185        } 
     186        void increment(char[] name) { 
     187            ++counted_opts[name]; 
     188        } 
     189        bool hasName(char[] name) { 
     190            return name in opts || name in counted_opts; 
     191        } 
     192    } 
    171193} 
    172194 
     
    186208alias void delegate()       OptionCallback; 
    187209 
    188 /* 
    189 Actions: 
    190  * Store:        name 
    191  * StoreConst:   name, const_value 
    192  * Append:       name 
    193  * AppendConst:  name, const_value 
    194  * Count:        name 
    195  * CallbackArg:  dga 
    196  * CallbackVoid: dg 
    197 */ 
    198210/// 
    199211enum Action { /+++/Store, /+++/StoreConst, /+++/Append, /+++/AppendConst, /+++/Count, /+++/SetTrue, /+++/SetFalse, /+++/Callback, /+++/CallbackFancy, /+++/Help /+++/} 
    200212/// 
    201 enum ArgType { /+++/None, /+++/String, /+++/Integer /+++/} 
    202  
    203 ArgType defaultType(Action action) { 
    204     switch (action) { 
    205         case Action.Store, Action.Append, Action.Callback, Action.CallbackFancy: 
    206             return ArgType.String; 
    207         default: 
    208             return ArgType.None; 
    209     } 
    210     return ArgType.None; 
    211 
     213enum ArgType { /+/+++/None,+/ /+++/String, /+++/Integer /+++/} 
    212214 
    213215/++ 
    214216This class represents a single command-line option. 
    215217+/ 
    216 class Option { 
     218abstract class Option { 
    217219    char[][] shortopts, longopts; 
    218     Action action; 
    219     ArgType type; 
    220220    char[] name, argname; 
    221     char[] const_value; 
    222  
    223     char[] default_string; 
    224     int default_value; 
    225     bool default_flag, has_default; 
    226  
    227     OptionCallbackArg callback; 
    228     OptionCallbackInt int_callback; 
    229     OptionCallback void_callback; 
    230  
    231     OptionCallbackFancyArg fancy_callback; 
    232     OptionCallbackFancyInt fancy_int_callback; 
    233     OptionCallbackFancy fancy_void_callback; 
    234221    char[] helptext; 
    235     this( 
    236         char[][] shorts, char[][] longs, ArgType type, 
    237         Action act, char[] name, char[] const_value, 
    238         OptionCallbackArg dga, OptionCallback dg, 
    239         OptionCallbackInt dgi, 
    240         OptionCallbackFancyArg fdga, 
    241         OptionCallbackFancyInt fdgi, 
    242         OptionCallbackFancy fdg 
    243     ) { 
    244         this.shortopts = shorts; 
    245         this.longopts = longs; 
    246         this.action = act; 
    247         this.type = type; 
    248         this.name = name; 
    249         this.argname = toupper(name.dup); 
    250         this.default_string = ""; 
    251         this.default_value = 0; 
    252         this.default_flag = false; 
    253  
    254         // Perform sanity checks. 
    255         assert (name !is null); 
    256         switch (act) { 
    257             case Action.Store, Action.Append: 
    258                 assert(type != ArgType.None); 
    259                 break; 
    260             case Action.StoreConst, Action.AppendConst: 
    261                 assert(type == ArgType.None); 
    262                 assert(const_value !is null); 
    263                 break; 
    264             case Action.Callback: 
    265                 //assert(type != ArgType.None); 
    266                 switch (type) { 
    267                     case ArgType.String: 
    268                         assert(dga !is null); 
    269                         break; 
    270                     case ArgType.Integer: 
    271                         assert(dgi !is null); 
    272                         break; 
    273                     case ArgType.None: 
    274                         assert(dg !is null); 
    275                         break; 
    276                     default: 
    277                         break; 
    278                 } 
    279                 break; 
    280             case Action.CallbackFancy: 
    281                 switch (type) { 
    282                     case ArgType.String: 
    283                         assert(fdga !is null); 
    284                         break; 
    285                     case ArgType.Integer: 
    286                         assert(fdgi !is null); 
    287                         break; 
    288                     case ArgType.None: 
    289                         assert(fdg !is null); 
    290                         break; 
    291                     default: 
    292                         break; 
    293                 } 
    294             default: 
    295                 break; 
    296         } 
    297         this.const_value = const_value; 
    298         this.callback = dga; 
    299         this.int_callback = dgi; 
    300         this.void_callback = dg; 
    301         this.fancy_callback = fdga; 
    302         this.fancy_int_callback = fdgi; 
    303         this.fancy_void_callback = fdg; 
     222    this(char[][] options, char[] name) { 
     223        dchar[] opt; 
     224        foreach (_opt; options) { 
     225            // (Unicode note: We convert to dchar[] so the length checks work 
     226            // out in the event of a short opt with a >127 character.) 
     227            opt = toUTF32(_opt); 
     228            if (opt.length < 2) { 
     229                throw new OptionError( 
     230                    "invalid option string '" ~ _opt ~ "': must be at least two characters long" 
     231                ); 
     232            } else if (opt.length > 2) { 
     233                if (opt[0 .. 2] != "--" || opt[2] == '-') 
     234                    throw new OptionError( 
     235                        "invalid long option string '" ~ _opt ~ "': must start with --, followed by non-dash" 
     236                    ); 
     237                longopts ~= _opt; 
     238            } else { 
     239                if (opt[0] != '-' || opt[1] == '-') 
     240                    throw new OptionError( 
     241                        "invalid short option string '" ~ _opt ~ "': must be of the form -x, where x is non-dash" 
     242                    ); 
     243                shortopts ~= _opt; 
     244            } 
     245        } 
     246        if (name is null) { 
     247            // (Unicode note: We know '-' is a single code unit, so these 
     248            // slices are okay.) 
     249            if (longopts.length > 0) 
     250                this.name = longopts[0][2 .. $]; 
     251            else if (shortopts.length > 0) 
     252                this.name = shortopts[0][1 .. 2]; 
     253            else 
     254                throw new OptionError( 
     255                    "No options provided to addOption!" 
     256                ); 
     257        } else { 
     258            this.name = name; 
     259        } 
     260        argname = toupper(this.name.dup); 
    304261    } 
    305262    char[] toString() { 
    306263        int optCount = this.shortopts.length + this.longopts.length; 
    307264        char[] result; 
    308         bool printed_arg = false; 
     265        //bool printed_arg = false; 
    309266        foreach(i, opt; this.shortopts ~ this.longopts) { 
    310267            result ~= opt; 
     
    319276    //enum Action { Store, StoreConst, Append, AppendConst, Count, SetTrue, SetFalse, Callback, CallbackFancy, Help } 
    320277    void issue_default(Options results) { 
    321         // Only set the default if the option doesn't already have a value. 
    322         char[][]* val = this.name in results.opts; 
    323         switch (this.action) { 
    324             case Action.Store, Action.Append: 
    325                 if (val !is null) return; 
    326                 if (this.type == ArgType.String) { 
    327                     results.opts[name] = [default_string]; 
    328                 } else { 
    329                     results.opts[name] = [.toString(default_value)]; 
    330                 } 
    331                 break; 
    332             case Action.StoreConst, Action.AppendConst: 
    333                 if (val !is null) return; 
    334                 results.opts[name] = [default_string]; 
    335                 break; 
    336             case Action.SetTrue, Action.SetFalse: 
    337                 if (val !is null) return; 
    338                 if (default_flag) { 
    339                     results.opts[name] = ["1"]; 
    340                 } else { 
    341                     results.opts[name] = ["0"]; 
    342                 } 
    343                 break; 
    344             default: 
    345                 return; 
    346         } 
    347     } 
    348     // Does whatever this option is supposed to do. 
    349     void performAction(OptionParser parser, Options results, inout char[][] args, inout int idx, char[] arg) { 
    350         int i; 
    351         if (this.type == ArgType.Integer) { 
    352             // Verify that it's an int. 
    353             i = parser.toOptInt(arg); 
    354         } 
    355         switch (this.action) { 
    356             case Action.Store: 
    357                 results.opts[name] = [arg]; 
    358                 break; 
    359             case Action.Append: 
    360                 results.opts[name] ~= arg; 
    361                 break; 
    362             case Action.StoreConst: 
    363                 assert(arg is null, "Got unexpected argument for '"~name~"' option."); 
    364                 results.opts[name] = [const_value]; 
    365                 break; 
    366             case Action.AppendConst: 
    367                 assert(arg is null, "Got unexpected argument for '"~name~"' option."); 
    368                 results.opts[name] ~= const_value; 
    369                 break; 
    370             case Action.Count: 
    371                 assert(arg is null, "Got unexpected argument for '"~name~"' option."); 
    372                 ++results.counted_opts[name]; 
    373                 break; 
    374             case Action.SetTrue: 
    375                 results.opts[name] = ["1"]; 
    376                 break; 
    377             case Action.SetFalse: 
    378                 results.opts[name] = ["0"]; 
    379                 break; 
    380             case Action.Callback: 
    381                 switch (type) { 
    382                     case ArgType.String: 
    383                         callback(arg); 
    384                         break; 
    385                     case ArgType.Integer: 
    386                         int_callback(i); 
    387                         break; 
    388                     case ArgType.None: 
    389                         void_callback(); 
    390                         break; 
    391                     default: 
    392                         break; 
    393                 } 
    394                 break; 
    395             case Action.CallbackFancy: 
    396                 switch (type) { 
    397                     case ArgType.String: 
    398                         fancy_callback(results, args, idx, name, arg); 
    399                         break; 
    400                     case ArgType.Integer: 
    401                         fancy_int_callback(results, args, idx, name, i); 
    402                         break; 
    403                     case ArgType.None: 
    404                         fancy_void_callback(results, args, idx, name); 
    405                         break; 
    406                     default: 
    407                         break; 
    408                 } 
    409                 break; 
    410             case Action.Help: 
    411                 parser.helpText(); 
    412                 exit(EXIT_SUCCESS); 
    413                 break;                 
    414             default: 
    415                 break; 
    416         } 
    417     } 
     278        return; 
     279    } 
     280    /// Does whatever this option is supposed to do. 
     281    abstract void performAction(OptionParser parser, Options results, inout char[][] args, inout int idx, char[] arg); 
    418282    /// Returns whether this option accepts an argument. 
    419283    bool hasArg() { 
    420         return this.type != ArgType.None; 
     284        return false; 
    421285    } 
    422286    /// Sets the help text for this option. 
     
    431295    } 
    432296    Option def(char[] val) { 
    433         if ( 
    434             (this.type != ArgType.String || (this.action != Action.Store && this.action != Action.Append)) && 
    435             this.action != Action.StoreConst && this.action != Action.AppendConst 
    436         ) 
    437             throw new OptionError("Cannot specify string default for non-string option '"~this.name~"'"); 
    438         this.has_default = true; 
    439         this.default_string = val; 
    440         return this; 
     297        throw new OptionError("Cannot specify string default for non-string option '"~this.name~"'"); 
    441298    } 
    442299    Option def(int val) { 
    443         if (this.type != ArgType.Integer || (this.action != Action.Store && this.action != Action.Append)) 
    444             throw new OptionError("Cannot specify integer default for non-integer option '"~this.name~"'"); 
    445         this.has_default = true; 
    446         this.default_value = val; 
    447         return this; 
     300        throw new OptionError("Cannot specify integer default for non-integer option '"~this.name~"'"); 
    448301    } 
    449302    Option def(bool val) { 
    450         if (this.action != Action.SetTrue && this.action != Action.SetFalse) 
    451             throw new OptionError("Cannot specify boolean default for non-flag option '"~this.name~"'"); 
    452         this.has_default = true; 
    453         this.default_flag = val; 
    454         return this; 
     303        throw new OptionError("Cannot specify boolean default for non-flag option '"~this.name~"'"); 
    455304    } 
    456305    // Returns true if the passed option string matches this option. 
     
    478327        } 
    479328        return false; 
     329    } 
     330} 
     331 
     332abstract class ArgOption : Option { 
     333    static const ArgType default_type = ArgType.String; 
     334    ArgType type; 
     335    bool has_default = false; 
     336    char[] default_string; 
     337    this(char[][] options, char[] name, ArgType type) { 
     338        super(options, name); 
     339        this.type = type; 
     340    } 
     341    override void performAction(OptionParser parser, Options results, inout char[][] args, inout int idx, char[] arg) { 
     342        if (this.type == ArgType.Integer) { 
     343            // Verify that it's an int. 
     344            int i = parser.toOptInt(arg); 
     345        } 
     346    } 
     347    override Option def(char[] val) { 
     348        if (this.type != ArgType.String) 
     349            super.def(val); 
     350        this.has_default = true; 
     351        this.default_string = val; 
     352        return this; 
     353    } 
     354    override Option def(int val) { 
     355        if (this.type != ArgType.Integer) 
     356            super.def(val); 
     357        this.has_default = true; 
     358        this.default_string = .toString(val); 
     359        return this; 
     360    } 
     361    override void issue_default(Options results) { 
     362        if (has_default) results.storeArg(this.name, this.default_string); 
     363    } 
     364    override bool hasArg() { 
     365        return true; 
     366    } 
     367} 
     368 
     369class Store : ArgOption { 
     370    this(char[][] options, char[] name, ArgType type=Store.default_type) { 
     371        super(options, name, type); 
     372    } 
     373    override void performAction(OptionParser parser, Options results, inout char[][] args, inout int idx, char[] arg) { 
     374        super.performAction(parser, results, args, idx, arg); 
     375        results.storeArg(this.name, arg); 
     376    } 
     377} 
     378class Append : ArgOption { 
     379    this(char[][] options, char[] name, ArgType type=Append.default_type) { 
     380        super(options, name, type); 
     381    } 
     382    override void performAction(OptionParser parser, Options results, inout char[][] args, inout int idx, char[] arg) { 
     383        super.performAction(parser, results, args, idx, arg); 
     384        results.appendArg(this.name, arg); 
     385    } 
     386} 
     387abstract class ConstOption : Option { 
     388    bool has_default = false; 
     389    char[] default_value; 
     390    char[] const_value; 
     391    this(char[][] options, char[] name, char[] const_value) { 
     392        super(options, name); 
     393        this.const_value = const_value; 
     394    } 
     395    override Option def(char[] val) { 
     396        this.has_default = true; 
     397        this.default_value = val; 
     398        return this; 
     399    } 
     400    override void issue_default(Options results) { 
     401        if (has_default) results.storeArg(this.name, this.default_value); 
     402    } 
     403} 
     404class StoreConst : ConstOption { 
     405    this(char[][] options, char[] name, char[] const_value) { 
     406        super(options, name, const_value); 
     407    } 
     408    override void performAction(OptionParser parser, Options results, inout char[][] args, inout int idx, char[] arg) { 
     409        results.storeArg(this.name, this.const_value); 
     410    } 
     411} 
     412class AppendConst : ConstOption { 
     413    this(char[][] options, char[] name, char[] const_value) { 
     414        super(options, name, const_value); 
     415    } 
     416    override void performAction(OptionParser parser, Options results, inout char[][] args, inout int idx, char[] arg) { 
     417        results.appendArg(this.name, this.const_value); 
     418    } 
     419} 
     420abstract class SetBool : Option { 
     421    bool has_default = false; 
     422    bool default_flag = false; 
     423    this(char[][] options, char[] name) { 
     424        super(options, name); 
     425    } 
     426    override Option def(bool val) { 
     427        this.has_default = true; 
     428        this.default_flag = val; 
     429        return this; 
     430    } 
     431    override void issue_default(Options results) { 
     432        if (has_default) results.storeArg(this.name, this.default_flag); 
     433    } 
     434} 
     435class SetTrue : SetBool { 
     436    this(char[][] options, char[] name) { 
     437        super(options, name); 
     438    } 
     439    override void performAction(OptionParser parser, Options results, inout char[][] args, inout int idx, char[] arg) { 
     440        results.storeArg(this.name, true); 
     441    } 
     442} 
     443class SetFalse : SetBool { 
     444    this(char[][] options, char[] name) { 
     445        super(options, name); 
     446    } 
     447    override void performAction(OptionParser parser, Options results, inout char[][] args, inout int idx, char[] arg) { 
     448        results.storeArg(this.name, false); 
     449    } 
     450} 
     451class Count : Option { 
     452    this(char[][] options, char[] name) { 
     453        super(options, name); 
     454    } 
     455    override void performAction(OptionParser parser, Options results, inout char[][] args, inout int idx, char[] arg) { 
     456        results.increment(this.name); 
     457    } 
     458} 
     459class Callback : Option { 
     460    OptionCallback cb; 
     461    this(char[][] options, OptionCallback cb) { 
     462        super(options, null); 
     463        this.cb = cb; 
     464    } 
     465    override void performAction(OptionParser parser, Options results, inout char[][] args, inout int idx, char[] arg) { 
     466        this.cb(); 
     467    } 
     468} 
     469class CallbackArg : Option { 
     470    OptionCallbackArg cb; 
     471    this(char[][] options, OptionCallbackArg cb) { 
     472        super(options, null); 
     473        this.cb = cb; 
     474    } 
     475    override void performAction(OptionParser parser, Options results, inout char[][] args, inout int idx, char[] arg) { 
     476        this.cb(arg); 
     477    } 
     478    override bool hasArg() { 
     479        return true; 
     480    } 
     481} 
     482class CallbackInt : Option { 
     483    OptionCallbackInt cb; 
     484    this(char[][] options, OptionCallbackInt cb) { 
     485        super(options, null); 
     486        this.cb = cb; 
     487    } 
     488    override void performAction(OptionParser parser, Options results, inout char[][] args, inout int idx, char[] arg) { 
     489        int i = parser.toOptInt(arg); 
     490        this.cb(i); 
     491    } 
     492    override bool hasArg() { 
     493        return true; 
     494    } 
     495} 
     496class FancyCallback : Option { 
     497    OptionCallbackFancy cb; 
     498    this(char[][] options, char[] name, OptionCallbackFancy cb) { 
     499        super(options, name); 
     500        this.cb = cb; 
     501    } 
     502    override void performAction(OptionParser parser, Options results, inout char[][] args, inout int idx, char[] arg) { 
     503        this.cb(results, args, idx, this.name); 
     504    } 
     505} 
     506class FancyCallbackArg : Option { 
     507    OptionCallbackFancyArg cb; 
     508    this(char[][] options, char[] name, OptionCallbackFancyArg cb) { 
     509        super(options, name); 
     510        this.cb = cb; 
     511    } 
     512    override void performAction(OptionParser parser, Options results, inout char[][] args, inout int idx, char[] arg) { 
     513        this.cb(results, args, idx, this.name, arg); 
     514    } 
     515    override bool hasArg() { 
     516        return true; 
     517    } 
     518} 
     519class FancyCallbackInt : Option { 
     520    OptionCallbackFancyInt cb; 
     521    this(char[][] options, char[] name, OptionCallbackFancyInt cb) { 
     522        super(options, name); 
     523        this.cb = cb; 
     524    } 
     525    override void performAction(OptionParser parser, Options results, inout char[][] args, inout int idx, char[] arg) { 
     526        int i = parser.toOptInt(arg); 
     527        this.cb(results, args, idx, this.name, i); 
     528    } 
     529    override bool hasArg() { 
     530        return true; 
     531    } 
     532} 
     533class Help : Option { 
     534    this(char[][] options) { 
     535        super(options, null); 
     536    } 
     537    override void performAction(OptionParser parser, Options results, inout char[][] args, inout int idx, char[] arg) { 
     538        parser.helpText(); 
     539        exit(EXIT_SUCCESS); 
    480540    } 
    481541} 
     
    731791        this.leftover_cb = dg; 
    732792    } 
    733     /// 
     793    private void wrong_args(char[][] options) { 
     794        if (options.length > 0) { 
     795            throw new OptionError( 
     796                "Wrong arguments to addOption for option '" 
     797                ~options[0]~"'." 
     798            ); 
     799        } else { 
     800            throw new OptionError("Found an empty option!"); 
     801        } 
     802    } 
     803    /// 
     804    Option addOption(char[][] options ...) { 
     805        return addOption(new Store(options, null)); 
     806    } 
     807    /// 
     808    Option addOption(char[][] options, char[] name) { 
     809        return addOption(new Store(options, name)); 
     810    } 
     811    /// 
     812    Option addOption(char[][] options, Action action) { 
     813        Option o; 
     814        switch (action) { 
     815            case Action.Store, Action.Append: 
     816                return addOption(options, null, action, ArgOption.default_type); 
     817            case Action.Count: 
     818                return addOption(options, null, action); 
     819            case Action.Help: 
     820                return addOption(new Help(options)); 
     821            default: 
     822                wrong_args(options); 
     823                break; 
     824        } 
     825        return addOption(o); 
     826    } 
     827    /// 
     828    Option addOption(char[][] options, ArgType type) { 
     829        return addOption(new Store(options, null, type)); 
     830    } 
     831    /// 
     832    Option addOption(char[][] options, Action action, ArgType type) { 
     833        return addOption(options, null, action, type); 
     834    } 
     835    /// 
     836    Option addOption(char[][] options, char[] name, Action action) { 
     837        Option o; 
     838        switch (action) { 
     839            case Action.Store, Action.Append: 
     840                return addOption(options, name, action, ArgOption.default_type); 
     841            case Action.Count: 
     842                o = new Count(options, name); 
     843                break; 
     844            case Action.SetTrue: 
     845                o = new SetTrue(options, name); 
     846                break; 
     847            case Action.SetFalse: 
     848                o = new SetFalse(options, name); 
     849                break; 
     850            default: 
     851                wrong_args(options); 
     852                break; 
     853        } 
     854        return addOption(o); 
     855    } 
     856    /// 
     857    Option addOption(char[][] options, char[] name, Action action, ArgType type) { 
     858        Option o; 
     859        switch (action) { 
     860            case Action.Store: 
     861                o = new Store(options, name, type); 
     862                break; 
     863            case Action.Append: 
     864                o = new Append(options, name, type); 
     865                break; 
     866            default: 
     867                wrong_args(options); 
     868                break; 
     869        } 
     870        return addOption(o); 
     871    } 
     872    /// 
     873    Option addOption(char[][] options, Action action, char[] const_value) { 
     874        return addOption(options, null, action, const_value); 
     875    } 
     876    /// 
     877    Option addOption(char[][] options, char[] name, char[] const_value) { 
     878        return addOption(options, name, Action.StoreConst, const_value); 
     879    } 
     880    /// 
     881    Option addOption(char[][] options, char[] name, Action action, char[] const_value) { 
     882        Option o; 
     883        switch (action) { 
     884            case Action.StoreConst: 
     885                o = new StoreConst(options, name, const_value); 
     886                break; 
     887            case Action.AppendConst: 
     888                o = new AppendConst(options, name, const_value); 
     889                break; 
     890            default: 
     891                wrong_args(options); 
     892                break; 
     893        } 
     894        return addOption(o); 
     895    } 
     896    /// 
     897    Option addOption(char[][] options, OptionCallback dg) { 
     898        return addOption(new Callback(options, dg)); 
     899    } 
     900    /// 
     901    Option addOption(char[][] options, OptionCallbackArg dg) { 
     902        return addOption(new CallbackArg(options, dg)); 
     903    } 
     904    /// 
     905    Option addOption(char[][] options, OptionCallbackInt dg) { 
     906        return addOption(new CallbackInt(options, dg)); 
     907    } 
     908    /// 
     909    Option addOption(char[][] options, OptionCallbackFancy dg) { 
     910        return addOption(new FancyCallback(options, null, dg)); 
     911    } 
     912    /// 
     913    Option addOption(char[][] options, OptionCallbackFancyArg dg) { 
     914        return addOption(new FancyCallbackArg(options, null, dg)); 
     915    } 
     916    /// 
     917    Option addOption(char[][] options, OptionCallbackFancyInt dg) { 
     918        return addOption(new FancyCallbackInt(options, null, dg)); 
     919    } 
     920    /// 
     921    Option addOption(char[][] options, char[] name, OptionCallbackFancy dg) { 
     922        return addOption(new FancyCallback(options, name, dg)); 
     923    } 
     924    /// 
     925    Option addOption(char[][] options, char[] name, OptionCallbackFancyArg dg) { 
     926        return addOption(new FancyCallbackArg(options, name, dg)); 
     927    } 
     928    /// 
     929    Option addOption(char[][] options, char[] name, OptionCallbackFancyInt dg) { 
     930        return addOption(new FancyCallbackInt(options, name, dg)); 
     931    } 
     932    // Although users certainly /can/ call this, all those overloads are there 
     933    // for a reason. 
    734934    Option addOption(Option option) { 
    735935        this.options ~= option; 
    736936        return option; 
    737937    } 
    738     //                    options  action             name  type                       const_value  dga   dgv   dgi   fdga  fdgi  fdg 
    739     /// 
    740     Option addOption(char[][] options ...) { 
    741         return addOption(options, Action.Store,      null, defaultType(Action.Store), null,        null, null, null, null, null, null); 
    742     } 
    743     /// 
    744     Option addOption(char[][] options, char[] name) { 
    745         return addOption(options, Action.Store,      name, defaultType(Action.Store), null,        null, null, null, null, null, null); 
    746     } 
    747     /// 
    748     Option addOption(char[][] options, Action action) { 
    749         return addOption(options, action,            null, defaultType(action),       null,        null, null, null, null, null, null); 
    750     } 
    751     /// 
    752     Option addOption(char[][] options, ArgType type) { 
    753         return addOption(options, Action.Store,      null, type,                      null,        null, null, null, null, null, null); 
    754     } 
    755     /// 
    756     Option addOption(char[][] options, Action action, ArgType type) { 
    757         return addOption(options, action,            null, type,                      null,        null, null, null, null, null, null); 
    758     } 
    759     /// 
    760     Option addOption(char[][] options, char[] name, Action action) { 
    761         return addOption(options, action,            name, defaultType(action),       null,        null, null, null, null, null, null); 
    762     } 
    763     /// 
    764     Option addOption(char[][] options, char[] name, Action action, ArgType type) { 
    765         return addOption(options, action,            name, type,                      null,        null, null, null, null, null, null); 
    766     } 
    767     /// 
    768     Option addOption(char[][] options, Action action, char[] const_value) { 
    769         return addOption(options, action,            null, defaultType(action),       const_value, null, null, null, null, null, null); 
    770     } 
    771     /// 
    772     Option addOption(char[][] options, char[] name, char[] const_value) { 
    773         return addOption(options, Action.StoreConst, name, defaultType(Action.Store), const_value, null, null, null, null, null, null); 
    774     } 
    775     /// 
    776     Option addOption(char[][] options, char[] name, Action action, char[] const_value) { 
    777         return addOption(options, action,            name, defaultType(action),       const_value, null, null, null, null, null, null); 
    778     } 
    779     /// 
    780     Option addOption(char[][] options, OptionCallbackArg dg) { 
    781         return addOption(options, Action.Callback,   null, ArgType.String,            null,        dg,   null, null, null, null, null); 
    782     } 
    783     /// 
    784     Option addOption(char[][] options, OptionCallback dg) { 
    785         return addOption(options, Action.Callback,   null, ArgType.None,              null,        null, dg,   null, null, null, null); 
    786     } 
    787     /// 
    788     Option addOption(char[][] options, OptionCallbackInt dg) { 
    789         return addOption(options, Action.Callback,   null, ArgType.Integer,           null,        null, null, dg,   null, null, null); 
    790     } 
    791     /// 
    792     Option addOption(char[][] options, OptionCallbackFancyArg dg) { 
    793         return addOption(options, Action.CallbackFancy, null, ArgType.String,         null,        null, null, null, dg,   null, null); 
    794     } 
    795     /// 
    796     Option addOption(char[][] options, OptionCallbackFancy dg) { 
    797         return addOption(options, Action.CallbackFancy, null, ArgType.None,           null,        null, null, null, null, null, dg); 
    798     } 
    799     /// 
    800     Option addOption(char[][] options, OptionCallbackFancyInt dg) { 
    801         return addOption(options, Action.CallbackFancy, null, ArgType.Integer,        null,        null, null, null, null, dg,   null); 
    802     } 
    803     /// 
    804     Option addOption(char[][] options, char[] name, OptionCallbackFancyArg dg) { 
    805         return addOption(options, Action.CallbackFancy, name, ArgType.String,         null,        null, null, null, dg,   null, null); 
    806     } 
    807     /// 
    808     Option addOption(char[][] options, char[] name, OptionCallbackFancy dg) { 
    809         return addOption(options, Action.CallbackFancy, name, ArgType.None,           null,        null, null, null, null, null, dg); 
    810     } 
    811     /// 
    812     Option addOption(char[][] options, char[] name, OptionCallbackFancyInt dg) { 
    813         return addOption(options, Action.CallbackFancy, name, ArgType.Integer,        null,        null, null, null, null, dg,   null); 
    814     } 
    815     // Although users certainly /can/ call this, all those overloads are there 
    816     // for a reason. 
    817     Option addOption( 
    818         char[][] options,  
    819         Action action, char[] name, ArgType type, char[] const_value, 
    820         OptionCallbackArg callback, OptionCallback vcall, 
    821         OptionCallbackInt icall, 
    822         OptionCallbackFancyArg fdga, 
    823         OptionCallbackFancyInt fdgi, 
    824         OptionCallbackFancy fdg 
    825     ) { 
    826         char[][] shortopts; 
    827         char[][] longopts; 
    828         dchar[] opt; 
    829         Option option; 
    830         foreach (_opt; options) { 
    831             // (Unicode note: We convert to dchar[] so the length checks work 
    832             // out in the event of a short opt with a >127 character.) 
    833             opt = toUTF32(_opt); 
    834             if (opt.length < 2) { 
    835                 throw new OptionError( 
    836                     "invalid option string '" ~ _opt ~ "': must be at least two characters long" 
    837                 ); 
    838             } else if (opt.length > 2) { 
    839                 if (opt[0 .. 2] != "--" || opt[2] == '-') 
    840                     throw new OptionError( 
    841                         "invalid long option string '" ~ _opt ~ "': must start with --, followed by non-dash" 
    842                     ); 
    843                 longopts ~= _opt; 
    844             } else { 
    845                 if (opt[0] != '-' || opt[1] == '-') 
    846                     throw new OptionError( 
    847                         "invalid short option string '" ~ _opt ~ "': must be of the form -x, where x is non-dash" 
    848                     ); 
    849                 shortopts ~= _opt; 
    850             } 
    851         } 
    852         if (name is null) { 
    853             // (Unicode note: We know '-' is a single code unit, so these 
    854             // slices are okay.) 
    855             if (longopts.length > 0) 
    856                 name = longopts[0][2 .. $]; 
    857             else if (shortopts.length > 0) 
    858                 name = shortopts[0][1 .. 2]; 
    859             else 
    860                 throw new OptionError( 
    861                     "No options provided to addOption!" 
    862                 ); 
    863         } 
    864         option = new Option(shortopts, longopts, type, action, name, const_value, callback, vcall, icall, fdga, fdgi, fdg); 
    865         this.options ~= option; 
    866         return option; 
    867     } 
    868 
    869  
     938
     939