Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Update getopt.erl

  • Loading branch information...
commit 5af57f80f05e9e6e52b0db399be725659850cf27 1 parent 3fb1659
Tuncer Ayaz authored April 09, 2012

Showing 1 changed file with 206 additions and 93 deletions. Show diff stats Hide diff stats

  1. 299  src/getopt.erl
299  src/getopt.erl
@@ -53,6 +53,8 @@
53 53
                    ArgSpec :: arg_spec(),
54 54
                    Help    :: string() | undefined
55 55
                   }.
  56
+%% Output streams
  57
+-type output_stream() :: 'standard_io' | 'standard_error'.
56 58
 
57 59
 
58 60
 %% @doc  Parse the command line options and arguments returning a list of tuples
@@ -79,26 +81,25 @@ parse(OptSpecList, CmdLine) ->
79 81
     {ok, {[option()], [string()]}}.
80 82
 %% Process the option terminator.
81 83
 parse(OptSpecList, OptAcc, ArgAcc, _ArgPos, ["--" | Tail]) ->
82  
-    % Any argument present after the terminator is not considered an option.
  84
+    %% Any argument present after the terminator is not considered an option.
83 85
     {ok, {lists:reverse(append_default_options(OptSpecList, OptAcc)), lists:reverse(ArgAcc, Tail)}};
84 86
 %% Process long options.
85 87
 parse(OptSpecList, OptAcc, ArgAcc, ArgPos, ["--" ++ OptArg = OptStr | Tail]) ->
86  
-    parse_option_long(OptSpecList, OptAcc, ArgAcc, ArgPos, Tail, OptStr, OptArg);
  88
+    parse_long_option(OptSpecList, OptAcc, ArgAcc, ArgPos, Tail, OptStr, OptArg);
87 89
 %% Process short options.
88 90
 parse(OptSpecList, OptAcc, ArgAcc, ArgPos, ["-" ++ ([_Char | _] = OptArg) = OptStr | Tail]) ->
89  
-    parse_option_short(OptSpecList, OptAcc, ArgAcc, ArgPos, Tail, OptStr, OptArg);
  91
+    parse_short_option(OptSpecList, OptAcc, ArgAcc, ArgPos, Tail, OptStr, OptArg);
90 92
 %% Process non-option arguments.
91 93
 parse(OptSpecList, OptAcc, ArgAcc, ArgPos, [Arg | Tail]) ->
92 94
     case find_non_option_arg(OptSpecList, ArgPos) of
93 95
         {value, OptSpec} when ?IS_OPT_SPEC(OptSpec) ->
94  
-            parse(OptSpecList, [convert_option_arg(OptSpec, Arg) | OptAcc],
95  
-                  ArgAcc, ArgPos + 1, Tail);
  96
+            parse(OptSpecList, add_option_with_arg(OptSpec, Arg, OptAcc), ArgAcc, ArgPos + 1, Tail);
96 97
         false ->
97 98
             parse(OptSpecList, OptAcc, [Arg | ArgAcc], ArgPos, Tail)
98 99
     end;
99 100
 parse(OptSpecList, OptAcc, ArgAcc, _ArgPos, []) ->
100  
-    % Once we have completed gathering the options we add the ones that were
101  
-    % not present but had default arguments in the specification.
  101
+    %% Once we have completed gathering the options we add the ones that were
  102
+    %% not present but had default arguments in the specification.
102 103
     {ok, {lists:reverse(append_default_options(OptSpecList, OptAcc)), lists:reverse(ArgAcc)}}.
103 104
 
104 105
 
@@ -108,14 +109,14 @@ parse(OptSpecList, OptAcc, ArgAcc, _ArgPos, []) ->
108 109
 %%        --foo      Single option 'foo', no argument
109 110
 %%        --foo=bar  Single option 'foo', argument "bar"
110 111
 %%        --foo bar  Single option 'foo', argument "bar"
111  
--spec parse_option_long([option_spec()], [option()], [string()], integer(), [string()], string(), string()) ->
  112
+-spec parse_long_option([option_spec()], [option()], [string()], integer(), [string()], string(), string()) ->
112 113
           {ok, {[option()], [string()]}}.
113  
-parse_option_long(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, OptArg) ->
  114
+parse_long_option(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, OptArg) ->
114 115
     case split_assigned_arg(OptArg) of
115 116
         {Long, Arg} ->
