Add support for embedded arguments with equal characters in them.
e.g. "--var=debug=1" --> {var, "debug=1"}
This commit is contained in:
parent
d26cb9df09
commit
0329f560c4
@ -11,6 +11,9 @@
|
|||||||
-module(getopt).
|
-module(getopt).
|
||||||
-author('juanjo@comellas.org').
|
-author('juanjo@comellas.org').
|
||||||
|
|
||||||
|
-export([parse/2, usage/2]).
|
||||||
|
|
||||||
|
|
||||||
-define(TAB_LENGTH, 8).
|
-define(TAB_LENGTH, 8).
|
||||||
%% Indentation of the help messages in number of tabs.
|
%% Indentation of the help messages in number of tabs.
|
||||||
-define(INDENTATION, 3).
|
-define(INDENTATION, 3).
|
||||||
@ -44,8 +47,6 @@
|
|||||||
Help :: string() | undefined
|
Help :: string() | undefined
|
||||||
}.
|
}.
|
||||||
|
|
||||||
-export([parse/2, usage/2]).
|
|
||||||
|
|
||||||
|
|
||||||
-spec parse([option_spec()], string() | [string()]) -> {ok, {[option()], [string()]}} | {error, {Reason :: atom(), Data :: any()}}.
|
-spec parse([option_spec()], string() | [string()]) -> {ok, {[option()], [string()]}} | {error, {Reason :: atom(), Data :: any()}}.
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
@ -73,13 +74,13 @@ parse(OptSpecList, CmdLine) ->
|
|||||||
%% Process long options.
|
%% Process long options.
|
||||||
parse(OptSpecList, OptAcc, ArgAcc, ArgPos, [[$-, $- | LongName] = OptStr | Tail]) ->
|
parse(OptSpecList, OptAcc, ArgAcc, ArgPos, [[$-, $- | LongName] = OptStr | Tail]) ->
|
||||||
{Option, Tail1} =
|
{Option, Tail1} =
|
||||||
case string:tokens(LongName, "=") of
|
case split_embedded_arg(LongName) of
|
||||||
[_LongName1] ->
|
{LongName1, Arg} ->
|
||||||
get_option(OptSpecList, OptStr, LongName, ?OPT_LONG, Tail);
|
%% Get option that has its argument within the same string
|
||||||
[LongName1, Arg] ->
|
%% separated by an equal ('=') character.
|
||||||
{get_option_embedded_arg(OptSpecList, OptStr, LongName1, Arg), Tail};
|
{get_option_embedded_arg(OptSpecList, OptStr, LongName1, Arg), Tail};
|
||||||
_ ->
|
_LongName1 ->
|
||||||
throw({error, {invalid_option_arg, OptStr}})
|
get_option(OptSpecList, OptStr, LongName, ?OPT_LONG, Tail)
|
||||||
end,
|
end,
|
||||||
parse(OptSpecList, [Option | OptAcc], ArgAcc, ArgPos, Tail1);
|
parse(OptSpecList, [Option | OptAcc], ArgAcc, ArgPos, Tail1);
|
||||||
%% Process short options.
|
%% Process short options.
|
||||||
@ -130,6 +131,7 @@ get_option(OptSpecList, OptStr, OptName, FieldPos, Tail) ->
|
|||||||
throw({error, {invalid_option, OptStr}})
|
throw({error, {invalid_option, OptStr}})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
-spec get_option_embedded_arg([option_spec()], string(), string(), string()) -> option().
|
-spec get_option_embedded_arg([option_spec()], string(), string(), string()) -> option().
|
||||||
%% @doc Retrieve the specification corresponding to an option matching a string
|
%% @doc Retrieve the specification corresponding to an option matching a string
|
||||||
%% received on the command line that had its argument assigned within the
|
%% received on the command line that had its argument assigned within the
|
||||||
@ -147,6 +149,21 @@ get_option_embedded_arg(OptSpecList, OptStr, OptName, Arg) ->
|
|||||||
throw({error, {invalid_option, OptStr}})
|
throw({error, {invalid_option, OptStr}})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
-spec split_embedded_arg(string()) -> {Name :: string(), Arg :: string()} | string().
|
||||||
|
%% @doc Split an option string that may contain and option with its argument
|
||||||
|
%% separated by an equal ('=') character (e.g. "port=1000").
|
||||||
|
split_embedded_arg(OptStr) ->
|
||||||
|
split_embedded_arg(OptStr, OptStr, []).
|
||||||
|
|
||||||
|
split_embedded_arg(_OptStr, [$= | Tail], Acc) ->
|
||||||
|
{lists:reverse(Acc), Tail};
|
||||||
|
split_embedded_arg(OptStr, [Char | Tail], Acc) ->
|
||||||
|
split_embedded_arg(OptStr, Tail, [Char | Acc]);
|
||||||
|
split_embedded_arg(OptStr, [], _Acc) ->
|
||||||
|
OptStr.
|
||||||
|
|
||||||
|
|
||||||
-spec get_option_no_arg([option_spec()], string(), string() | char(), integer()) -> option().
|
-spec get_option_no_arg([option_spec()], string(), string() | char(), integer()) -> option().
|
||||||
%% @doc Retrieve the specification corresponding to an option that has no
|
%% @doc Retrieve the specification corresponding to an option that has no
|
||||||
%% argument and matches a string received on the command line.
|
%% argument and matches a string received on the command line.
|
||||||
@ -160,6 +177,7 @@ get_option_no_arg(OptSpecList, OptStr, OptName, FieldPos) ->
|
|||||||
throw({error, {invalid_option, OptStr}})
|
throw({error, {invalid_option, OptStr}})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
-spec find_non_option_arg([option_spec()], integer()) -> {value, option_spec()} | false.
|
-spec find_non_option_arg([option_spec()], integer()) -> {value, option_spec()} | false.
|
||||||
%% @doc Find the option for the discrete argument in position specified in the
|
%% @doc Find the option for the discrete argument in position specified in the
|
||||||
%% Pos argument.
|
%% Pos argument.
|
||||||
@ -207,6 +225,7 @@ convert_option_arg({Name, _Short, _Long, ArgSpec, _Help}, Arg) ->
|
|||||||
throw({error, {invalid_option_arg, {Name, Arg}}})
|
throw({error, {invalid_option_arg, {Name, Arg}}})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
-spec to_type(atom(), string()) -> arg_value().
|
-spec to_type(atom(), string()) -> arg_value().
|
||||||
to_type(binary, Arg) ->
|
to_type(binary, Arg) ->
|
||||||
list_to_binary(Arg);
|
list_to_binary(Arg);
|
||||||
|
@ -127,12 +127,10 @@ parse_1_test_() ->
|
|||||||
{?HELP(Long), ?_assertMatch({ok, {[long], []}}, parse([Long], ["--long"]))},
|
{?HELP(Long), ?_assertMatch({ok, {[long], []}}, parse([Long], ["--long"]))},
|
||||||
{?HELP(LongArg), ?_assertMatch({ok, {[{long_arg, "value"}], []}}, parse([LongArg], ["--long-arg", "value"]))},
|
{?HELP(LongArg), ?_assertMatch({ok, {[{long_arg, "value"}], []}}, parse([LongArg], ["--long-arg", "value"]))},
|
||||||
{?HELP(LongArg), ?_assertMatch({ok, {[{long_arg, "value"}], []}}, parse([LongArg], ["--long-arg=value"]))},
|
{?HELP(LongArg), ?_assertMatch({ok, {[{long_arg, "value"}], []}}, parse([LongArg], ["--long-arg=value"]))},
|
||||||
|
{?HELP(LongArg), ?_assertMatch({ok, {[{long_arg, "value=1"}], []}}, parse([LongArg], ["--long-arg=value=1"]))},
|
||||||
{?HELP(LongDefArg), ?_assertMatch({ok, {[{long_def_arg, "default-long"}], []}}, parse([LongDefArg], []))},
|
{?HELP(LongDefArg), ?_assertMatch({ok, {[{long_def_arg, "default-long"}], []}}, parse([LongDefArg], []))},
|
||||||
{?HELP(LongInt), ?_assertMatch({ok, {[{long_int, 100}], []}}, parse([LongInt], ["--long-int", "100"]))},
|
{?HELP(LongInt), ?_assertMatch({ok, {[{long_int, 100}], []}}, parse([LongInt], ["--long-int", "100"]))},
|
||||||
{?HELP(LongInt), ?_assertMatch({ok, {[{long_int, 100}], []}}, parse([LongInt], ["--long-int=100"]))},
|
{?HELP(LongInt), ?_assertMatch({ok, {[{long_int, 100}], []}}, parse([LongInt], ["--long-int=100"]))},
|
||||||
%% Options with only the long form (expected failures)
|
|
||||||
{?HELP(LongArg) ++ " (XFAIL)",
|
|
||||||
?_assertEqual({error, {invalid_option_arg, "--long-arg=value=1"}}, parse([LongArg], ["--long-arg=value=1"]))},
|
|
||||||
{"Long form option and arguments",
|
{"Long form option and arguments",
|
||||||
?_assertMatch({ok, {[long], ["arg1", "arg2"]}}, parse([Long], ["--long", "arg1", "arg2"]))},
|
?_assertMatch({ok, {[long], ["arg1", "arg2"]}}, parse([Long], ["--long", "arg1", "arg2"]))},
|
||||||
{"Long form option and arguments (unsorted)",
|
{"Long form option and arguments (unsorted)",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user