diff options
Diffstat (limited to 'libphobos/src/std/getopt.d')
-rw-r--r-- | libphobos/src/std/getopt.d | 111 |
1 files changed, 102 insertions, 9 deletions
diff --git a/libphobos/src/std/getopt.d b/libphobos/src/std/getopt.d index cb97eeb..1a90722 100644 --- a/libphobos/src/std/getopt.d +++ b/libphobos/src/std/getopt.d @@ -610,6 +610,23 @@ private template optionValidator(A...) alias optionValidator = message; } +private void handleConversion(R)(string option, string value, R* receiver, + size_t idx, string file = __FILE__, size_t line = __LINE__) +{ + import std.conv : to, ConvException; + import std.format : format; + try + { + *receiver = to!(typeof(*receiver))(value); + } + catch (ConvException e) + { + throw new ConvException(format("Argument '%s' at position '%u' could " + ~ "not be converted to type '%s' as required by option '%s'.", + value, idx, R.stringof, option), e, file, line); + } +} + @safe pure unittest { alias P = void*; @@ -864,7 +881,7 @@ private bool handleOption(R)(string option, R receiver, ref string[] args, if (val.length) { // parse '--b=true/false' - *receiver = to!(typeof(*receiver))(val); + handleConversion(option, val, receiver, i); } else { @@ -888,15 +905,22 @@ private bool handleOption(R)(string option, R receiver, ref string[] args, val = args[i]; args = args[0 .. i] ~ args[i + 1 .. $]; } - static if (is(typeof(*receiver) == enum)) + static if (is(typeof(*receiver) == enum) || + is(typeof(*receiver) == string)) { - *receiver = to!(typeof(*receiver))(val); + handleConversion(option, val, receiver, i); } else static if (is(typeof(*receiver) : real)) { // numeric receiver - if (incremental) ++*receiver; - else *receiver = to!(typeof(*receiver))(val); + if (incremental) + { + ++*receiver; + } + else + { + handleConversion(option, val, receiver, i); + } } else static if (is(typeof(*receiver) == string)) { @@ -936,12 +960,18 @@ private bool handleOption(R)(string option, R receiver, ref string[] args, if (arraySep == "") { - *receiver ~= to!E(val); + E tmp; + handleConversion(option, val, &tmp, i); + *receiver ~= tmp; } else { - foreach (elem; val.splitter(arraySep).map!(a => to!E(a))()) - *receiver ~= elem; + foreach (elem; val.splitter(arraySep)) + { + E tmp; + handleConversion(option, elem, &tmp, i); + *receiver ~= tmp; + } } } else static if (isAssociativeArray!(typeof(*receiver))) @@ -961,7 +991,14 @@ private bool handleOption(R)(string option, R receiver, ref string[] args, ~ to!string(assignChar) ~ "' in argument '" ~ input ~ "'."); auto key = input[0 .. j]; auto value = input[j + 1 .. $]; - return tuple(to!K(key), to!V(value)); + + K k; + handleConversion("", key, &k, 0); + + V v; + handleConversion("", value, &v, 0); + + return tuple(k,v); } static void setHash(Range)(R receiver, Range range) @@ -1946,3 +1983,59 @@ void defaultGetoptFormatter(Output)(Output output, string text, Option[] opt, st ~ "information.\n"; assert(wanted == helpMsg); } + + +@safe unittest +{ + import std.conv : ConvException; + import std.string : indexOf; + + enum UniqueIdentifer { + a, + b + } + + UniqueIdentifer a; + + auto args = ["prog", "--foo", "HELLO"]; + try + { + auto t = getopt(args, "foo|f", &a); + assert(false, "Must not be reached, as \"HELLO\" cannot be converted" + ~ " to enum A."); + } + catch (ConvException e) + { + string str = () @trusted { return e.toString(); }(); + assert(str.indexOf("HELLO") != -1); + assert(str.indexOf("UniqueIdentifer") != -1); + assert(str.indexOf("foo") != -1); + } +} + +@safe unittest +{ + import std.conv : ConvException; + import std.string : indexOf; + + int a; + + auto args = ["prog", "--foo", "HELLO"]; + try + { + auto t = getopt(args, "foo|f", &a); + assert(false, "Must not be reached, as \"HELLO\" cannot be converted" + ~ " to an int"); + } + catch (ConvException e) + { + string str = () @trusted { return e.toString(); }(); + assert(str.indexOf("HELLO") != -1); + assert(str.indexOf("int") != -1); + assert(str.indexOf("foo") != -1); + } + + args = ["prog", "--foo", "1337"]; + getopt(args, "foo|f", &a); + assert(a == 1337); +} |