116  
-            % Get option that has its argument within the same string
117  
-            % separated by an equal ('=') character (e.g. "--port=1000").
118  
-            parse_option_assigned_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, Long, Arg);
  117
+            %% Get option that has its argument within the same string
  118
+            %% separated by an equal ('=') character (e.g. "--port=1000").
  119
+            parse_long_option_assigned_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, Long, Arg);
119 120
 
120 121
         Long ->
121 122
             case lists:keyfind(Long, ?OPT_LONG, OptSpecList) of
@@ -123,9 +124,10 @@ parse_option_long(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, OptArg) ->
123 124
                     parse(OptSpecList, [Name | OptAcc], ArgAcc, ArgPos, Args);
124 125
 
125 126
                 {_Name, _Short, Long, _ArgSpec, _Help} = OptSpec ->
126  
-                    % The option argument string is empty, but the option requires
127  
-                    % an argument, so we look into the next string in the list.
128  
-                    parse_option_next_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptSpec);
  127
+                    %% The option argument string is empty, but the option requires
  128
+                    %% an argument, so we look into the next string in the list.
  129
+                    %% e.g ["--port", "1000"]
  130
+                    parse_long_option_next_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptSpec);
129 131
                 false ->
130 132
                     throw({error, {invalid_option, OptStr}})
131 133
             end
@@ -135,17 +137,17 @@ parse_option_long(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, OptArg) ->
135 137
 %% @doc Parse an option where the argument is 'assigned' in the same string using
136 138
 %%      the '=' character, add it to the option accumulator and continue parsing the
137 139
 %%      rest of the arguments recursively. This syntax is only valid for long options.
138  
--spec parse_option_assigned_arg([option_spec()], [option()], [string()], integer(),
139  
-                                [string()], string(), string(), string()) ->
140  
-          {ok, {[option()], [string()]}}.
141  
-parse_option_assigned_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, Long, Arg) ->
  140
+-spec parse_long_option_assigned_arg([option_spec()], [option()], [string()], integer(),
  141
+                                     [string()], string(), string(), string()) ->
  142
+                                            {ok, {[option()], [string()]}}.
  143
+parse_long_option_assigned_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, Long, Arg) ->
142 144
     case lists:keyfind(Long, ?OPT_LONG, OptSpecList) of
143 145
         {_Name, _Short, Long, ArgSpec, _Help} = OptSpec ->
144 146
             case ArgSpec of
145 147
                 undefined ->
146 148
                     throw({error, {invalid_option_arg, OptStr}});
147 149
                 _ ->
148  
-                    parse(OptSpecList, [convert_option_arg(OptSpec, Arg) | OptAcc], ArgAcc, ArgPos, Args)
  150
+                    parse(OptSpecList, add_option_with_assigned_arg(OptSpec, Arg, OptAcc), ArgAcc, ArgPos, Args)
149 151
             end;
150 152
         false ->
151 153
             throw({error, {invalid_option, OptStr}})
@@ -166,6 +168,25 @@ split_assigned_arg(OptStr, [], _Acc) ->
166 168
     OptStr.
167 169
 
168 170
 
  171
+%% @doc Retrieve the argument for an option from the next string in the list of
  172
+%%      command-line parameters or set the value of the argument from the argument
  173
+%%      specification (for boolean and integer arguments), if possible.
  174
+parse_long_option_next_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, {Name, _Short, _Long, ArgSpec, _Help} = OptSpec) ->
  175
+    ArgSpecType = arg_spec_type(ArgSpec),
  176
+    case Args =:= [] orelse is_implicit_arg(ArgSpecType, hd(Args)) of
  177
+        true ->
  178
+            parse(OptSpecList, add_option_with_implicit_arg(OptSpec, OptAcc), ArgAcc, ArgPos, Args);
  179
+        false ->
  180
+            [Arg | Tail] = Args,
  181
+            try
  182
+                parse(OptSpecList, [{Name, to_type(ArgSpecType, Arg)} | OptAcc], ArgAcc, ArgPos, Tail)
  183
+            catch
  184
+                error:_ ->
  185
+                    throw({error, {invalid_option_arg, {Name, Arg}}})
  186
+            end
  187
+    end.
  188
+
  189
+
169 190
 %% @doc Parse a short option, add it to the option accumulator and continue
170 191
 %%      parsing the rest of the arguments recursively.
171 192
 %%      A short option can have the following syntax:
