📄 long.pm
字号:
# Link to global $opt_XXX variable. # Make sure a valid perl identifier results. my $ov = $orig; $ov =~ s/\W/_/g; if ( $opctl{$name}[CTL_DEST] == CTL_DEST_ARRAY ) { print STDERR ("=> link \"$orig\" to \@$pkg","::opt_$ov\n") if $debug; eval ("\$linkage{\$orig} = \\\@".$pkg."::opt_$ov;"); } elsif ( $opctl{$name}[CTL_DEST] == CTL_DEST_HASH ) { print STDERR ("=> link \"$orig\" to \%$pkg","::opt_$ov\n") if $debug; eval ("\$linkage{\$orig} = \\\%".$pkg."::opt_$ov;"); } else { print STDERR ("=> link \"$orig\" to \$$pkg","::opt_$ov\n") if $debug; eval ("\$linkage{\$orig} = \\\$".$pkg."::opt_$ov;"); } } } # Bail out if errors found. die ($error) if $error; $error = 0; # Supply --version and --help support, if needed and allowed. if ( defined($auto_version) ? $auto_version : ($requested_version >= 2.3203) ) { if ( !defined($opctl{version}) ) { $opctl{version} = ['','version',0,CTL_DEST_CODE,undef]; $linkage{version} = \&VersionMessage; } $auto_version = 1; } if ( defined($auto_help) ? $auto_help : ($requested_version >= 2.3203) ) { if ( !defined($opctl{help}) && !defined($opctl{'?'}) ) { $opctl{help} = $opctl{'?'} = ['','help',0,CTL_DEST_CODE,undef]; $linkage{help} = \&HelpMessage; } $auto_help = 1; } # Show the options tables if debugging. if ( $debug ) { my ($arrow, $k, $v); $arrow = "=> "; while ( ($k,$v) = each(%opctl) ) { print STDERR ($arrow, "\$opctl{$k} = $v ", OptCtl($v), "\n"); $arrow = " "; } } # Process argument list my $goon = 1; while ( $goon && @$argv > 0 ) { # Get next argument. $opt = shift (@$argv); print STDERR ("=> arg \"", $opt, "\"\n") if $debug; # Double dash is option list terminator. if ( $opt eq $argend ) { push (@ret, $argend) if $passthrough; last; } # Look it up. my $tryopt = $opt; my $found; # success status my $key; # key (if hash type) my $arg; # option argument my $ctl; # the opctl entry ($found, $opt, $ctl, $arg, $key) = FindOption ($argv, $prefix, $argend, $opt, \%opctl); if ( $found ) { # FindOption undefines $opt in case of errors. next unless defined $opt; my $argcnt = 0; while ( defined $arg ) { # Get the canonical name. print STDERR ("=> cname for \"$opt\" is ") if $debug; $opt = $ctl->[CTL_CNAME]; print STDERR ("\"$ctl->[CTL_CNAME]\"\n") if $debug; if ( defined $linkage{$opt} ) { print STDERR ("=> ref(\$L{$opt}) -> ", ref($linkage{$opt}), "\n") if $debug; if ( ref($linkage{$opt}) eq 'SCALAR' || ref($linkage{$opt}) eq 'REF' ) { if ( $ctl->[CTL_TYPE] eq '+' ) { print STDERR ("=> \$\$L{$opt} += \"$arg\"\n") if $debug; if ( defined ${$linkage{$opt}} ) { ${$linkage{$opt}} += $arg; } else { ${$linkage{$opt}} = $arg; } } elsif ( $ctl->[CTL_DEST] == CTL_DEST_ARRAY ) { print STDERR ("=> ref(\$L{$opt}) auto-vivified", " to ARRAY\n") if $debug; my $t = $linkage{$opt}; $$t = $linkage{$opt} = []; print STDERR ("=> push(\@{\$L{$opt}, \"$arg\")\n") if $debug; push (@{$linkage{$opt}}, $arg); } elsif ( $ctl->[CTL_DEST] == CTL_DEST_HASH ) { print STDERR ("=> ref(\$L{$opt}) auto-vivified", " to HASH\n") if $debug; my $t = $linkage{$opt}; $$t = $linkage{$opt} = {}; print STDERR ("=> \$\$L{$opt}->{$key} = \"$arg\"\n") if $debug; $linkage{$opt}->{$key} = $arg; } else { print STDERR ("=> \$\$L{$opt} = \"$arg\"\n") if $debug; ${$linkage{$opt}} = $arg; } } elsif ( ref($linkage{$opt}) eq 'ARRAY' ) { print STDERR ("=> push(\@{\$L{$opt}, \"$arg\")\n") if $debug; push (@{$linkage{$opt}}, $arg); } elsif ( ref($linkage{$opt}) eq 'HASH' ) { print STDERR ("=> \$\$L{$opt}->{$key} = \"$arg\"\n") if $debug; $linkage{$opt}->{$key} = $arg; } elsif ( ref($linkage{$opt}) eq 'CODE' ) { print STDERR ("=> &L{$opt}(\"$opt\"", $ctl->[CTL_DEST] == CTL_DEST_HASH ? ", \"$key\"" : "", ", \"$arg\")\n") if $debug; my $eval_error = do { local $@; local $SIG{__DIE__} = '__DEFAULT__'; eval { &{$linkage{$opt}} (Getopt::Long::CallBack->new (name => $opt, ctl => $ctl, opctl => \%opctl, linkage => \%linkage, prefix => $prefix, ), $ctl->[CTL_DEST] == CTL_DEST_HASH ? ($key) : (), $arg); }; $@; }; print STDERR ("=> die($eval_error)\n") if $debug && $eval_error ne ''; if ( $eval_error =~ /^!/ ) { if ( $eval_error =~ /^!FINISH\b/ ) { $goon = 0; } } elsif ( $eval_error ne '' ) { warn ($eval_error); $error++; } } else { print STDERR ("Invalid REF type \"", ref($linkage{$opt}), "\" in linkage\n"); die("Getopt::Long -- internal error!\n"); } } # No entry in linkage means entry in userlinkage. elsif ( $ctl->[CTL_DEST] == CTL_DEST_ARRAY ) { if ( defined $userlinkage->{$opt} ) { print STDERR ("=> push(\@{\$L{$opt}}, \"$arg\")\n") if $debug; push (@{$userlinkage->{$opt}}, $arg); } else { print STDERR ("=>\$L{$opt} = [\"$arg\"]\n") if $debug; $userlinkage->{$opt} = [$arg]; } } elsif ( $ctl->[CTL_DEST] == CTL_DEST_HASH ) { if ( defined $userlinkage->{$opt} ) { print STDERR ("=> \$L{$opt}->{$key} = \"$arg\"\n") if $debug; $userlinkage->{$opt}->{$key} = $arg; } else { print STDERR ("=>\$L{$opt} = {$key => \"$arg\"}\n") if $debug; $userlinkage->{$opt} = {$key => $arg}; } } else { if ( $ctl->[CTL_TYPE] eq '+' ) { print STDERR ("=> \$L{$opt} += \"$arg\"\n") if $debug; if ( defined $userlinkage->{$opt} ) { $userlinkage->{$opt} += $arg; } else { $userlinkage->{$opt} = $arg; } } else { print STDERR ("=>\$L{$opt} = \"$arg\"\n") if $debug; $userlinkage->{$opt} = $arg; } } $argcnt++; last if $argcnt >= $ctl->[CTL_AMAX] && $ctl->[CTL_AMAX] != -1; undef($arg); # Need more args? if ( $argcnt < $ctl->[CTL_AMIN] ) { if ( @$argv ) { if ( ValidValue($ctl, $argv->[0], 1, $argend, $prefix) ) { $arg = shift(@$argv); $arg =~ tr/_//d if $ctl->[CTL_TYPE] =~ /^[iIo]$/; ($key,$arg) = $arg =~ /^([^=]+)=(.*)/ if $ctl->[CTL_DEST] == CTL_DEST_HASH; next; } warn("Value \"$$argv[0]\" invalid for option $opt\n"); $error++; } else { warn("Insufficient arguments for option $opt\n"); $error++; } } # Any more args? if ( @$argv && ValidValue($ctl, $argv->[0], 0, $argend, $prefix) ) { $arg = shift(@$argv); $arg =~ tr/_//d if $ctl->[CTL_TYPE] =~ /^[iIo]$/; ($key,$arg) = $arg =~ /^([^=]+)=(.*)/ if $ctl->[CTL_DEST] == CTL_DEST_HASH; next; } } } # Not an option. Save it if we $PERMUTE and don't have a <>. elsif ( $order == $PERMUTE ) { # Try non-options call-back. my $cb; if ( (defined ($cb = $linkage{'<>'})) ) { print STDERR ("=> &L{$tryopt}(\"$tryopt\")\n") if $debug; my $eval_error = do { local $@; local $SIG{__DIE__} = '__DEFAULT__'; eval { &$cb ($tryopt) }; $@; }; print STDERR ("=> die($eval_error)\n") if $debug && $eval_error ne ''; if ( $eval_error =~ /^!/ ) { if ( $eval_error =~ /^!FINISH\b/ ) { $goon = 0; } } elsif ( $eval_error ne '' ) { warn ($eval_error); $error++; } } else { print STDERR ("=> saving \"$tryopt\" ", "(not an option, may permute)\n") if $debug; push (@ret, $tryopt); } next; } # ...otherwise, terminate. else { # Push this one back and exit. unshift (@$argv, $tryopt); return ($error == 0); } } # Finish. if ( @ret && $order == $PERMUTE ) { # Push back accumulated arguments print STDERR ("=> restoring \"", join('" "', @ret), "\"\n") if $debug; unshift (@$argv, @ret); } return ($error == 0);}# A readable representation of what's in an optbl.sub OptCtl ($) { my ($v) = @_; my @v = map { defined($_) ? ($_) : ("<undef>") } @$v; "[". join(",", "\"$v[CTL_TYPE]\"", "\"$v[CTL_CNAME]\"", "\"$v[CTL_DEFAULT]\"", ("\$","\@","\%","\&")[$v[CTL_DEST] || 0], $v[CTL_AMIN] || '', $v[CTL_AMAX] || '',# $v[CTL_RANGE] || '',# $v[CTL_REPEAT] || '', ). "]";}# Parse an option specification and fill the tables.sub ParseOptionSpec ($$) { my ($opt, $opctl) = @_; # Match option spec. if ( $opt !~ m;^ ( # Option name (?: \w+[-\w]* ) # Alias names, or "?" (?: \| (?: \? | \w[-\w]* )? )* )? ( # Either modifiers ... [!+] | # ... or a value/dest/repeat specification [=:] [ionfs] [@%]? (?: \{\d*,?\d*\} )? | # ... or an optional-with-default spec : (?: -?\d+ | \+ ) [@%]? )? $;x ) { return (undef, "Error in option spec: \"$opt\"\n"); } my ($names, $spec) = ($1, $2); $spec = '' unless defined $spec; # $orig keeps track of the primary name the user specified. # This name will be used for the internal or external linkage. # In other words, if the user specifies "FoO|BaR", it will # match any case combinations of 'foo' and 'bar', but if a global # variable needs to be set, it will be $opt_FoO in the exact case # as specified. my $orig; my @names; if ( defined $names ) { @names = split (/\|/, $names); $orig = $names[0]; } else { @names = (''); $orig = ''; } # Construct the opctl entries. my $entry; if ( $spec eq '' || $spec eq '+' || $spec eq '!' ) { # Fields are hard-wired here. $entry = [$spec,$orig,undef,CTL_DEST_SCALAR,0,0]; } elsif ( $spec =~ /^:(-?\d+|\+)([@%])?$/ ) { my $def = $1; my $dest = $2; my $type = $def eq '+' ? 'I' : 'i'; $dest ||= '$'; $dest = $dest eq '@' ? CTL_DEST_ARRAY : $dest eq '%' ? CTL_DEST_HASH : CTL_DEST_SCALAR; # Fields are hard-wired here. $entry = [$type,$orig,$def eq '+' ? undef : $def, $dest,0,1]; } else { my ($mand, $type, $dest) = $spec =~ /^([=:])([ionfs])([@%])?(\{(\d+)?(,)?(\d+)?\})?$/; return (undef, "Cannot repeat while bundling: \"$opt\"\n") if $bundling && defined($4); my ($mi, $cm, $ma) = ($5, $6, $7); return (undef, "{0} is useless in option spec: \"$opt\"\n") if defined($mi) && !$mi && !defined($ma) && !defined($cm); $type = 'i' if $type eq 'n'; $dest ||= '$'; $dest = $dest eq '@' ? CTL_DEST_ARRAY : $dest eq '%' ? CTL_DEST_HASH : CTL_DEST_SCALAR; # Default minargs to 1/0 depending on mand status. $mi = $mand eq '=' ? 1 : 0 unless defined $mi; # Adjust mand status according to minargs. $mand = $mi ? '=' : ':'; # Adjust maxargs. $ma = $mi ? $mi : 1 unless defined $ma || defined $cm; return (undef, "Max must be greater than zero in option spec: \"$opt\"\n") if defined($ma) && !$ma; return (undef, "Max less than min in option spec: \"$opt\"\n") if defined($ma) && $ma < $mi; # Fields are hard-wired here. $entry = [$type,$orig,undef,$dest,$mi,$ma||-1]; } # Process all names. First is canonical, the rest are aliases. my $dups = ''; foreach ( @names ) { $_ = lc ($_) if $ignorecase > (($bundling && length($_) == 1) ? 1 : 0); if ( exists $opctl->{$_} ) { $dups .= "Duplicate specification \"$opt\" for option \"$_\"\n"; } if ( $spec eq '!' ) { $opctl->{"no$_"} = $entry; $opctl->{"no-$_"} = $entry; $opctl->{$_} = [@$entry]; $opctl->{$_}->[CTL_TYPE] = ''; } else { $opctl->{$_} = $entry; } } if ( $dups && $^W ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -