File Coverage

blib/lib/P4/Getopt.pm
Criterion Covered Total %
statement 134 170 78.8
branch 65 118 55.0
condition 29 45 64.4
subroutine 20 25 80.0
pod 8 17 47.0
total 256 375 68.2


line stmt bran cond sub pod time code
1             # $Revision: 709 $$Date: 2005-05-03 17:32:07 -0400 (Tue, 03 May 2005) $$Author: wsnyder $
2             # Author: Wilson Snyder
3             ######################################################################
4             #
5             # Copyright 2002-2005 by Wilson Snyder. This program is free software;
6             # you can redistribute it and/or modify it under the terms of either the GNU
7             # General Public License or the Perl Artistic License.
8             #
9             # This program is distributed in the hope that it will be useful,
10             # but WITHOUT ANY WARRANTY; without even the implied warranty of
11             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12             # GNU General Public License for more details.
13             #
14             ######################################################################
15              
16             package P4::Getopt;
17             require 5.006_001;
18              
19 1     1   22398 use strict;
  1         3  
  1         35  
20 1     1   5 use vars qw($AUTOLOAD $Debug %Args);
  1         3  
  1         52  
21 1     1   5 use Carp;
  1         2  
  1         55  
22 1     1   4 use IO::File;
  1         2  
  1         116  
23 1     1   4 use Cwd;
  1         2  
  1         2028  