@@ -174,55 +195,62 @@ split_assigned_arg(OptStr, [], _Acc) ->
174 195
 %%        -afoo    Single option 'a', argument "foo"
175 196
 %%        -abc     Multiple options: 'a'; 'b'; 'c'
176 197
 %%        -bcafoo  Multiple options: 'b'; 'c'; 'a' with argument "foo"
177  
--spec parse_option_short([option_spec()], [option()], [string()], integer(), [string()], string(), string()) ->
  198
+%%        -aaa     Multiple repetitions of option 'a' (only valid for options with integer arguments)
  199
+-spec parse_short_option([option_spec()], [option()], [string()], integer(), [string()], string(), string()) ->
178 200
     {ok, {[option()], [string()]}}.
179  
-parse_option_short(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, [Short | Arg]) ->
  201
+parse_short_option(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, OptArg) ->
  202
+    parse_short_option(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, first, OptArg).
  203
+
  204
+parse_short_option(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptStr, OptPos, [Short | Arg]) ->
180 205
     case lists:keyfind(Short, ?OPT_SHORT, OptSpecList) of
181 206
         {Name, Short, _Long, undefined, _Help} ->
182  
-            parse_option_short(OptSpecList, [Name | OptAcc], ArgAcc, ArgPos, Args, OptStr, Arg);
  207
+            parse_short_option(OptSpecList, [Name | OptAcc], ArgAcc, ArgPos, Args, OptStr, first, Arg);
183 208
 
184 209
         {_Name, Short, _Long, ArgSpec, _Help} = OptSpec ->
  210
+            %% The option has a specification, so it requires an argument.
185 211
             case Arg of
186 212
                 [] ->
187  
-                    % The option argument string is empty, but the option requires
188  
-                    % an argument, so we look into the next string in the list.
189  
-                    parse_option_next_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptSpec);
  213
+                    %% The option argument string is empty, but the option requires
  214
+                    %% an argument, so we look into the next string in the list.
  215
+                    parse_short_option_next_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, OptSpec, OptPos);
190 216
 
191 217
                 _ ->
192 218
                     case is_valid_arg(ArgSpec, Arg) of
193 219
                         true ->
194  
-                            parse(OptSpecList, [convert_option_arg(OptSpec, Arg) | OptAcc], ArgAcc, ArgPos, Args);
  220
+                            parse(OptSpecList, add_option_with_arg(OptSpec, Arg, OptAcc), ArgAcc, ArgPos, Args);
195 221
                         _ ->
196  
-                            parse_option_short(OptSpecList, [convert_option_no_arg(OptSpec) | OptAcc], ArgAcc, ArgPos, Args, OptStr, Arg)
  222
+                            NewOptAcc = case OptPos of
  223
+                                            first -> add_option_with_implicit_arg(OptSpec, OptAcc);
  224
+                                            _     -> add_option_with_implicit_incrementable_arg(OptSpec, OptAcc)
  225
+                                        end,
  226
+                            parse_short_option(OptSpecList, NewOptAcc, ArgAcc, ArgPos, Args, OptStr, next, Arg)
197 227
                     end
198 228
             end;
199 229
 
200 230
         false ->
201 231
             throw({error, {invalid_option, OptStr}})
202 232
     end;
203  
-parse_option_short(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, _OptStr, []) ->
  233
+parse_short_option(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, _OptStr, _OptPos, []) ->
204 234
     parse(OptSpecList, OptAcc, ArgAcc, ArgPos, Args).
205 235
 
206 236
 
207 237
 %% @doc Retrieve the argument for an option from the next string in the list of
208  
-%%      command-line parameters.
209  
-parse_option_next_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, [Arg | Tail] = Args, {Name, _Short, _Long, ArgSpec, _Help} = OptSpec) ->
210  
-    % Special case for booleans: when the next string is an option we assume
211  
-    % the value is 'true'.
212  
-    case (arg_spec_type(ArgSpec) =:= boolean) andalso not is_boolean_arg(Arg) of
  238
+%%      command-line parameters or set the value of the argument from the argument
  239
+%%      specification (for boolean and integer arguments), if possible.
  240
+parse_short_option_next_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, Args, {Name, _Short, _Long, ArgSpec, _Help} = OptSpec, OptPos) ->
  241
+    case Args =:= [] orelse is_implicit_arg(ArgSpec, hd(Args)) of
  242
+        true when OptPos =:= first ->
  243
