File Coverage

blib/lib/Getopt/Tree.pm
Criterion Covered Total %
statement 217 292 74.3
branch 95 160 59.3
condition 27 48 56.2
subroutine 17 18 94.4
pod 2 7 28.5
total 358 525 68.1


line stmt bran cond sub pod time code
1             package Getopt::Tree;
2              
3 1     1   21914 use strict;
  1         1  
  1         25  
4 1     1   1766 use Text::Wrap;
  1         3783  
  1         64  
5 1     1   1185 use Getopt::Long qw( :config no_auto_abbrev no_getopt_compat no_permute require_order no_ignore_case_always );
  1         15543  
  1         7  
6 1     1   263 use File::Basename;
  1         2  
  1         103  
7              
8             BEGIN {
9 1     1   6 use Exporter ();
  1         2  
  1         50  
10 1     1   3 our ( @ISA, @EXPORT );
11              
12 1         12 @ISA = qw(Exporter);
13 1         19 @EXPORT = qw/ parse_command_line print_usage /;
14             }
15              
16 1     1   5 use vars qw( $VERSION );
  1         2  
  1         50  
17             $VERSION = '1.12';
18              
19 1     1   36 use constant ABBR_PARAM_SEPARATOR => ', ';
  1         2  
  1         73  
20 1     1   5 use constant ABBR_PARAM_SEPARATOR_LENGTH => length( ABBR_PARAM_SEPARATOR );
  1         2  
  1         41  
21 1     1   5 use constant DEPTH_STR => ' ';
  1         2  
  1         3406  
