|
|
@ -11,6 +11,9 @@ |
|
|
|
-module(getopt). |
|
|
|
-author('juanjo@comellas.org'). |
|
|
|
|
|
|
|
-export([parse/2, usage/2]). |
|
|
|
|
|
|
|
|
|
|
|
-define(TAB_LENGTH, 8). |
|
|
|
%% Indentation of the help messages in number of tabs. |
|
|
|
-define(INDENTATION, 3). |
|
|
@ -44,8 +47,6 @@ |
|
|
|
Help :: string() | undefined |
|
|
|
}. |
|
|
|
|
|
|
|
-export([parse/2, usage/2]). |
|
|
|
|
|
|
|
|
|
|
|
-spec parse([option_spec()], string() | [string()]) -> {ok, {[option()], [string()]}} | {error, {Reason :: atom(), Data :: any()}}. |
|
|
|
%%-------------------------------------------------------------------- |
|
|
@ -68,72 +69,150 @@ parse(OptSpecList, CmdLine) -> |
|
|
|
Error |
|
|
|
end. |
|
|
|
|
|
|
|
|
|
|
|
-spec parse([option_spec()], [option()], [string()], integer(), [string()]) -> |
|
|
|
{ok, {[option()], [string()]}} | {error, {Reason :: atom(), Data:: any()}}. |
|
|
|
%% Process the option terminator. |
|
|
|
parse(OptSpecList, OptAcc, ArgAcc, _ArgPos, ["--" | Tail]) -> |
|
|
|
% Any argument present after the terminator is not considered an option. |
|
|
|
{ok, {lists:reverse(append_default_options(OptSpecList, OptAcc)), lists:reverse(ArgAcc, Tail)}}; |
|
|
|
%% Process long options. |
|
|
|
parse(OptSpecList, OptAcc, ArgAcc, ArgPos, [[$-, $- | LongName] = OptStr | Tail]) -> |
|
|
|
{Option, Tail1} = get_option(OptSpecList, OptStr, LongName, ?OPT_LONG, Tail), |
|
|
|
parse(OptSpecList, [Option | OptAcc], ArgAcc, ArgPos, Tail1); |
|
|
|
parse(OptSpecList, OptAcc, ArgAcc, ArgPos, [[$-, $- | OptArg] = OptStr | Tail]) -> |
|
|
|
parse_option_long(OptSpecList, OptAcc, ArgAcc, ArgPos, Tail, OptStr, OptArg); |
|
|
|
%% Process short options. |
|
|
|
parse(OptSpecList, OptAcc, ArgAcc, ArgPos, [[$-, ShortName] = OptStr | Tail]) -> |
|
|
|
{Option, Tail1} = get_option(OptSpecList, OptStr, ShortName, ?OPT_SHORT, Tail), |
|
|
|
parse(OptSpecList, [Option | OptAcc], ArgAcc, ArgPos, Tail1); |
|
|
|
%% Process multiple short options with no argument. |
|
|
|
parse(OptSpecList, OptAcc, ArgAcc, ArgPos, [[$- | ShortNameList] = OptStr | Tail]) -> |
|
|
|
NewOptAcc = |
|
|
|
lists:foldl( |
|
|
|
fun (ShortName, OptAcc1) -> |
|
|
|
[get_option_no_arg(OptSpecList, OptStr, ShortName, ?OPT_SHORT) | OptAcc1] |
|
|
|
end, OptAcc, ShortNameList), |
|
|
|
parse(OptSpecList, NewOptAcc, ArgAcc, ArgPos, Tail); |
|
|
|
parse(OptSpecList, OptAcc, ArgAcc, ArgPos, [[$- | OptArg] = OptStr | Tail]) -> |
|
|
|
parse_option_short(OptSpecList, OptAcc, ArgAcc, ArgPos, Tail, OptStr, OptArg); |
|
|
|
%% Process non-option arguments. |
|
|
|
parse(OptSpecList, OptAcc, ArgAcc, ArgPos, [Arg | Tail]) -> |
|
|
|
case find_non_option_arg(OptSpecList, ArgPos) of |
|
|
|
{value, OptSpec} when ?IS_OPT_SPEC(OptSpec) -> |
|
|
|
parse(OptSpecList, [convert_option_arg(OptSpec, Arg) | OptAcc], ArgAcc, ArgPos + 1, Tail); |
|
|
|
parse(OptSpecList, [convert_option_arg(OptSpec, Arg) | OptAcc], |
|
|
|
ArgAcc, ArgPos + 1, Tail); |
|
|
|
false -> |
|
|
|
parse(OptSpecList, OptAcc, [Arg | ArgAcc], ArgPos, Tail) |
|
|
|
end; |
|
|
|
parse(OptSpecList, OptAcc, ArgAcc, _ArgPos, []) -> |
|
|
|
%% Once we have completed gathering the options we add the ones that were |
|
|
|
%% not present but had default arguments in the specification. |
|
|
|
{ok, {lists:reverse(append_default_args(OptSpecList, OptAcc)), lists:reverse(ArgAcc)}}. |
|
|
|
|
|
|
|
|
|
|
|
-spec get_option([option_spec()], string(), string() | char(), integer(), [string()]) -> |
|
|
|
{option(), [string()]}. |
|
|
|
%% @doc Retrieve the specification corresponding to an option matching a string |
|
|
|
%% received on the command line. |
|
|
|
get_option(OptSpecList, OptStr, OptName, FieldPos, Tail) -> |
|
|
|
case lists:keysearch(OptName, FieldPos, OptSpecList) of |
|
|
|
{value, {Name, _Short, _Long, ArgSpec, _Help} = OptSpec} -> |
|
|
|
% Once we have completed gathering the options we add the ones that were |
|
|
|
% not present but had default arguments in the specification. |
|
|
|
{ok, {lists:reverse(append_default_options(OptSpecList, OptAcc)), lists:reverse(ArgAcc)}}. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
%% A long option can have the following formats: |
|
|
|
%% --foo Single option 'foo', no argument |
|
|
|
%% --foo=bar Single option 'foo', argument "bar" |
|
|
|
%% --foo bar Single option 'foo', argument "bar" |
|
|
|
-spec parse_option_long([option_spec()], [option()], [string()], integer(), [string()], string(), string()) -> |
|
|
|
{ok, {[option()], [string()]}} | {error, {Reason :: atom(), Data:: any()}}. |
|
|
|
parse_option_long(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, OptArg) -> |
|
|
|
case split_assigned_arg(OptArg) of |
|
|
|
{Long, Arg} -> |
|
|
|
% Get option that has its argument within the same string |
|
|
|
% separated by an equal ('=') character (e.g. "--port=1000"). |
|
|
|
parse_option_assigned_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, Long, Arg); |
|
|
|
|
|
|
|
Long -> |
|
|
|
case lists:keysearch(Long, ?OPT_LONG, OptSpecList) of |
|
|
|
{value, {Name, _Short, Long, undefined, _Help}} -> |
|
|
|
parse(OptSpecList, [Name | OptAcc], ArgAcc, ArgPos, Args); |
|
|
|
|
|
|
|
{value, {_Name, _Short, Long, _ArgSpec, _Help} = OptSpec} -> |
|
|
|
% The option argument string is empty, but the option requires |
|
|
|
% an argument, so we look into the next string in the list. |
|
|
|
parse_option_next_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptSpec); |
|
|
|
false -> |
|
|
|
throw({error, {invalid_option, OptStr}}) |
|
|
|
end |
|
|
|
end. |
|
|
|
|
|
|
|
|
|
|
|
parse_option_assigned_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, Long, Arg) -> |
|
|
|
case lists:keysearch(Long, ?OPT_LONG, OptSpecList) of |
|
|
|
{value, {_Name, _Short, Long, ArgSpec, _Help} = OptSpec} -> |
|
|
|
case ArgSpec of |
|
|
|
undefined -> |
|
|
|
{Name, Tail}; |
|
|
|
throw({error, {invalid_option_arg, OptStr}}); |
|
|
|
_ -> |
|
|
|
case Tail of |
|
|
|
[Arg | Tail1] -> |
|
|
|
{convert_option_arg(OptSpec, Arg), Tail1}; |
|
|
|
[] -> |
|
|
|
throw({error, {missing_option_arg, Name}}) |
|
|
|
end |
|
|
|
parse(OptSpecList, [convert_option_arg(OptSpec, Arg) | OptAcc], ArgAcc, ArgPos, Args) |
|
|
|
end; |
|
|
|
false -> |
|
|
|
throw({error, {invalid_option, OptStr}}) |
|
|
|
end. |
|
|
|
|
|
|
|
-spec get_option_no_arg([option_spec()], string(), string() | char(), integer()) -> option(). |
|
|
|
%% @doc Retrieve the specification corresponding to an option that has no |
|
|
|
%% argument and matches a string received on the command line. |
|
|
|
get_option_no_arg(OptSpecList, OptStr, OptName, FieldPos) -> |
|
|
|
case lists:keysearch(OptName, FieldPos, OptSpecList) of |
|
|
|
{value, {Name, _Short, _Long, undefined, _Help}} -> |
|
|
|
Name; |
|
|
|
{value, {Name, _Short, _Long, _ArgSpec, _Help}} -> |
|
|
|
throw({error, {missing_option_arg, Name}}); |
|
|
|
|
|
|
|
-spec split_assigned_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_assigned_arg(OptStr) -> |
|
|
|
split_assigned_arg(OptStr, OptStr, []). |
|
|
|
|
|
|
|
split_assigned_arg(_OptStr, [$= | Tail], Acc) -> |
|
|
|
{lists:reverse(Acc), Tail}; |
|
|
|
split_assigned_arg(OptStr, [Char | Tail], Acc) -> |
|
|
|
split_assigned_arg(OptStr, Tail, [Char | Acc]); |
|
|
|
split_assigned_arg(OptStr, [], _Acc) -> |
|
|
|
OptStr. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
%% A short option can have the following formats: |
|
|
|
%% -a Single option 'a', no argument |
|
|
|
%% -a foo Single option 'a', argument "foo" |
|
|
|
%% -afoo Single option 'a', argument "foo" |
|
|
|
%% -abc Multiple options: 'a'; 'b'; 'c' |
|
|
|
%% -bcafoo Multiple options: 'b'; 'c'; 'a' with argument "foo" |
|
|
|
-spec parse_option_short([option_spec()], [option()], [string()], integer(), [string()], string(), string()) -> |
|
|
|
{ok, {[option()], [string()]}} | {error, {Reason :: atom(), Data:: any()}}. |
|
|
|
parse_option_short(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, [Short | Arg]) -> |
|
|
|
case lists:keysearch(Short, ?OPT_SHORT, OptSpecList) of |
|
|
|
{value, {Name, Short, _Long, undefined, _Help}} -> |
|
|
|
parse_option_short(OptSpecList, [Name | OptAcc], ArgAcc, ArgPos, Args, OptStr, Arg); |
|
|
|
|
|
|
|
{value, {_Name, Short, _Long, ArgSpec, _Help} = OptSpec} -> |
|
|
|
case Arg of |
|
|
|
[] -> |
|
|
|
% The option argument string is empty, but the option requires |
|
|
|
% an argument, so we look into the next string in the list. |
|
|
|
parse_option_next_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptSpec); |
|
|
|
|
|
|
|
_ -> |
|
|
|
case is_valid_arg(ArgSpec, Arg) of |
|
|
|
true -> |
|
|
|
parse(OptSpecList, [convert_option_arg(OptSpec, Arg) | OptAcc], ArgAcc, ArgPos, Args); |
|
|
|
_ -> |
|
|
|
parse_option_short(OptSpecList, [convert_option_no_arg(OptSpec) | OptAcc], ArgAcc, ArgPos, Args, OptStr, Arg) |
|
|
|
end |
|
|
|
end; |
|
|
|
|
|
|
|
false -> |
|
|
|
throw({error, {invalid_option, OptStr}}) |
|
|
|
end; |
|
|
|
parse_option_short(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, _OptStr, []) -> |
|
|
|
parse(OptSpecList, OptAcc, ArgAcc, ArgPos, Args). |
|
|
|
|
|
|
|
|
|
|
|
%% @doc Retrieve the argument for an option from the next string in the list of |
|
|
|
%% command-line parameters. |
|
|
|
parse_option_next_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, [Arg | Tail] = Args, {Name, _Short, _Long, ArgSpec, _Help} = OptSpec) -> |
|
|
|
% Special case for booleans: when the next string is an option we assume |
|
|
|
% the value is 'true'. |
|
|
|
case (arg_spec_type(ArgSpec) =:= boolean) andalso not is_boolean_arg(Arg) of |
|
|
|
true -> |
|
|
|
parse(OptSpecList, [{Name, true} | OptAcc], ArgAcc, ArgPos, Args); |
|
|
|
_ -> |
|
|
|
parse(OptSpecList, [convert_option_arg(OptSpec, Arg) | OptAcc], ArgAcc, ArgPos, Tail) |
|
|
|
end; |
|
|
|
parse_option_next_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, [] = Args, {Name, _Short, _Long, ArgSpec, _Help}) -> |
|
|
|
% Special case for booleans: when the next string is missing we assume the |
|
|
|
% value is 'true'. |
|
|
|
case arg_spec_type(ArgSpec) of |
|
|
|
boolean -> |
|
|
|
parse(OptSpecList, [{Name, true} | OptAcc], ArgAcc, ArgPos, Args); |
|
|
|
_ -> |
|
|
|
throw({error, {missing_option_arg, Name}}) |
|
|
|
end. |
|
|
|
|
|
|
|
|
|
|
|
-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 |
|
|
@ -148,10 +227,10 @@ find_non_option_arg([], _Pos) -> |
|
|
|
false. |
|
|
|
|
|
|
|
|
|
|
|
-spec append_default_args([option_spec()], [option()]) -> [option()]. |
|
|
|
-spec append_default_options([option_spec()], [option()]) -> [option()]. |
|
|
|
%% @doc Appends the default values of the options that are not present. |
|
|
|
append_default_args([{Name, _Short, _Long, {_Type, DefaultArg}, _Help} | Tail], OptAcc) -> |
|
|
|
append_default_args(Tail, |
|
|
|
append_default_options([{Name, _Short, _Long, {_Type, DefaultArg}, _Help} | Tail], OptAcc) -> |
|
|
|
append_default_options(Tail, |
|
|
|
case lists:keymember(Name, 1, OptAcc) of |
|
|
|
false -> |
|
|
|
[{Name, DefaultArg} | OptAcc]; |
|
|
@ -159,29 +238,47 @@ append_default_args([{Name, _Short, _Long, {_Type, DefaultArg}, _Help} | Tail], |
|
|
|
OptAcc |
|
|
|
end); |
|
|
|
%% For options with no default argument. |
|
|
|
append_default_args([_Head | Tail], OptAcc) -> |
|
|
|
append_default_args(Tail, OptAcc); |
|
|
|
append_default_args([], OptAcc) -> |
|
|
|
append_default_options([_Head | Tail], OptAcc) -> |
|
|
|
append_default_options(Tail, OptAcc); |
|
|
|
append_default_options([], OptAcc) -> |
|
|
|
OptAcc. |
|
|
|
|
|
|
|
|
|
|
|
-spec convert_option_arg(option_spec(), string()) -> [option()]. |
|
|
|
-spec convert_option_no_arg(option_spec()) -> option(). |
|
|
|
convert_option_no_arg({Name, _Short, _Long, ArgSpec, _Help}) -> |
|
|
|
case ArgSpec of |
|
|
|
% Special case for booleans: if there is no argument we assume |
|
|
|
% the value is 'true'. |
|
|
|
{boolean, _DefaultValue} -> |
|
|
|
{Name, true}; |
|
|
|
boolean -> |
|
|
|
{Name, true}; |
|
|
|
{_Type, DefaultValue} -> |
|
|
|
{Name, DefaultValue}; |
|
|
|
_ -> |
|
|
|
throw({error, {missing_option_arg, Name}}) |
|
|
|
end. |
|
|
|
|
|
|
|
|
|
|
|
-spec convert_option_arg(option_spec(), string()) -> option(). |
|
|
|
%% @doc Convert the argument passed in the command line to the data type |
|
|
|
%% indicated byt the argument specification. |
|
|
|
%% indicated by the argument specification. |
|
|
|
convert_option_arg({Name, _Short, _Long, ArgSpec, _Help}, Arg) -> |
|
|
|
try |
|
|
|
Converted = case ArgSpec of |
|
|
|
{Type, _DefaultArg} -> |
|
|
|
to_type(Type, Arg); |
|
|
|
Type when is_atom(Type) -> |
|
|
|
to_type(Type, Arg) |
|
|
|
end, |
|
|
|
{Name, Converted} |
|
|
|
{Name, to_type(arg_spec_type(ArgSpec), Arg)} |
|
|
|
catch |
|
|
|
error:_ -> |
|
|
|
throw({error, {invalid_option_arg, {Name, Arg}}}) |
|
|
|
end. |
|
|
|
|
|
|
|
|
|
|
|
-spec arg_spec_type(arg_spec()) -> arg_type() | undefined. |
|
|
|
arg_spec_type({Type, _DefaultArg}) -> |
|
|
|
Type; |
|
|
|
arg_spec_type(Type) when is_atom(Type) -> |
|
|
|
Type. |
|
|
|
|
|
|
|
|
|
|
|
-spec to_type(atom(), string()) -> arg_value(). |
|
|
|
to_type(binary, Arg) -> |
|
|
|
list_to_binary(Arg); |
|
|
@ -192,13 +289,60 @@ to_type(integer, Arg) -> |
|
|
|
to_type(float, Arg) -> |
|
|
|
list_to_float(Arg); |
|
|
|
to_type(boolean, Arg) -> |
|
|
|
is_boolean_arg(Arg); |
|
|
|
to_type(_Type, Arg) -> |
|
|
|
Arg. |
|
|
|
|
|
|
|
|
|
|
|
% -spec is_valid_option([option_spec()], Opt :: char() | string(), FieldPos :: integer()) -> boolean(). |
|
|
|
% is_valid_option(OptSpecList, Opt, FieldPos) -> |
|
|
|
% case lists:keysearch(Opt, FieldPos, OptSpecList) of |
|
|
|
% {value, {_Name, _Short, _Long, _ArgSpec, _Help}} -> |
|
|
|
% true; |
|
|
|
% _ -> |
|
|
|
% false |
|
|
|
% end. |
|
|
|
|
|
|
|
|
|
|
|
-spec is_valid_arg(arg_spec() | arg_type(), string()) -> boolean(). |
|
|
|
is_valid_arg({Type, _DefaultArg}, Arg) -> |
|
|
|
is_valid_arg(Type, Arg); |
|
|
|
is_valid_arg(boolean, Arg) -> |
|
|
|
is_boolean_arg(Arg); |
|
|
|
is_valid_arg(integer, Arg) -> |
|
|
|
is_integer_arg(Arg); |
|
|
|
is_valid_arg(float, Arg) -> |
|
|
|
is_float_arg(Arg); |
|
|
|
is_valid_arg(_Type, _Arg) -> |
|
|
|
true. |
|
|
|
|
|
|
|
|
|
|
|
-spec is_boolean_arg(string()) -> boolean(). |
|
|
|
is_boolean_arg(Arg) -> |
|
|
|
LowerArg = string:to_lower(Arg), |
|
|
|
(LowerArg =:= "true") orelse (LowerArg =:= "t") orelse |
|
|
|
(LowerArg =:= "yes") orelse (LowerArg =:= "y") orelse |
|
|
|
(LowerArg =:= "on") orelse (LowerArg =:= "enabled"); |
|
|
|
to_type(_Type, Arg) -> |
|
|
|
Arg. |
|
|
|
(LowerArg =:= "on") orelse (LowerArg =:= "enabled") orelse |
|
|
|
(LowerArg =:= "1"). |
|
|
|
|
|
|
|
|
|
|
|
-spec is_integer_arg(string()) -> boolean(). |
|
|
|
is_integer_arg([Head | Tail]) when Head >= $0, Head =< $9 -> |
|
|
|
is_integer_arg(Tail); |
|
|
|
is_integer_arg([_Head | _Tail]) -> |
|
|
|
false; |
|
|
|
is_integer_arg([]) -> |
|
|
|
true. |
|
|
|
|
|
|
|
|
|
|
|
-spec is_float_arg(string()) -> boolean(). |
|
|
|
is_float_arg([Head | Tail]) when (Head >= $0 andalso Head =< $9) orelse Head =:= $. -> |
|
|
|
is_float_arg(Tail); |
|
|
|
is_float_arg([_Head | _Tail]) -> |
|
|
|
false; |
|
|
|
is_float_arg([]) -> |
|
|
|
true. |
|
|
|
|
|
|
|
|
|
|
|
-spec usage([option_spec()], string()) -> ok. |
|
|
|
%%-------------------------------------------------------------------- |
|
|
@ -222,10 +366,10 @@ usage_cmd_line([{Name, Short, Long, ArgSpec, _Help} | Tail], Acc) -> |
|
|
|
case ArgSpec of |
|
|
|
undefined -> |
|
|
|
if |
|
|
|
%% For options with short form and no argument. |
|
|
|
% For options with short form and no argument. |
|
|
|
Short =/= undefined -> |
|
|
|
[$\s, $[, $-, Short, $]]; |
|
|
|
%% For options with only long form and no argument. |
|
|
|
% For options with only long form and no argument. |
|
|
|
Long =/= undefined -> |
|
|
|
[$\s, $[, $-, $-, Long, $]]; |
|
|
|
true -> |
|
|
@ -233,13 +377,13 @@ usage_cmd_line([{Name, Short, Long, ArgSpec, _Help} | Tail], Acc) -> |
|
|
|
end; |
|
|
|
_ -> |
|
|
|
if |
|
|
|
%% For options with short form and argument. |
|
|
|
% For options with short form and argument. |
|
|
|
Short =/= undefined -> |
|
|
|
[$\s, $[, $-, Short, $\s, $<, atom_to_list(Name), $>, $]]; |
|
|
|
%% For options with only long form and argument. |
|
|
|
% For options with only long form and argument. |
|
|
|
Long =/= undefined -> |
|
|
|
[$\s, $[, $-, $-, Long, $\s, $<, atom_to_list(Name), $>, $]]; |
|
|
|
%% For options with neither short nor long form and argument. |
|
|
|
% For options with neither short nor long form and argument. |
|
|
|
true -> |
|
|
|
[$\s, $<, atom_to_list(Name), $>] |
|
|
|
end |
|
|
@ -260,19 +404,19 @@ usage_options([{Name, Short, Long, _ArgSpec, _Help} = OptSpec | Tail], Acc) -> |
|
|
|
case Long of |
|
|
|
undefined -> |
|
|
|
case Short of |
|
|
|
%% Neither short nor long form (non-option argument). |
|
|
|
% Neither short nor long form (non-option argument). |
|
|
|
undefined -> |
|
|
|
[$<, atom_to_list(Name), $>]; |
|
|
|
%% Only short form. |
|
|
|
% Only short form. |
|
|
|
_ -> |
|
|
|
[$-, Short] |
|
|
|
end; |
|
|
|
_ -> |
|
|
|
case Short of |
|
|
|
%% Only long form. |
|
|
|
% Only long form. |
|
|
|
undefined -> |
|
|
|
[$-, $-, Long]; |
|
|
|
%% Both short and long form. |
|
|
|
% Both short and long form. |
|
|
|
_ -> |
|
|
|
[$-, Short, $,, $\s, $-, $-, Long] |
|
|
|
end |
|
|
@ -291,9 +435,9 @@ add_option_help({_Name, _Short, _Long, _ArgSpec, Help}, Prefix, Acc) when is_lis |
|
|
|
Tab = lists:duplicate(ceiling(TabSize / ?TAB_LENGTH), $\t), |
|
|
|
[[$\s, $\s, FlatPrefix, Tab, Help, $\n] | Acc]; |
|
|
|
_ -> |
|
|
|
%% The indentation for the option description is 3 tabs (i.e. 24 characters) |
|
|
|
%% IMPORTANT: Change the number of tabs below if you change the |
|
|
|
%% value of the INDENTATION macro. |
|
|
|
% The indentation for the option description is 3 tabs (i.e. 24 characters) |
|
|
|
% IMPORTANT: Change the number of tabs below if you change the |
|
|
|
% value of the INDENTATION macro. |
|
|
|
[[$\t, $\t, $\t, Help, $\n], [$\s, $\s, FlatPrefix, $\n] | Acc] |
|
|
|
end; |
|
|
|
add_option_help(_Opt, _Prefix, Acc) -> |
|
|
@ -305,8 +449,8 @@ add_option_help(_Opt, _Prefix, Acc) -> |
|
|
|
ceiling(X) -> |
|
|
|
T = erlang:trunc(X), |
|
|
|
case (X - T) of |
|
|
|
%% Neg when Neg < 0 -> |
|
|
|
%% T; |
|
|
|
% Neg when Neg < 0 -> |
|
|
|
% T; |
|
|
|
Pos when Pos > 0 -> |
|
|
|
T + 1; |
|
|
|
_ -> |
|
|
|