+            parse(OptSpecList, add_option_with_implicit_arg(OptSpec, OptAcc), ArgAcc, ArgPos, Args);
213 244
         true ->
214  
-            parse(OptSpecList, [{Name, true} | OptAcc], ArgAcc, ArgPos, Args);
215  
-        _ ->
216  
-            parse(OptSpecList, [convert_option_arg(OptSpec, Arg) | OptAcc], ArgAcc, ArgPos, Tail)
217  
-    end;
218  
-parse_option_next_arg(OptSpecList, OptAcc, ArgAcc, ArgPos, [] = Args, {Name, _Short, _Long, ArgSpec, _Help}) ->
219  
-    % Special case for booleans: when the next string is missing we assume the
220  
-    % value is 'true'.
221  
-    case arg_spec_type(ArgSpec) of
222  
-        boolean ->
223  
-            parse(OptSpecList, [{Name, true} | OptAcc], ArgAcc, ArgPos, Args);
224  
-        _ ->
225  
-            throw({error, {missing_option_arg, Name}})
  245
+            parse(OptSpecList, add_option_with_implicit_incrementable_arg(OptSpec, OptAcc), ArgAcc, ArgPos, Args);
  246
+        false ->
  247
+            [Arg | Tail] = Args,
  248
+            try
  249
+                parse(OptSpecList, [{Name, to_type(ArgSpec, Arg)} | OptAcc], ArgAcc, ArgPos, Tail)
  250
+            catch
  251
+                error:_ ->
  252
+                    throw({error, {invalid_option_arg, {Name, Arg}}})
  253
+            end
226 254
     end.
227 255
 
228 256
 
@@ -257,32 +285,79 @@ append_default_options([], OptAcc) ->
257 285
     OptAcc.
258 286
 
259 287
 
260  
--spec convert_option_no_arg(option_spec()) -> compound_option().
261  
-convert_option_no_arg({Name, _Short, _Long, ArgSpec, _Help}) ->
262  
-    case ArgSpec of
263  
-        % Special case for booleans: if there is no argument we assume
264  
-        % the value is 'true'.
265  
-        {boolean, _DefaultValue} ->
266  
-            {Name, true};
267  
-        boolean ->
268  
-            {Name, true};
269  
-        _ ->
270  
-            throw({error, {missing_option_arg, Name}})
  288
+%% @doc Add an option with argument converting it to the data type indicated by the
  289
+%%      argument specification.
  290
+-spec add_option_with_arg(option_spec(), string(), [option()]) -> [option()].
  291
+add_option_with_arg({Name, _Short, _Long, ArgSpec, _Help} = OptSpec, Arg, OptAcc) ->
  292
+    case is_valid_arg(ArgSpec, Arg) of
  293
+        true ->
  294
+            try
  295
+                [{Name, to_type(ArgSpec, Arg)} | OptAcc]
  296
+            catch
  297
+                error:_ ->
  298
+                    throw({error, {invalid_option_arg, {Name, Arg}}})
  299
+            end;
  300
+        false ->
  301
+            add_option_with_implicit_arg(OptSpec, OptAcc)
271 302
     end.
272 303
 
273 304
 
274  
-%% @doc Convert the argument passed in the command line to the data type
275  
-%%      indicated by the argument specification.
276  
--spec convert_option_arg(option_spec(), string()) -> compound_option().
277  
-convert_option_arg({Name, _Short, _Long, ArgSpec, _Help}, Arg) ->
  305
+%% @doc Add an option with argument that was part of an assignment expression
  306
+%%      (e.g. "--verbose=3") converting it to the data type indicated by the
  307
+%%      argument specification.
  308
+-spec add_option_with_assigned_arg(option_spec(), string(), [option()]) -> [option()].
  309
+add_option_with_assigned_arg({Name, _Short, _Long, ArgSpec, _Help}, Arg, OptAcc) ->
278 310
     try
279  
-        {Name, to_type(arg_spec_type(ArgSpec), Arg)}
  311
+        [{Name, to_type(ArgSpec, Arg)} | OptAcc]
280 312
     catch
281 313
         error:_ ->
282 314
             throw({error, {invalid_option_arg, {Name, Arg}}})
283 315
     end.
284 316
 
285 317
 
  318
+%% @doc Add an option that required an argument but did not have one. Some data
  319
+%%      types (boolean, integer) allow implicit or assumed arguments.
  320
