File Coverage

blib/lib/Getopt/WonderBra.pm
Criterion Covered Total %
statement 81 101 80.2
branch 28 56 50.0
condition n/a
subroutine 13 14 92.8
pod 0 7 0.0
total 122 178 68.5


line stmt bran cond sub pod time code
1             #!/usr/bin/env perl
2              
3             =head1 NAME
4              
5             Getopt::WonderBra - Lift and Separate Command Line Options
6              
7             =head1 SYNOPSIS
8              
9             use Getopt::WonderBra;
10             @ARGV = getopt( 'opts:-:', @ARGV );
11              
12             sub help() { print "Useless help message"; };
13             sub version() { print "Useless version message"; };
14             while ( ( $_ = shift ) ne '--' ) {
15             if (/^-o$/) { $opt_o++ }
16             elsif (/^-p$/) { $opt_p++ }
17             elsif (/^-t$/) { $opt_t++ }
18             elsif (/^-s$/) { push( @opt_s, shift ); }
19             elsif (/^--/) { push( @opt_long, $_ ); }
20             else { die 'I do not grok -', $_; }
21             }
22             print "-o given $opt_o times" if $opt_o;
23             print "-p given $opt_p times" if $opt_p;
24             print "-t given $opt_t times" if $opt_t;
25             print "-s given with arg $_" for @opt_s;
26             print "long opt $_ given" for @opt_long;
27             print "";
28             print " param: $_" for @ARGV;
29              
30             =head1 REQUIRES
31              
32             perl5.008006, Carp, Exporter
33              
34             =head1 EXPORTS
35              
36             getopt($@)
37              
38             =head1 DESCRIPTION
39              
40             See eg/WonderBra.pl for an example of usage.
41              
42             There just weren't enough command line processessing modules, so I had
43             to write my own. Actually, it exists because it made it easy to port
44             shell scripts to perl: it acts just like the getopt program. Oddly,
45             none of the modules that are actually named after it do. (Though some
46             act like the C function) The following sequence chops your args up and
47             gives 'em to you straight:
48              
49             =head1 HELP
50              
51             main::help() must exist prior to calling getopt(). It is wrapped by
52             this module. This is done to ensure correct behavior for programs that
53             use getopt. (e.g. error messages to stdout if --help in specified,
54             so $ foo --help | less has the desired results)
55              
56             main::help() is replaced by a wrapper that will exit the program.
57             If it gets args, it will select STDERR, call your help function, print
58             the passed args, and exit non-zero.
59              
60             Otherwise, it will select STDOUT, call your help function, and exit non-zero.
61              
62             Note that the program will exit if you call help after calling getopt, as
63             well. This is not a bug. It's for issuing error messages while handling
64             the parsed args.
65              
66             The wrapper sub never returns.
67              
68             =head1 VERSION
69              
70             If you define a main::version() sub, it will be called if the
71             user specified --version, and the program will terminate.
72              
73             STDOUT will always be selected.
74              
75             =cut
76              
77             package Getopt::WonderBra;
78 10     10   331230 use strict;
  10         20  
  10         885  
79             our($VERSION)="1.04";
80              
81              
82 10     10   59 use strict;
  10         19  
  10         299  
83 10     10   59 use Carp;
  10         20  
  10         678  
84 10     10   49 use Carp qw(confess);
  10         19  
  10         3503  