24              
25             ######################################################################
26             #### Configuration Section
27              
28             our $VERSION = '2.041';
29              
30             #p4 -s -c -d -H -p -P -u -C
31              
32             # List of commands and arguments.
33             # Three forms
34             # [-switch]
35             # [-switch argument]
36             # nonoptional... # Many parameters
37             # nonoptional # One parameter
38             # [optional...] # Many parameters
39             # [optional] # One parameter
40             # The argument "files" is specially detected by c4 for filename parsing.
41              
42             %Args = (
43             'add' =>'[-c changelist] [-t type] file...',
44             'admin' =>'[-z] cmds...',
45             'annotate' =>'[-a] [-c] [-q] filerev...',
46             'branch' =>'[-i] [-o] [-d] [-f] branchspec',
47             'branches' =>'',
48             'change' =>'[-i] [-o] [-d] [-f] [-s] [changelist]',
49             'changes' =>'[-i] [-l] [-c client] [-m maxnum] [-s status] [-u user] [file...]',
50             'client' =>'[-i] [-o] [-d] [-f] [-t template] [client]',
51             'clients' =>'',
52             'counter' =>'[-d] [-f] countername [value]',
53             'counters' =>'',
54             'delete' =>'[-c changelist] file...',
55             'depot' =>'[-i] [-o] [-d] depotname',
56             'depots' =>'',
57             'describe' =>'[-dn] [-dc] [-ds] [-du] [-s] changelist',
58             'diff' =>'[-d*] [-f] [-sa] [-sd] [-se] [-sr] [-t] [filerev...]',
59             'diff2' =>'[-d*] [-q] [-t] [-b branch] [filerev] [filerev2]',
60             'dirs' =>'[-C] [-D] [-H] [-t type] depotdirectory...',
61             'edit' =>'[-c changelist] [-t type] file...',
62             'filelog' =>'[-i] [-l] [-m maxrev] file...',
63             'files' =>'[-a] filerev...',
64             'fix' =>'[-d] [-s status] [-c changelist] jobName...',
65             'fixes' =>'[-i] [-j jobname] [-c changelist] [filerevs...]',
66             'flush' =>'[-f] [-n] [filerevs...]',
67             'fstat' =>'[-c changelist] [-C] [-l] [-H] [-P] [-s] [-W] filerev...',
68             'group' =>'[-i] [-o] [-d] groupname',
69             'groups' =>'[user]',
70             'have' =>'[file...]',
71             'help' =>'[keywords...]',
72             'info', =>'',
73             'integrate' =>'[-i] [-c changelist] [-d] [-f] [-n] [-r] [-t] [-v] [-b branch] [-s fromfile] [filerevs...]',
74             'integrated' =>'file...',
75             'job' =>'[-i] [-o] [-d] [-f] [jobname]',
76             'jobs' =>'[-i] [-e jobview] [-R] [-l] [-r] [-m max] [filerev...]',
77             'jobspec' =>'[-i] [-o]',
78             'label' =>'[-i] [-o] [-f] [-t template] labelname',
79             'labels' =>'filerevs',
80             'labelsync' =>'[-a] [-d] [-n] -l labelname [filerevs...]',
81             'lock' =>'[-c changelist] [file ...]',
82             'logger' =>'[-c sequence] [-t countername]',
83             'monitor' =>'[-a] [-l] cmds...',
84             'obliterate' =>'[-y] [-z] filerevs...',
85             'opened' =>'[-a] [-c changelist] [file...]',
86             'passwd' =>'[-O oldpassword] [-P newpassword] [user]',
87             'print' =>'[-o outfile] [-q] filerev...',
88             'protect' =>'[-o] [-i]',
89             'reopen' =>'[-c changelist] [-t type] file...',
90             'resolve' =>'[-af] [-am] [-as] [-at] [-ay] [-db] [-dw] [-f] [-n] [-t] [-v] [file...]',
91             'resolved' =>'[file...]',
92             'revert' =>'[-c changelist] [-a] [-n] file...',
93             'review' =>'[-c changelist] [-t countername]',
94             'reviews' =>'[-c changelist] [file...]',
95             'set' =>'[-s] [-S svcname] [varvalue]',
96             'triggers' =>'[-i] [-o]',
97             'typemap' =>'[-i] [-o]',
98             'unlock' =>'[-c changelist] [-f] file...',
99             'user' =>'[-d] [-i] [-o] [-f] [username]',
100             'users' =>'[user...]',
101             'verify' =>'[-q] [-u] [-v] file...',
102             'where' =>'[file...]',
103             # Flags added
104             'submit' =>'[-p4] [-i] [-f] [-r] [-c changelist] [-s] [files]', # Added -f, -p4
105             'sync' =>'[-p4] [-f] [-n] [files...]', # Added -p4
106             # C4's own
107             'change-max' =>'[files...]',
108             'client-create' =>'[-i] [-o] [-d] [-f] [-rmdir] [-c4] [-t template] [client]',
109             'client-delete' =>'[-d] [-f] [client]',
110             'help-summary' =>'',
111             'unknown' =>'[-a] [-pi] [files...]',
112             'update' =>'[-n] [-f] [-a] [-pi] [-rl] [files...]',
113             );
114              
115             #######################################################################
116             #######################################################################
117             #######################################################################
118              
119             sub new {
120 1 50   1 1 96 @_ >= 1 or croak 'usage: P4::Getopt->new ({options})';
121 1         4 my $class = shift; # Class (Getopt Element)
122 1   50     4 $class ||= __PACKAGE__;
123 1   33     34 my $defaults = {client=>$ENV{P4CLIENT}, #-c <>
124             pwd=>Cwd::getcwd(), #-d <>
125             host=>$ENV{P4HOST}, #-H <>
126             port=>$ENV{P4PORT}, #-p <>
127             password=>$ENV{P4PASSWD}, #-P <>
128             script=>0, #-s
129             user=>($ENV{P4USER}||$ENV{USER}||$ENV{USERNAME}), #-u <>
130             charset=>$ENV{P4CHARSET}, # -C
131             # Ours
132             noop=>0, #-n
133             fileline=>'Command_Line:0',
134             };
135 1         2 my $self = {%{$defaults},
  1         9  
136             defaults=>$defaults,
137             @_,
138             };
139 1         3 bless $self, $class;
140 1         4 return $self;
141             }
142              
143             #######################################################################
144             # Option parsing
145              
146             sub parameter_file {
147 1     1 0 2 my $self = shift;
148 1         2 my $filename = shift;
149             # Parse: -x files
150              
151 1 50       6 print "*parameter_file $filename\n" if $Debug;
152 1 50       10 my $fh = IO::File->new($filename) or die "%Error: ".$self->fileline().": $! $filename\n";
153 1         96 my $hold_fileline = $self->fileline();
154 1         33 while (my $line = $fh->getline()) {
155 9         277 chomp $line;
156 9         27 $line =~ s/\/\/.*$//;
157 9 100       208 next if $line =~ /^\s*$/;
158 1         26 $self->fileline ("$filename:$.");
159 1         5 my @p = (split /\s+/,"$line ");
160 1         7 $self->parameter (@p);
161             }
162 1         43 $fh->close();
163 1         31 $self->fileline($hold_fileline);
164             }
165              
166             sub parameter {
167 2     2 1 50 my $self = shift;
168             # Parse a parameter. Return list of leftover parameters
169            
170 2         4 my @new_params = ();
171 2         5 foreach my $param (@_) {
172 18 50       60 next if ($param =~ /^\s*$/);
173 18 50       106 print " parameter($param)\n" if $Debug;
174 18 100       46 if ($self->{_parameter_unknown}) {
175 2         4 push @new_params, $param;
176 2         5 next;
177             }
178              
179 16 100 100     255 if ($param eq '-c'
    100 100        
    50 100        
    100 100        
    50 100        
      66        
      100        
180             || $param eq '-d'
181             || $param eq '-H'
182             || $param eq '-p'
183             || $param eq '-P'
184             || $param eq '-u'
185             || $param eq '-C'
186             || $param eq '-x'
187             ) {
188 7         16 $self->{_parameter_next} = $param;
189             }
190             elsif ($param eq '-s') {
191 1         2 $self->{script} = 1;
192             } elsif ($param eq '-n') {
193 0         0 $self->{noop} = 1; # Cvs compatibility
194             }
195             # Second parameters
196             elsif ($self->{_parameter_next}) {
197 7         9 my $pn = $self->{_parameter_next};
198 7         13 $self->{_parameter_next} = undef;
199 7 100       41 if ($pn eq '-x') {
    100          
    100          
    100          
    100          
    100          
    50          
    0          
200 1         4 $self->parameter_file ($param);
201             } elsif ($pn eq '-c') {
202 1         11 $self->client ($param);
203             } elsif ($pn eq '-d') {
204 1         7 $self->pwd ($param);
205             } elsif ($pn eq '-H') {
206 1         8 $self->host ($param);
207             } elsif ($pn eq '-p') {
208 1         8 $self->port ($param);
209             } elsif ($pn eq '-P') {
210 1         7 $self->password ($param);
211             } elsif ($pn eq '-u') {
212 1         17 $self->user ($param);
213             } elsif ($pn eq '-C') {
214 0         0 $self->charset ($param);
215             } else {
216 0         0 die "%Error: ".$self->fileline().": Bad internal next param ".$pn;
217             }
218             }
219             elsif ($param !~ /^-/) { # Unknown. Ignore rest.
220 1         2 push @new_params, $param;
221 1         4 $self->{_parameter_unknown} = 1;
222             }
223             }
224 2         31 return @new_params;
225             }
226              
227             #######################################################################
228             # Accessors
229              
230             sub commands_sorted {
231 0     0 1 0 return (sort (keys %Args));
232             }
233              
234             sub command_arg_text {
235 0     0 1 0 my $self = shift;
236 0         0 my $cmd = shift;
237 0         0 return ($Args{$cmd});
238             }
239              
240             sub _param_changed {
241 8     8   11 my $self = shift;
242 8         12 my $param = shift;
243 8   100     83 return (($self->{$param}||"") ne ($self->{defaults}{$param}||""));
      100        
244             }
245              
246             sub get_parameters {
247 1     1 0 60 my $self = shift;
248 1         3 my @params = ();
249 1 50       4 push @params, ("-c", $self->{client}) if _param_changed($self, 'client');
250 1 50       4 push @params, ("-d", $self->{pwd}) if _param_changed($self, 'pwd');
251 1 50       4 push @params, ("-h", $self->{host}) if _param_changed($self, 'host');
252 1 50       5 push @params, ("-p", $self->{port}) if _param_changed($self, 'port');
253 1 50       6 push @params, ("-P", $self->{password}) if _param_changed($self, 'password');
254 1 50       3 push @params, ("-s") if _param_changed($self, 'script');
255 1 50       3 push @params, ("-u", $self->{user}) if _param_changed($self, 'user');
256 1 50       4 push @params, ("-C", $self->{charset}) if _param_changed($self, 'charset');
257 1         7 return (@params);
258             }
259              
260             #######################################################################
261             # Methods
262              
263             sub setClientOpt {
264 0     0 0 0 my $self = shift;
265 0 0       0 my $client = shift or carp "%Error: usage setClientOpt(P4::Client object),";
266              
267 0 0 0     0 print "SetClient(".$self->client.")\n" if $self->client && $Debug;
268 0 0 0     0 print "SetPort(".$self->port.")\n" if $self->port && $Debug;
269 0 0 0     0 print "SetPassword(".$self->password.")\n" if $self->password && $Debug;
270              
271 0 0       0 $client->SetClient($self->client) if $self->client;
272 0 0       0 $client->SetPort($self->port) if $self->port;
273 0 0       0 $client->SetPassword($self->password) if $self->password;
274             }
275              
276             sub parseCmd {
277 1     1 1 3 my $self = shift;
278 1         1 my $cmd = shift;
279 1         3 my @args = @_;
280              
281             # Returns an array elements for each parameter.
282             # It's what the given argument is
283             # Switch, The name of the switch, or unknown
284 1         4 my $cmdTemplate = $Args{$cmd};
285 1 50       12 print "parseCmd($cmd @args) -> $cmdTemplate\n" if $Debug;
286 1         1 my %parser; # Hash of switch and if it gets a parameter
287 1         3 my $paramNum=0;
288 1         2 my $tempElement = $cmdTemplate;
289 1         5 while ($tempElement) {
290 6         30 $tempElement =~ s/^\s+//;
291 6 100       63 if ($tempElement =~ s/^\[(-\S+)\]//) {
    100          
    50          
    50          
    0          
    0          
292 3         18 $parser{$1} = {what=>'switch', then=>undef, more=>0,};
293             } elsif ($tempElement =~ s/^\[(-\S+)\s+(\S+)\]//) {
294 1         975 $parser{$1} = {what=>'switch', then=>$2, more=>0,};
295             } elsif ($tempElement =~ s/^\[(\S+)\.\.\.\]//) {
296 0         0 $parser{$paramNum} = {what=>$1, then=>undef, more=>1,};
297 0         0 $paramNum++;
298             } elsif ($tempElement =~ s/^\[(\S+)\]//) {
299 2         14 $parser{$paramNum} = {what=>$1, then=>undef, more=>0,};
300 2         9 $paramNum++;
301             } elsif ($tempElement =~ s/^(\S+)\.\.\.//) {
302 0         0 $parser{$paramNum} = {what=>$1, then=>undef, more=>1,};
303 0         0 $paramNum++;
304             } elsif ($tempElement =~ s/^(\S+)//) {
305 0         0 $parser{$paramNum} = {what=>$1, then=>undef, more=>0,};
306 0         0 $paramNum++;
307             } else {
308 0         0 die "Internal %Error: Bad Cmd Template $cmd/$paramNum: $cmdTemplate,";
309             }
310             }
311             #use Data::Dumper; print Dumper(\%parser) if $Debug||1;
312              
313 1         1 my @out;
314             my $inSwitch;
315 1         2 $paramNum = 0;
316 1         4 foreach my $arg (@args) {
317 4         36 my $argone = substr($arg,0,2)."*"; # -dw -> -d* for diff detection
318 4 100 66     35 if ($arg =~ /^-/ && $parser{$arg}) {
    50 33        
319 1         5 push @out, $parser{$arg}{what};
320 1         4 $inSwitch = $parser{$arg}{then};
321             } elsif ($arg =~ /^-/ && $parser{$argone}) {
322 0         0 push @out, $parser{$argone}{what};
323 0         0 $inSwitch = $parser{$argone}{then};
324             } else {
325 3 100       12 if ($inSwitch) { # Argument to a switch
    50          
326 1         2 push @out, $inSwitch;
327 1         3 $inSwitch = 0;
328             } elsif ($parser{$paramNum}) { # Named [optional?] argument
329 2         6 push @out, $parser{$paramNum}{what};
330 2 50       10 $paramNum++ if !$parser{$paramNum}{more};
331             } else {
332 0         0 push @out, "unknown";
333             }
334             }
335             }
336 1         19 return @out;
337             }
338              
339             sub hashCmd {
340 1     1 1 52 my $self = shift;
341 1         2 my $cmd = shift;
342 1         3 my @args = @_;
343              
344 1         2 my %hashed;
345 1         4 my @cmdParsed = $self->parseCmd($cmd, @args);
346             #use Data::Dumper; print Dumper(\@args, \@cmdParsed);
347 1         9 for (my $i=0; $i<=$#cmdParsed; $i++) {
348 4 100       12 if ($cmdParsed[$i] eq 'switch') {
349 1         4 $hashed{$args[$i]} = 1;
350             } else {
351 3 50       9 if (!ref $hashed{$cmdParsed[$i]}) {
352 3         15 $hashed{$cmdParsed[$i]} = [$args[$i]];
353             } else {
354 0         0 push @{$hashed{$cmdParsed[$i]}}, $args[$i];
  0         0  
355             }
356             }
357             }
358 1         13 return %hashed;
359             }
360              
361             sub stripOneArg {
362 0     0 1 0 my $self = shift;
363 0         0 my $switch = shift;
364 0         0 my @args = @_;
365 0         0 my @out;
366 0         0 foreach my $par (@args) {
367 0 0       0 push @out, $par unless $par eq $switch;
368             }
369 0         0 return @out;
370             }
371              
372             #######################################################################
373              
374             sub AUTOLOAD {
375 7     7   10 my $self = $_[0];
376 7         10 my $func = $AUTOLOAD;
377 7         30 $func =~ s/.*:://;
378 7 50       25 if (exists $self->{$func}) {
379 7 50   1 0 607 eval "sub $func { \$_[0]->{'$func'} = \$_[1] if defined \$_[1]; return \$_[0]->{'$func'}; }; 1;" or die;
  1 50   3 1 9  
  1 100   1 0 3  
  3 50   1 0 11  
  3 50   1 0 15  
  1 50   1 0 8  
  1 50   1 0 4  
  1 50       25  
  1         5  
  1         8  
  1         4  
  1         8  
  1         4  
  1         8  
  1         4  
380 7         131 goto &$AUTOLOAD;
381             } else {
382 0         0 croak "Undefined ".__PACKAGE__." subroutine $func called,";
383             }
384             }
385              
386 0     0     sub DESTROY {}
387              
388             ######################################################################
389             ### Package return
390             1;
391             __END__