+-spec add_option_with_implicit_arg(option_spec(), [option()]) -> [option()].
  321
+add_option_with_implicit_arg({Name, _Short, _Long, ArgSpec, _Help}, OptAcc) ->
  322
+    case arg_spec_type(ArgSpec) of
  323
+        boolean ->
  324
+            %% Special case for boolean arguments: if there is no argument we
  325
+            %% set the value to 'true'.
  326
+            [{Name, true} | OptAcc];
  327
+        integer ->
  328
+            %% Special case for integer arguments: if the option had not been set
  329
+            %% before we set the value to 1. This is needed to support options like
  330
+            %% "-v" to return something like {verbose, 1}.
  331
+            [{Name, 1} | OptAcc];
  332
+        _ ->
  333
+            throw({error, {missing_option_arg, Name}})
  334
+    end.
  335
+
  336
+
  337
+%% @doc Add an option with an implicit or assumed argument.
  338
+-spec add_option_with_implicit_incrementable_arg(option_spec() | arg_spec(), [option()]) -> [option()].
  339
+add_option_with_implicit_incrementable_arg({Name, _Short, _Long, ArgSpec, _Help}, OptAcc) ->
  340
+    case arg_spec_type(ArgSpec) of
  341
+        boolean ->
  342
+            %% Special case for boolean arguments: if there is no argument we
  343
+            %% set the value to 'true'.
  344
+            [{Name, true} | OptAcc];
  345
+        integer ->
  346
+            %% Special case for integer arguments: if the option had not been set
  347
+            %% before we set the value to 1; if not we increment the previous value
  348
+            %% the option had. This is needed to support options like "-vvv" to
  349
+            %% return something like {verbose, 3}.
  350
+            case OptAcc of
  351
+                [{Name, Count} | Tail] ->
  352
+                    [{Name, Count + 1} | Tail];
  353
+                _ ->
  354
+                    [{Name, 1} | OptAcc]
  355
+            end;
  356
+        _ ->
  357
+            throw({error, {missing_option_arg, Name}})
  358
+    end.
  359
+
  360
+
286 361
 %% @doc Retrieve the data type form an argument specification.
287 362
 -spec arg_spec_type(arg_spec()) -> arg_type() | undefined.
288 363
 arg_spec_type({Type, _DefaultArg}) ->
@@ -292,7 +367,9 @@ arg_spec_type(Type) when is_atom(Type) ->
292 367
 
293 368
 
294 369
 %% @doc Convert an argument string to its corresponding data type.
295  
--spec to_type(arg_type(), string()) -> arg_value().
  370
+-spec to_type(arg_spec() | arg_type(), string()) -> arg_value().
  371
+to_type({Type, _DefaultArg}, Arg) ->
  372
+    to_type(Type, Arg);
296 373
 to_type(binary, Arg) ->
297 374
     list_to_binary(Arg);
298 375
 to_type(atom, Arg) ->
@@ -340,13 +417,24 @@ is_valid_arg({Type, _DefaultArg}, Arg) ->
340 417
 is_valid_arg(boolean, Arg) ->
341 418
     is_boolean_arg(Arg);
342 419
 is_valid_arg(integer, Arg) ->
343  
-    is_integer_arg(Arg);
  420
+    is_non_neg_integer_arg(Arg);
344 421
 is_valid_arg(float, Arg) ->
345  
-    is_float_arg(Arg);
  422
+    is_non_neg_float_arg(Arg);
346 423
 is_valid_arg(_Type, _Arg) ->
347 424
     true.
348 425
 
349 426
 
  427
+-spec is_implicit_arg(arg_spec(), nonempty_string()) -> boolean().
  428
+is_implicit_arg({Type, _DefaultArg}, Arg) ->
  429
+    is_implicit_arg(Type, Arg);
  430
+is_implicit_arg(boolean, Arg) ->
  431
+    not is_boolean_arg(Arg);
  432
+is_implicit_arg(integer, Arg) ->
  433
+    not is_integer_arg(Arg);
  434
+is_implicit_arg(_Type, _Arg) ->
  435
+    false.
  436
+
  437
+
350 438
 -spec is_boolean_arg(string()) -> boolean().
351 439
 is_boolean_arg(Arg) ->
352 440
     LowerArg = string:to_lower(Arg),
@@ -354,51 +442,76 @@ is_boolean_arg(Arg) ->
354 442
 
355 443
 
356 444
 -spec is_integer_arg(string()) -> boolean().