85             sub import {
86 10     10   16414 *{main::getopt}=\&getopt;
87             };
88             our (%switches, @arg, @noarg, $res);
89             my $mainhelp;
90             my $mainver;
91             sub version {
92 0 0   0 0 0 select STDERR if ( @_ );
93 0         0 $mainver->();
94 0 0       0 if ( @_ ) {
95 0         0 print "\n ERROR: @_\n";
96             };
97 0         0 exit @_ != 0;
98             };
99             sub help {
100 1 50   1 0 26 select STDERR if ( @_ );
101 1         23 $mainhelp->(@_);
102 1 50       27 if ( @_ ) {
103 1         24 print "\n ERROR: @_\n";
104             };
105 1         260 exit @_ != 0;
106             };
107             sub rep_funcs {
108 8 50   8 0 950 die "missing main::help" unless exists &main::help;
109 8 50       213 die "missing main::version" unless exists &main::version;
110 8 50       837 unless (defined($mainhelp)){
111 8         199 $mainhelp = \&main::help;
112 10     10   59 no warnings 'redefine';
  10         19  
  10         787  
113 8         726 *main::help=\&Getopt::WonderBra::help;
114             };
115 8 50       358 unless (defined($mainver)){
116 8         49 $mainver = \&main::version;
117 10     10   49 no warnings 'redefine';
  10         118  
  10         10177  
118 8         133 *main::version=\&Getopt::WonderBra::version;
119             };
120             };
121             sub parsefmt($){
122 8     8 0 195 local $_ = shift;
123 8         1135 while(length) {
124 7         25 my ($switch,$colons);
125 7         599 ($switch,$colons,$_) = m/^(.)(:?:?)(.*)/;
126 7 50       95 confess "no optional args" if ( $colons eq '::' );
127 7 50       37 confess ": is not a legal switch" if ( $switch eq ':' );
128 7 50       41 confess "$switch repeated" if ( $switches{$switch} );
129 7 50       83 if ( $colons ) {
130 0         0 push(@arg, $switch);
131 0         0 $switches{$switch}='arg';
132             } else {
133 7         81 push(@noarg, $switch);
134 7         156 $switches{$switch}='noarg';
135             };
136             }
137 8 100       88 $switches{'-'} = 'arg' if defined $switches{'-'};
138 8 50       77 if ( defined($ENV{GETOPT_WONDERBRA_DUMP_FMT}) ) {
139 0         0 eval 'use Data::Dumper;';
140 0         0 print STDERR Dumper(\%switches);
141             };
142             }
143              
144             sub singleopt($\@){
145 2     2 0 10 my $text = 'single: "'.join('","',@{$_[$#_]}).'"';
  2         29  
146 2         8 local $_ = shift;
147 2         200 my $arg = shift;
148 2         8 my ($s, @res,$t);
149 2         10 while(length) {
150 2         30 ( $s, $_ ) = m/^(.)(.*)/;
151 2 50       16 if ( !exists $switches{$s} ) {
152 0         0 help("illegal switch: $s (part of $s$_)");
153             }
154 2         8 my $type = $switches{$s};
155 2         8 push(@res,"-$s");
156 2 50       17 if ( $type eq 'noarg' ) {
    0          
157 2         30 next;
158             } elsif ( $type eq 'arg' ) {
159 0 0       0 if ( length ) { push(@res, $_);last; }
  0         0  
  0         0  
160 0 0       0 if ( @$arg ) { push(@res, shift @$arg);last; }
  0         0  
  0         0  
161 0         0 help("switch $s missing required arg");
162             } else {
163 0         0 confess "Internal Error: $type";
164             };
165             }
166 2         32 return ( @res );
167             };
168             sub doubleopt($\@){
169 2 50   2 0 13 return help() if $_[0] eq 'help';
170 2 50       23 return version() if $_[0] eq 'version';
171 2 100       104 help("not accepting long opts, but got --$_[0]")
172             unless defined $switches{'-'};
173 1         13 return "--".$_[0];
174             }
175              
176             sub getopt($\@) {
177 8     8 0 7782952 rep_funcs;
178 8         90 my ($opts,$args) = @_;
179 8 50       149 confess "Internal Error: Missing switch specifiers" unless @_;
180 8         79 parsefmt($opts);
181 8         116 local *_ = $args;
182 8         11461 my @nonopts;
183             my @opts;
184 8         39165 while(@_) {
185 7 50       115 confess "undef amongst the args?" unless defined($_ = shift);
186 7 100       362 if ( !s/^-// ) { push(@nonopts,$_); next; }
  1         10  
  1         12  
187 6 50       40 if ( !length ) { push(@nonopts,'-'); next; }
  0         0  
  0         0  
188 6 100       77 if ( !s/^-// ) { push(@opts,singleopt $_, @_);next; }
  2         19  
  2         11  
189 4 100       22 if ( length ) { push(@opts,doubleopt $_, @_);next; }
  2         18  
  1         13  
190 2         20 last;
191             };
192 7         8921 return @opts, '--', @nonopts, @_;
193             }
194             1;
195