22              
23             our $USAGE_HEADER = '';
24             our $USAGE_FOOTER = '';
25             our $SWITCH_PREFIX_STR = '-';
26              
27             =head1 NAME
28              
29             Getopt::Tree - Get tree-like options (like the route command).
30              
31             =head1 ABSTRACT
32              
33             Getopt::Tree is a module to help parse and validate command line parameters
34             built on top of Getopt::Long. Getopt::Tree allows the developer to specify an
35             array parameters, including the name, abbreviation, type, description, and any
36             parameters that are applicable to and/or dependent on that parameter.
37              
38             =head1 EXAMPLE
39              
40             =head2 Simple "route" example
41              
42             # Accept the commands add, remove, print, and their associated dependent
43             # options.
44             my $p = [
45             {
46             name => 'add',
47             exists => 1,
48             descr => 'Add a new route',
49             params => [
50             {
51             name => 'gateway',
52             abbr => 'gw',
53             descr => 'Remote gateway for this network',
54             },
55             {
56             name => 'network',
57             abbr => 'net',
58             descr => 'Network address to add route for',
59             },
60             {
61             name => 'subnet',
62             abbr => 'mask',
63             descr => 'Subnet mask for the given network',
64             },
65             ],
66             },
67             {
68             name => 'remove',
69             abbr => 'delete',
70             exists => 1,
71             descr => 'Delete a route',
72             params => [
73             {
74             name => 'network',
75             abbr => 'net',
76             descr => 'Network address to delete',
77             },
78             {
79             name => 'subnet',
80             abbr => 'mask',
81             descr => 'Subnet mask for the given network',
82             },
83             ],
84             },
85             {
86             name => 'print',
87             exists => 1,
88             descr => 'Display routing table',
89             },
90             ];
91            
92             =head2 Complex example
93              
94             my $p = [
95             # Required global parameter.
96             { name => 'user', leaf => 1, eval => sub { my ( $p ) = @_; return 1 if $p =~ /^[a-z]+$/i; },
97             # Optional global parameter.
98             {
99             name => 'no-cache',
100             abbr => 'nc',
101             exists => 1,
102             optional => 1,
103             descr => 'Don\'t cache your credentials in /tmp/.'
104             },
105             # Start of a branch. If one or more branches exist, at least one must be
106             # followed.
107             {
108             name => 'search',
109             abbr => 's',
110             descr => 'Search for ticket, list tickets in queue, or print contents of a ticket.',
111             params => [
112             {
113             name => 'ticket', # field name
114             abbr => 't', # alternate name
115             re => TICKET_REGEX, # field must match re
116             descr => 'The ticket number to search for.', # auto-doc
117             params => [
118             { # fields that are allowed if this field is set
119             name => 'show-all-worklog-fields',
120             exists => 1, # I just want a 1 or a 0 if set
121             optional => 1,
122             descr => 'Show all worklog fields.'
123             },
124             {
125             name => 'show-all-fields',
126             multi => 1, # can be set multiple times, returns arrayref
127             exists => 1, # unless exists is set too, then you just get the count
128             descr => 'Show all ticket fields.'
129             },
130             ],
131             },
132             ],
133             }
134             ];
135             my ( $operation, $params ) = parse_command_line( $p );
136             if ( !$operation ) { print_usage( $p ); die; }
137             print "Performing $operation!\n"
138              
139             =head1 USAGE
140              
141             Two functions are exported by default: L and
142             L.
143              
144             =head2 Functions
145              
146             =head3 parse_command_line
147              
148             Parses the command line (@ARGV) based on the specified data structure.
149              
150             Accepts two parameters. The first is a required array reference describing the
151             possible command line parameters. It returns three values, the "top level"
152             option, a hashref of the other specified options, and an arrayref of any
153             remaining unparsed options (similar to Getopt::Long).
154              
155             The second parameter is an optional array reference or string from which the
156             parameters are to be read, rather than reading them from @ARGV. If a string is
157             passed, it will be converted to an array via C.
158              
159             If the command line was unable to be parsed (the passed data structure was
160             inconsistent, etc), parse_command_line will die with an appropriate error
161             message. If the command line was invalid (the user entered something that did
162             not meet the given requirements, etc) a warning will be printed and undef will
163             be returned.
164              
165             =head3 print_usage
166              
167             Prints usage information based on the specified data structure.
168              
169             Takes two parameters, the first is a required array reference describing the
170             possible command line parameters, and the second is an optional file handle to
171             which the usage information will be printed. Alternately, in place of a
172             filehandle, a hashref of options can be passed. Valid options are:
173              
174             =over 4
175              
176             =item fh
177              
178             The filehandle to print to. If not set, no output is printed.
179              
180             =item return
181              
182             A boolean value that determines whether or not the usage should be returned as
183             a string.
184              
185             =item wrap_at
186              
187             Number of characters to wrap the output at. Will be auto-detected from
188             $ENV{COLUMNS} if not set, defaults to 80 if auto-detection fails.
189              
190             =item hide_top_line
191              
192             Hides the top line of output which contains the program name how to pass
193             switches.
194              
195             =back
196              
197             Usage information is generated mostly from the "descr" fields in the data
198             structure, indentation is based on parameter dependence, parameters that accept
199             values are noted, and optional parameters are presented inside of brackets.
200              
201             =head2 Configuration
202              
203             The "expected command line configuration data structure" will be referred to as
204             "the data structure" because I can't think of a better name for it.
205              
206             =head3 Concepts
207              
208             The design is similar to the Unix "route" command, in which a "top level"
209             command (such as "add" or "delete") will have zero or more dependent parameters
210             (such as the "gateway" or "subnet"). Getopt::Tree uses Getopt::Long to actually
211             parse the command line, but adds a layer of logic on top to discover which
212             top level command and dependent options the user specified. Conflicting
213             options, parameter types, and usage document generation are all handled by
214             Getopt::Tree based on the data structure supplied by the developer.
215              
216             Commands are separated into two types, top level and dependent. At least on top
217             level command is required. Once Getopt::Tree identifies the proper top level
218             command, it will look for the dependent commands that apply to the specified
219             top level command. Since each dependent command can also have dependent
220             commands, the process is repeated until no more commands are found.
221              
222             Each set of dependents in the tree is considered a "level", with the top level
223             being the first set of entries in the structure, and each successive level
224             being composed of the dependents of the prior level. Note that a level could
225             simply be described as the distance to the top of a tree, where as a "branch"
226             would be the specific set of dependents for a given command, irrespective of
227             dependents of commands on the same level.
228              
229             =head3 Data Structure
230              
231             The data structure is composed of an array of hashrefs. Each hashref describes
232             a single parameter. Each hashref in the array contains various options
233             describing the parameter. Valid options are as follows:
234              
235             =head4 name
236              
237             Full parameter name. Required. Must not contain the characters "@", "|", or "="
238             and must not conflict with other names or abbreviations in the same branch.
239             This is the name that will be returned, if the parameter is set, by
240             L.
241              
242             =head4 abbr
243              
244             Parameter abbreviation. Will be accepted on the command line in place of the
245             proper name, but must obey the same rules as the proper name.
246              
247             =head4 optional
248              
249             Defines whether this parameter is optional. Boolean. Defaults to false, ie, the
250             parameter is required.
251              
252             =head4 exists
253              
254             Defines whether or not the parameter has a value or whether it should simply be
255             checked for existence. Boolean. Defaults to false, ie, the parameter must have
256             a value.
257              
258             =head4 leaf
259              
260             Defines whether or not the parameter should be considered a "leaf" on the
261             current branch or not. A leaf is a required parameter at the current level and
262             has no dependents. Useful to place a required parameter that applies to
263             multiple branches without specifying the required parameter in each branch.
264             Conflicts with "optional" and "params". Defaults to false, ie, this parameter
265             is not a leaf.
266              
267             =head4 params
268              
269             An optional arrayref of hashrefs representing parameters dependent on this
270             parameter. Format is exactly the same as for the primary data structure.
271              
272             =head4 descr
273              
274             Textural description of what the parameter is and does. Used as part of the
275             usage information. If not set, a placeholder is supplied.
276              
277             =head4 multi
278              
279             Defines whether or not this parameter can be specified multiple times or not.
280             Boolean. Defaults to false.
281              
282             =head4 re
283              
284             Defines a regular expression to match values against. The result of the first
285             capture of this expression will be treated as the value in place of the
286             user-specified value. If no capture is found or the match fails, the parameter
287             will be treated as invalid. Conflicts with "exists". If both "re" and "eval"
288             are specified, "re" will be processed first and the result passed to "eval".
289              
290             =head4 eval
291              
292             Defines a subroutine to be called to validate the value passed for this
293             parameter. The returned value from the subroutine will be used in place of the
294             user-specified value. If undef is returned, the parameter is treated as
295             invalid. Conflicts with "exists". If both "re" and "eval" are specified, "re"
296             will be processed first and the result passed to "eval".
297              
298             =head1 VARIABLES
299              
300             =head2 $Getopt::Tree::USAGE_HEADER
301              
302             Text to be printed near the top of the "usage" output.
303              
304             =head2 $Getopt::Tree::USAGE_HEADER
305              
306             Text to be printed at the end of the "usage" output.
307              
308             =head2 $Getopt::Tree::SWITCH_PREFIX_STR
309              
310             Characters to prefix a switch. Defaults to a single hyphen ('-'). Can be set to
311             an empty string to use switchless options (Note: This option is not well
312             tested!).
313              
314             =head1 NOTES
315              
316             You can't have a dependent parameter of the same name as a non-optional
317             parameter higher in the tree. If the parser sees a two instances of the same
318             parameter it will bail, so you have to make sure that there are no identically
319             named parameters in one part of the tree as in another part of the tree that
320             the parser passes through. Example:
321              
322             { name => 'bad' },
323             { name => 'normal', params => [ { name => 'bad' }, { name => 'bad2' } ] }
324             { name => 'normal2', params => [ { name => 'bad2' } ] }
325              
326             Both of the 'bad' entries will collide when the user specifies 'normal', since
327             the parser passes through the top level and the normal->params level. However,
328             bad2 will never collide because the parser will never pass through both levels.
329              
330             Also, identical abbreviations are not checked for or corrected. They will
331             probably cause problems.
332              
333             =cut
334              
335             # Process the name and abbreviations into something Getopt::Long would like.
336             sub process_getopt_params {
337 20     20 0 27 my ( $param_array ) = @_;
338 20         23 my @param_array;
339             my $p_name;
340              
341 20         20 foreach my $param_ref ( @{$param_array} ) {
  20         33  
342 43 50       100 if ( !$param_ref->{name} ) { die "Parameter lacks a name!"; }
  0         0  
343 43 50       107 if ( $param_ref->{name} =~ /[=|@]/ ) { die "Parameter names should not contain [=|@]!"; }
  0         0  
344 43 50       90 if ( $param_ref->{name} =~ /^-/ ) { die "Parameter names should not begin with a dash!"; }
  0         0  
345 43 100       76 if ( $param_ref->{abbr} ) {
346 26 50       54 if ( $param_ref->{abbr} =~ /[-=|]@/ ) { die "Parameter abbreviations should not contain [=|@]!"; }
  0         0  
347 26 50       52 if ( $param_ref->{abbr} =~ /^-/ ) { die "Parameter abbreviations should not begin with a dash!"; }
  0         0  
348 26         64 $p_name = $param_ref->{name} . '|' . $param_ref->{abbr};
349             } else {
350 17         26 $p_name = $param_ref->{name};
351             }
352 43 100       115 if ( $param_ref->{multi} ) {
    100          
353 1         3 $p_name .= '=s@';
354             } elsif ( !$param_ref->{exists} ) {
355 17         19 $p_name .= '=s';
356             }
357 43         65 push @param_array, $p_name;
358 43 100       106 if ( $param_ref->{params} ) { push @param_array, process_getopt_params( $param_ref->{params} ); }
  12         55  
359             }
360 20         87 return @param_array;
361             }
362              
363             # Check to see if a given parameter is valid (handles exists, checks against passed regex,
364             # runs associated code blocks, etc).
365             # Returns ( status, value ). Sorry.
366             sub calc_param_value {
367 8     8 0 14 my ( $top_level, $g_opts ) = @_;
368 8         13 my $v = $g_opts->{ $top_level->{name} };
369              
370             # If all they want is 'exists', quickly check and return.
371 8 100       23 if ( $top_level->{exists} ) {
372 4 50       9 if ( $top_level->{multi} ) {
373 0 0       0 if ( ref $v eq 'ARRAY' ) {
374 0         0 return ( 1, scalar( @{$v} ) );
  0         0  
375             } else {
376 0         0 die "Should be an array?";
377             }
378             }
379 4         12 return ( 1, 1 );
380             }
381              
382 4 100       12 if ( $top_level->{re} ) {
383 3 50       8 if ( $top_level->{multi} ) {
384 0         0 my $result = [];
385 0 0       0 if ( ref $v eq 'ARRAY' ) {
386 0         0 foreach my $entry ( @{$v} ) {
  0         0  
387 0         0 $entry =~ $top_level->{re};
388 0 0       0 if ( !defined $1 ) { return ( 0, undef ); }
  0         0  
389 0         0 push @{$result}, $1;
  0         0  
390             }
391             } else {
392 0         0 die "Should be an array?";
393             }
394 0         0 $v = $result;
395             } else {
396 3         25 $v =~ $top_level->{re};
397 3 50       12 if ( !defined $1 ) { return ( 0, undef ); }
  0         0  
398 3         7 $v = $1;
399             }
400             }
401 4 100       14 if ( $top_level->{eval} ) {
402 1         6 $v = $top_level->{eval}->( $v, $g_opts );
403 1 50       13 if ( !defined $v ) { return ( 0, undef ); }
  0         0  
404             }
405 4         13 return ( 1, $v );
406             }
407              
408             # Recursive function to check the user's input against our data structure.
409             sub check_parameter {
410 14     14 0 22 my ( $g_opts, $params ) = @_;
411              
412 14         16 my @approved_flags;
413             my $this_level;
414 14         17 my $this_level_is_a_leaf = 1;
415             # This is a bit of a pain, but we have to track existence of leaves
416             # separately from regular parameters. Since we don't recurse into a leaf
417             # like we do a branch, we can't let check_parameter() handle the existence
418             # test for us.
419 14         14 my %matched_leaves;
420              
421 14         14 foreach my $top_level ( @{$params} ) {
  14         26  
422 35 50 66     141 if ( $top_level->{params} && $top_level->{leaf} ) {
423 0         0 die "Invalid settings! You can not specify params and leaf!";
424             }
425 35 50 66     91 if ( !$top_level->{optional} && !$top_level->{leaf} ) {
426 13         17 $this_level_is_a_leaf = 0;
427             }
428             # This level has a flag that was passed on the command line
429 35 100       117 if ( defined $g_opts->{ $top_level->{name} } ) {
430             # We only get one non-optional command per branch in the tree
431 8 100       27 if ( $top_level->{optional} ) {
    50          
432 1         5 my ( $status, $v ) = calc_param_value( $top_level, $g_opts );
433 1 50       11 if ( !$status ) { warn "Invalid value for $top_level->{name}!\n"; return; }
  0         0  
  0         0  
434 1         2 $g_opts->{ $top_level->{name} } = $v;
435 1         3 push @approved_flags, $top_level->{name};
436             } elsif ( $top_level->{leaf} ) {
437 0         0 my ( $status, $v ) = calc_param_value( $top_level, $g_opts );
438 0 0       0 if ( !$status ) { warn "Invalid value for $top_level->{name}!\n"; return; }
  0         0  
  0         0  
439 0         0 $g_opts->{ $top_level->{name} } = $v;
440 0         0 push @approved_flags, $top_level->{name};
441 0         0 $matched_leaves{ $top_level->{name} } = 1;
442             } else {
443 7 50       16 if ( $this_level ) {
444             # Already got a required parameter for this level, can't accept two!
445 0         0 warn "Can not specify $this_level and $top_level->{name}\n";
446 0         0 return;
447             }
448 7         21 $this_level = $top_level->{name};
449              
450 7         19 my ( $status, $v ) = calc_param_value( $top_level, $g_opts );
451 7 50       18 if ( !$status ) { warn "Invalid value for $top_level->{name}!\n"; return; }
  0         0  
  0         0  
452 7         14 $g_opts->{ $top_level->{name} } = $v;
453 7         16 push @approved_flags, $top_level->{name};
454             }
455 8 100 66     41 if ( $top_level->{params} && !$top_level->{leaf} ) {
456 6         39 my ( $status, @a ) = check_parameter( $g_opts, $top_level->{params} );
457 6 50       15 if ( !$status ) { return; }
  0         0  
458 6         123 push @approved_flags, @a;
459             }
460             }
461             }
462 14         22 foreach my $l ( grep { $_->{leaf} } @{$params} ) {
  35         144  
  14         24  
463 0 0       0 if ( !$matched_leaves{ $l->{name} } ) {
464 0         0 warn "Missing the following parameter: $l->{name}\n";
465 0         0 return;
466             }
467             }
468              
469             # We didn't match a parameter on this level and this level requires at
470             # least one match!
471 14 50 66     50 if ( ( !$this_level ) && ( !$this_level_is_a_leaf ) ) {
472 0         0 my @missing = map { $_->{name} } @{$params};
  0         0  
  0         0  
473 0         0 warn "Missing one (or more) of the following parameters: " . join( ', ', @missing ) . "\n";
474 0         0 return;
475             }
476              
477 14         49 return 1, @approved_flags;
478             }
479              
480             # Sets up the recursive call to check_parameter. This handles the first
481             # parameter in a special manner. A lot of this is probably unnecessary. Returns
482             # two values, the first is the "operation name" (the name of the first level
483             # parameter we matched on) and the hash of parameter name => value pairs.
484             # This function is exported.
485             sub parse_command_line {
486 4     4 1 4578 my ( $params, $source ) = @_;
487 4         9 my @getopt_params;
488             my %g_opts;
489 0         0 my $status;
490 0         0 my $op_ref;
491 4         7 my $argv_index = 0;
492 4         4 my $op;
493             my $remaining_options;
494              
495 4 50 33     33 if ( !$SWITCH_PREFIX_STR || $SWITCH_PREFIX_STR ne '-' ) {
496 0   0     0 my $t = $SWITCH_PREFIX_STR || '(?:)';
497 0         0 Getopt::Long::Configure( "prefix_pattern=$t" );
498             }
499              
500 4 50       11 if ( !defined $source ) {
    0          
501 4         8 $source = \@ARGV;
502             } elsif ( !ref $source ) {
503 0         0 require Text::ParseWords;
504 0         0 $source = [ Text::ParseWords::shellwords($source) ];
505             }
506              
507             # We can check our ARGV source for the first top level branch (non-optional
508             # and non-leaf) here, and then use that when we process that branch (only)
509             # below.
510 4         8 ARGV_INDEX_LOOP: while ( 1 ) {
511 4         10 $op = $source->[ $argv_index++ ];
512 4 50       9 last if !defined $op;
513              
514             # If we encounter a value without a parameter before we find a top
515             # level op, abort with an error. Any values tied to a parameter should
516             # be skipped in the loop below.
517             # Is this really necessary? Any problems would be caught below
518             # --jeagle 20110411
519             #die "The command '$op' is not valid!\n" unless $op =~ /^-/;
520 4 50       7 if ( $SWITCH_PREFIX_STR ) {
521 4         55 $op =~ s/^\Q$SWITCH_PREFIX_STR\E//;
522             }
523 4         7 foreach my $known_ops ( @{$params} ) {
  4         10  
524 28 50       67 if ( !$known_ops->{name} ) { die 'Invalid name!'; }
  0         0  
525 28 100 100     169 if ( ( $op eq $known_ops->{name} )
      33        
526             || ( ( $known_ops->{abbr} ) && ( $op eq $known_ops->{abbr} ) ) )
527             {
528 4 50 33     25 if ( ( $known_ops->{optional} ) || ( $known_ops->{leaf} ) ) {
529 0 0       0 if ( !$known_ops->{exists} ) {
530 0         0 $argv_index++;
531             }
532 0         0 next ARGV_INDEX_LOOP;
533             }
534 4         8 $op = $known_ops->{name};
535 4         6 $op_ref = $known_ops;
536 4         9 last ARGV_INDEX_LOOP;
537             # if ( !$known_ops->{params} ) { return $op, { $op => 1 }; }
538             }
539             }
540 0 0       0 if ( !$op_ref ) {
541 0         0 warn "The command '$op' is unknown!\n";
542 0         0 return;
543             }
544             }
545              
546 4 50       11 if ( !$op ) { return; }
  0         0  
547              
548             # Gather up all of the global non-branch parameters to pass to GetOptions.
549             # While we're at it, check to make sure the parameters are correct
550 4         6 my @global_options;
551 4         7 foreach my $optional_ops ( @{$params} ) {
  4         9  
552 36 100 66     127 next unless ( $optional_ops->{optional} ) || ( $optional_ops->{leaf} );
553 16 50       31 if ( !$optional_ops->{name} ) { die 'Invalid name!'; }
  0         0  
554 16         21 push @global_options, $optional_ops;
555             }
556              
557 4 50       12 if ( @global_options ) { push @getopt_params, process_getopt_params( \@global_options ); }
  4         15  
558 4         16 push @getopt_params, process_getopt_params( [$op_ref] );
559 4         13 foreach my $p ( @getopt_params ) {
560 43         136 my ( $root ) = $p =~ /^(.+)=?/;
561 43         109 foreach my $k ( keys %g_opts ) {
562 0 0       0 if ( $k =~ /^\Q$root\E/ ) {
563 0 0       0 if ( $k ne $p ) {
564 0         0 die "Duplicate parameter $p (matched $k) with different type specifications!\n";
565             }
566             }
567             }
568             }
569 4         11 undef %g_opts;
570              
571 4         9 eval {
572 4     0   36 local $SIG{__WARN__} = sub { };
  0         0  
573             # GetOptionsFromArray behaves badly unless called fully qualified. Not
574             # interested in tracking down why.
575 4         22 ( my $getopt_success, $remaining_options ) =
576             Getopt::Long::GetOptionsFromArray( $source, \%g_opts, @getopt_params );
577 4 50       3422 return unless $getopt_success;
578             };
579 4         12 undef @getopt_params;
580              
581             # Find the top-level parameter we're going to work with.
582 4         16 ( $status, @getopt_params ) = check_parameter( \%g_opts, [$op_ref] );
583 4 50       13 return unless $status;
584              
585 4 50       9 if ( @global_options ) {
586 4         10 ( $status, @global_options ) = check_parameter( \%g_opts, \@global_options );
587 4 50       9 return unless $status;
588 4         7 push @getopt_params, @global_options;
589             }
590              
591             # By this point, %g_opts contains everything the user passed, and @global_options
592             # is everything that should have been passed.
593              
594 4         5 my %good_values;
595 4         6 my $all_good = 1;
596 4         11 @good_values{@getopt_params} = ();
597 4         16 foreach my $k ( keys( %g_opts ) ) {
598 8 50       27 if ( !exists $good_values{$k} ) {
599 0         0 warn "Invalid parameter: $k\n";
600 0         0 $all_good = 0;
601             }
602             }
603              
604 4 50       11 if ( !$all_good ) {
605 0         0 warn "Not all good!";
606 0         0 return;
607             }
608 4         22 return $op, \%g_opts, $remaining_options;
609             }
610              
611             # Pre-scan to get the width of all of the parameters
612             sub get_usage_param_width {
613 9     9 0 19 my ( $params, $depth, $length ) = @_;
614 9 100       28 if ( !defined $depth ) { $depth = 0; }
  1         3  
615 9   100     27 my $param_length = ( $length || 1 );
616              
617 9         14 foreach my $top_level ( @{$params} ) {
  9         21  
618 23         55 my $this_length = ( length( DEPTH_STR ) * $depth ) + length( $top_level->{name} ) + 1;
619 23 100       68 if ( $top_level->{abbr} ) {
620 15         31 $this_length += length( $top_level->{abbr} ) + ABBR_PARAM_SEPARATOR_LENGTH + 1;
621             }
622 23 100       283 if ( $top_level->{optional} ) {
623 12         18 $this_length += 4; # length of '[ ' . ' ]'
624             }
625 23 100       57 if ( !$top_level->{exists} ) {
626 10         11 $this_length += 5; # length of _<..>
627             }
628              
629 23 100       52 if ( $this_length > $param_length ) {
630 5         10 $param_length = $this_length;
631             }
632 23 100       85 if ( $top_level->{params} ) {
633 8         59 $param_length = get_usage_param_width( $top_level->{params}, $depth + 1, $param_length );
634             }
635             }
636 9         33 return $param_length;
637             }
638              
639             sub print_actual_usage {
640 9     9 0 27 my ( $params, $param_width, $depth ) = @_;
641 9 100       27 if ( !defined $depth ) { $depth = 0; }
  1         3  
642 9         25 my $d = DEPTH_STR x $depth;
643 9         14 my $out = '';
644 9   50     45 my $switch_prefix = $SWITCH_PREFIX_STR || '';
645 9 50       33 return '' unless ref $params eq 'ARRAY';
646              
647             # Print the parameters (recursively) with optional parameters first.
648 9         13 foreach my $top_level (
649             sort {
650 30 100 100     192 if ( ( $a->{optional} || 0 ) == ( $b->{optional} || 0 ) )
  9   100     51  
651             {
652 21         57 return $a->{name} cmp $b->{name};
653             } else {
654 9 100       27 if ( $a->{optional} ) { return -1; }
  3         7  
655 6 50       56 if ( $b->{optional} ) { return 1; }
  6         12  
656 0         0 return 0;
657             }
658             } @{$params} )
659             {
660             # Don't show the leading dash on the first parameter (command).
661             #my $param_desc = ( ( $depth == 0 && !$top_level->{optional} ) ? '' : '-' ) . $top_level->{name};
662 23         62 my $param_desc = $switch_prefix . $top_level->{name};
663 23 100       82 if ( $top_level->{abbr} ) {
664 15         44 $param_desc = $param_desc . ABBR_PARAM_SEPARATOR
665             #. ( ( $depth == 0 && !$top_level->{optional} ) ? '' : '-' )
666             . $switch_prefix . $top_level->{abbr};
667             }
668 23 100       67 if ( !$top_level->{exists} ) {
669 10         18 $param_desc .= ' <..>';
670             }
671 23 100       59 if ( $top_level->{optional} ) {
672 12         28 $param_desc = '[ ' . $param_desc . ' ]';
673             }
674 23         106 $param_desc = sprintf( "%-${param_width}.${param_width}s ", $d . $param_desc );
675              
676 23   50     158 $out .= wrap(
677             $param_desc,
678             ' ' x ( $param_width + 2 ),
679             ( $top_level->{descr} || '(No description provided.)' ) ) . "\n";
680 23 100       6633 if ( $top_level->{params} ) {
681 8         47 $out .= print_actual_usage( $top_level->{params}, $param_width, $depth + 1 );
682             }
683             }
684              
685 9         68 return $out;
686             }
687              
688             # Calculate widths and set off the recursive call to print_actual_usage.
689             # This function is exported.
690             # Woah! Why did this get so complicated? Well, prior to 1.12 we accepted the
691             # second parameter as a filehandle to print to. In 1.12 I realized that was
692             # silly, and it would be better to just return the usage as a string. So now,
693             # for backward-compatability sake, we must support all of the options. Passing
694             # a filehandle causes us to print to that with an appropriate width. No
695             # filehandle will assume STDOUT as the filehandle. Passing a hash causes us to
696             # read various options from that hash.
697             sub print_usage {
698 1     1 1 1510 my ( $params, $fh_or_options ) = @_;
699 1         17 my $param_width = get_usage_param_width( $params );
700 1         3 my $options;
701              
702 1 50       24 if ( !defined $fh_or_options ) {
    50          
703 0         0 $options = { fh => *STDERR, return => 0 };
704             } elsif ( ref $fh_or_options eq 'HASH' ) {
705             # Copy it in case the caller wants to re-use.
706 0         0 $options = \%{ $fh_or_options };
  0         0  
707             } else {
708 1         6 $options = { fh => $fh_or_options, return => 0 };
709             }
710 1 50 33     15 if ( $options->{fh} && !$options->{wrap_at} ) {
711 1 50 33     21 if ( ( -t $options->{fh} ) && ( defined $ENV{COLUMNS} ) ) {
712 0         0 $options->{wrap_at} = $ENV{COLUMNS};
713             }
714             }
715 1 50 33     7 if ( !$options->{wrap_at} || $options->{wrap_at} !~ /^\d{1,4}$/ ) {
716 1         3 $options->{wrap_at} = 80;
717             }
718              
719 1         3 local $Text::Wrap::unexpand = 0;
720 1         5 local $Text::Wrap::columns = $options->{wrap_at};
721 1         3 my $usage_short = '';
722              
723 1         2 foreach my $p ( @{ $params } ) {
  1         5  
724 9 50       26 if ( $p->{leaf} ) {
725 0         0 $usage_short .= "-$p->{name} ";
726             }
727             }
728              
729 1         3 my $usage_str = '';
730              
731 1 50       6 if ( !$options->{hide_top_line} ) {
732 1         139 $usage_str = 'Usage: ' . basename( $0 ) . wrap( '', '', " ${usage_short}\[flags\]\n" ) . "\n";
733             }
734              
735 1 50       425 if ( $USAGE_HEADER ) {
736 1         4 $usage_str .= $USAGE_HEADER;
737             }
738              
739 1         195 $usage_str .= "Options:\n" . print_actual_usage( $params, $param_width ), "\n";
740              
741 1 50       8 if ( $USAGE_FOOTER ) {
742 1         3 $usage_str .= $USAGE_FOOTER;
743             }
744              
745 1 50       15 if ( $options->{fh} ) { print {$options->{fh}} $usage_str; }
  1         3  
  1         39  
746 1 50       15 if ( $options->{return} ) { return $usage_str; }
  0            
747             }
748              
749             =head1 CHANGES
750              
751             =head2 Version 1.12, 20100411, jeagle
752              
753             Add ability to return usage as a string.
754              
755             Add ability to set the prefix character via $Getopt::Tree::SWITCH_PREFIX_STR
756              
757             Remove automatic -help flag.
758              
759             Fix a silly bug causing parameter values that evaluate to false to fail.
760              
761             =head2 Version 1.11, 20100917, jeagle
762              
763             Appease older versions of Perl in print_usage's usage of square brackets in
764             a string.
765              
766             =head2 Version 1.10, 20100709, jeagle
767              
768             Correct handling of eval flags mixed with other flags.
769              
770             Add optional destination filehandle to print_usage.
771              
772             Clean up for export to CPAN.
773              
774             =head2 Version 1.9, 20100428, jeagle
775              
776             Show usage if no parameters are passed.
777              
778             =head2 Version 1.8, 20100427, jeagle
779              
780             Add $Version variable.
781              
782             Give a better error message for parameters passed without a leading '-'.
783              
784             =head2 Version 1.4, 20100427, jeagle
785              
786             Add automatic -help flag parsing. This feature may cause problems if users
787             wanted to override '-help', so this may change in the future.
788              
789             Show required leaf parmeters at the top usage line, reformat usage a little.
790              
791             =cut
792              
793             1;