357  
-is_integer_arg([Head | Tail]) when Head >= $0, Head =< $9 ->
358  
-    is_integer_arg(Tail);
359  
-is_integer_arg([_Head | _Tail]) ->
  445
+is_integer_arg([$- | Tail]) ->
  446
+    is_non_neg_integer_arg(Tail);
  447
+is_integer_arg(Arg) ->
  448
+    is_non_neg_integer_arg(Arg).
  449
+
  450
+
  451
+-spec is_non_neg_integer_arg(string()) -> boolean().
  452
+is_non_neg_integer_arg([Head | Tail]) when Head >= $0, Head =< $9 ->
  453
+    is_non_neg_integer_arg(Tail);
  454
+is_non_neg_integer_arg([_Head | _Tail]) ->
360 455
     false;
361  
-is_integer_arg([]) ->
  456
+is_non_neg_integer_arg([]) ->
362 457
     true.
363 458
 
364 459
 
365  
--spec is_float_arg(string()) -> boolean().
366  
-is_float_arg([Head | Tail]) when (Head >= $0 andalso Head =< $9) orelse Head =:= $. ->
367  
-    is_float_arg(Tail);
368  
-is_float_arg([_Head | _Tail]) ->
  460
+-spec is_non_neg_float_arg(string()) -> boolean().
  461
+is_non_neg_float_arg([Head | Tail]) when (Head >= $0 andalso Head =< $9) orelse Head =:= $. ->
  462
+    is_non_neg_float_arg(Tail);
  463
+is_non_neg_float_arg([_Head | _Tail]) ->
369 464
     false;
370  
-is_float_arg([]) ->
  465
+is_non_neg_float_arg([]) ->
371 466
     true.
372 467
 
373 468
 
374  
-%% @doc  Show a message on stdout indicating the command line options and
  469
+%% @doc  Show a message on standard_error indicating the command line options and
375 470
 %%       arguments that are supported by the program.
376 471
 -spec usage([option_spec()], string()) -> ok.
377 472
 usage(OptSpecList, ProgramName) ->
378  
-    io:format("Usage: ~s~s~n~n~s~n",
379  
-              [ProgramName, usage_cmd_line(OptSpecList), usage_options(OptSpecList)]).
  473
+	usage(OptSpecList, ProgramName, standard_error).
380 474
 
381 475
 
382  
-%% @doc  Show a message on stdout indicating the command line options and
  476
+%% @doc  Show a message on standard_error or standard_io indicating the command line options and
  477
+%%       arguments that are supported by the program.
  478
+-spec usage([option_spec()], string(), output_stream() | string()) -> ok.
  479
+usage(OptSpecList, ProgramName, OutputStream) when is_atom(OutputStream) ->
  480
+    io:format(OutputStream, "Usage: ~s~s~n~n~s~n",
  481
+              [ProgramName, usage_cmd_line(OptSpecList), usage_options(OptSpecList)]);
  482
+%% @doc  Show a message on standard_error indicating the command line options and
383 483
 %%       arguments that are supported by the program. The CmdLineTail argument
384 484
 %%       is a string that is added to the end of the usage command line.
385  
--spec usage([option_spec()], string(), string()) -> ok.
386 485
 usage(OptSpecList, ProgramName, CmdLineTail) ->
387  
-    io:format("Usage: ~s~s ~s~n~n~s~n",
388  
-              [ProgramName, usage_cmd_line(OptSpecList), CmdLineTail, usage_options(OptSpecList)]).
  486
+	usage(OptSpecList, ProgramName, CmdLineTail, standard_error).
389 487
 
390 488
 
391  
-%% @doc  Show a message on stdout indicating the command line options and
  489
+%% @doc  Show a message on standard_error or standard_io indicating the command line options and
  490
+%%       arguments that are supported by the program. The CmdLineTail argument
  491
+%%       is a string that is added to the end of the usage command line.
  492
+-spec usage([option_spec()], string(), string(), output_stream() | [{string(), string()}]) -> ok.
  493
+usage(OptSpecList, ProgramName, CmdLineTail, OutputStream) when is_atom(OutputStream) ->
  494
+	io:format(OutputStream, "Usage: ~s~s ~s~n~n~s~n",
  495
+              [ProgramName, usage_cmd_line(OptSpecList), CmdLineTail, usage_options(OptSpecList)]);
  496
