File Coverage

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   1175482 use strict;
  10         19  
  10         389  
79             our($VERSION)="1.05";
80              
81              
82 10     10   31 use strict;
  10         10  
  10         134  
83 10     10   40 use Carp;
  10         9  
  10         474  
84 10     10   30 use Carp qw(confess);
  10         26  
  10         2200  
85             sub import {
86 10     10   11249 *{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 44 select STDERR if ( @_ );
101 1         52 $mainhelp->(@_);
102 1 50       37 if ( @_ ) {
103 1         8 print "\n ERROR: @_\n";
104             };
105 1         712 exit @_ != 0;
106             };
107             sub rep_funcs {
108 8 50   8 0 759 die "missing main::help" unless exists &main::help;
109 8 50       503 die "missing main::version" unless exists &main::version;
110 8 50       379 unless (defined($mainhelp)){
111 8         379 $mainhelp = \&main::help;
112 10     10   40 no warnings 'redefine';
  10         10  
  10         656  
113 8         659 *main::help=\&Getopt::WonderBra::help;
114             };
115 8 50       368 unless (defined($mainver)){
116 8         248 $mainver = \&main::version;
117 10     10   67 no warnings 'redefine';
  10         10  
  10         7236  
118 8         131 *main::version=\&Getopt::WonderBra::version;
119             };
120             };
121             sub parsefmt($){
122 8     8 0 240 local $_ = shift;
123 8         301 while(length) {
124 7         20 my ($switch,$colons);
125 7         511 ($switch,$colons,$_) = m/^(.)(:?:?)(.*)/;
126 7 50       153 confess "no optional args" if ( $colons eq '::' );
127 7 50       125 confess ": is not a legal switch" if ( $switch eq ':' );
128 7 50       150 confess "$switch repeated" if ( $switches{$switch} );
129 7 50       56 if ( $colons ) {
130 0         0 push(@arg, $switch);
131 0         0 $switches{$switch}='arg';
132             } else {
133 7         317 push(@noarg, $switch);
134 7         171 $switches{$switch}='noarg';
135             };
136             }
137 8 100       147 $switches{'-'} = 'arg' if defined $switches{'-'};
138 8 50       149 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 8 my $text = 'single: "'.join('","',@{$_[$#_]}).'"';
  2         16  
146 2         3 local $_ = shift;
147 2         16 my $arg = shift;
148 2         4 my ($s, @res,$t);
149 2         5 while(length) {
150 2         8 ( $s, $_ ) = m/^(.)(.*)/;
151 2 50       25 if ( !exists $switches{$s} ) {
152 0         0 help("illegal switch: $s (part of $s$_)");
153             }
154 2         18 my $type = $switches{$s};
155 2         4 push(@res,"-$s");
156 2 50       28 if ( $type eq 'noarg' ) {
    0          
157 2         29 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         6 return ( @res );
167             };
168             sub doubleopt($\@){
169 2 50   2 0 15 return help() if $_[0] eq 'help';
170 2 50       49 return version() if $_[0] eq 'version';
171             help("not accepting long opts, but got --$_[0]")
172 2 100       48 unless defined $switches{'-'};
173 1         5 return "--".$_[0];
174             }
175              
176             sub getopt($\@) {
177 8     8 0 7650066 rep_funcs;
178 8         378 my ($opts,$args) = @_;
179 8 50       257 confess "Internal Error: Missing switch specifiers" unless @_;
180 8         287 parsefmt($opts);
181 8         245 local *_ = $args;
182 8         28 my @nonopts;
183             my @opts;
184 8         84 while(@_) {
185 7 50       322 confess "undef amongst the args?" unless defined($_ = shift);
186 7 100       288 if ( !s/^-// ) { push(@nonopts,$_); next; }
  1         13  
  1         10  
187 6 50       85 if ( !length ) { push(@nonopts,'-'); next; }
  0         0  
  0         0  
188 6 100       195 if ( !s/^-// ) { push(@opts,singleopt $_, @_);next; }
  2         9  
  2         4  
189 4 100       55 if ( length ) { push(@opts,doubleopt $_, @_);next; }
  2         14  
  1         12  
190 2         21 last;
191             };
192 7         467 return @opts, '--', @nonopts, @_;
193             }
194             1;
195