Skip to content

Commit

Permalink
Name argument if data conversion fails getopt
Browse files Browse the repository at this point in the history
Fixes #9662

whitespace
  • Loading branch information
burner committed Dec 20, 2024
1 parent 8973596 commit 6f6fd6e
Showing 1 changed file with 101 additions and 10 deletions.
111 changes: 101 additions & 10 deletions std/getopt.d
Original file line number Diff line number Diff line change
Expand Up @@ -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 GetOptException(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*;
Expand Down Expand Up @@ -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
{
Expand All @@ -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))
{
Expand Down Expand Up @@ -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)))
Expand All @@ -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)
Expand Down Expand Up @@ -1477,7 +1514,7 @@ private void setConfig(ref configuration cfg, config option) @safe pure nothrow
assertThrown!GetOptException(getopt(args, "abc", &abc));

args = ["prog", "--abc=string"];
assertThrown!ConvException(getopt(args, "abc", &abc));
assertThrown!GetOptException(getopt(args, "abc", &abc));
}

// https://issues.dlang.org/show_bug.cgi?id=7693
Expand Down Expand Up @@ -1946,3 +1983,57 @@ void defaultGetoptFormatter(Output)(Output output, string text, Option[] opt, st
~ "information.\n";
assert(wanted == helpMsg);
}


@safe unittest
{
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 (GetOptException 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.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 (GetOptException 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);
}

0 comments on commit 6f6fd6e

Please sign in to comment.