+%% @doc  Show a message on standard_error indicating the command line options and
392 497
 %%       arguments that are supported by the program. The CmdLineTail and OptionsTail
393 498
 %%       arguments are a string that is added to the end of the usage command line
394 499
 %%       and a list of tuples that are added to the end of the options' help lines.
395  
--spec usage([option_spec()], string(), string(), [{string(), string()}]) -> ok.
396 500
 usage(OptSpecList, ProgramName, CmdLineTail, OptionsTail) ->
  501
+	usage(OptSpecList, ProgramName, CmdLineTail, OptionsTail, standard_error).
  502
+
  503
+
  504
+%% @doc  Show a message on standard_error or standard_io indicating the command line options and
  505
+%%       arguments that are supported by the program. The CmdLineTail and OptionsTail
  506
+%%       arguments are a string that is added to the end of the usage command line
  507
+%%       and a list of tuples that are added to the end of the options' help lines.
  508
+-spec usage([option_spec()], string(), string(), [{string(), string()}], output_stream()) -> ok.
  509
+usage(OptSpecList, ProgramName, CmdLineTail, OptionsTail, OutputStream) ->
397 510
     UsageOptions = lists:foldl(
398 511
                      fun ({Prefix, Help}, Acc) ->
399 512
                              add_option_help(Prefix, Help, Acc)
400 513
                      end, usage_options_reverse(OptSpecList, []), OptionsTail),
401  
-    io:format("Usage: ~s~s ~s~n~n~s~n",
  514
+    io:format(OutputStream, "Usage: ~s~s ~s~n~n~s~n",
402 515
               [ProgramName, usage_cmd_line(OptSpecList), CmdLineTail,
403 516
                lists:flatten(lists:reverse(UsageOptions))]).
404 517
 
@@ -414,10 +527,10 @@ usage_cmd_line([{Name, Short, Long, ArgSpec, _Help} | Tail], Acc) ->
414 527
         case ArgSpec of
415 528
             undefined ->
416 529
                 if
417  
-                    % For options with short form and no argument.
  530
+                    %% For options with short form and no argument.
418 531
                     Short =/= undefined ->
419 532
                         [$\s, $[, $-, Short, $]];
420  
-                    % For options with only long form and no argument.
  533
+                    %% For options with only long form and no argument.
421 534
                     Long =/= undefined ->
422 535
                         [$\s, $[, $-, $-, Long, $]];
423 536
                     true ->
@@ -425,13 +538,13 @@ usage_cmd_line([{Name, Short, Long, ArgSpec, _Help} | Tail], Acc) ->
425 538
                 end;
426 539
             _ ->
427 540
                 if
428  
-                    % For options with short form and argument.
  541
+                    %% For options with short form and argument.
429 542
                     Short =/= undefined ->
430 543
                         [$\s, $[, $-, Short, $\s, $<, atom_to_list(Name), $>, $]];
431  
-                    % For options with only long form and argument.
  544
+                    %% For options with only long form and argument.
432 545
                     Long =/= undefined ->
433 546
                         [$\s, $[, $-, $-, Long, $\s, $<, atom_to_list(Name), $>, $]];
434  
-                    % For options with neither short nor long form and argument.
  547
+                    %% For options with neither short nor long form and argument.
435 548
                     true ->
436 549
                         [$\s, $<, atom_to_list(Name), $>]
437 550
                 end
@@ -452,19 +565,19 @@ usage_options_reverse([{Name, Short, Long, _ArgSpec, Help} | Tail], Acc) ->
452 565
         case Long of
453 566
             undefined ->
454 567
                 case Short of
455  
-                    % Neither short nor long form (non-option argument).
  568
+                    %% Neither short nor long form (non-option argument).
456 569
                     undefined ->
457 570
                         [$<, atom_to_list(Name), $>];
458  
-                    % Only short form.
  571
+                    %% Only short form.
459 572
                     _ ->
460 573
                         [$-, Short]
461 574
                 end;
462 575
             _ ->
463 576
                 case Short of
464  
-                    % Only long form.
  577
+                    %% Only long form.
465 578
                     undefined ->
466 579
                         [$-, $- | Long];
467  
-                    % Both short and long form.
  580
+                    %% Both short and long form.
468 581
                     _ ->
469 582
                         [$-, Short, $,, $\s, $-, $- | Long]
470 583
                 end

0 notes on commit 5af57f8

Please sign in to comment.
Something went wrong with that request. Please try again.