All pastes #781630 Raw Edit

Unnamed

public text v1 · immutable
·published 2007-11-18 23:00 UTC
rendered paste body
# (C) Bryan Steimel 2007 and beyond

package SvD::GetOpt; 


use strict;
use warnings; 

use Carp qw(croak); 
use Exporter qw(import); 

our %EXPORT_TAGS = ( 
  constants => [ grep {/^(?:OPT_|ARG_)/} %::SvD::GetOpt:: ], 
  subs 		=>	[ qw(fsit) ] 
); 
my %exists; 
$EXPORT_TAGS{all} = [ grep {!$exists{$_}++} map {@$_} values %EXPORT_TAGS ]; 
undef %exists; 

our @EXPORT_OK = @{$EXPORT_TAGS{all}};

use constant { 
  true	=> 1, 
  false	=> 0
};

use constant { 
  OPT_OPTIONAL		=> 0x0001,
  OPT_MANDATORY		=> 0x0002,
  ARG_NONE			=> 0x0004,
  ARG_STR			=> 0x0008, 
  ARG_FLOAT			=> 0x0010,
  ARG_BOOL			=> 0x0020,
  ARG_NOTNULL		=> 0x0040,
  ARG_INT			=> 0x0080
   
};

use constant { 
  BITS_SHORTN => 0, 
  BITS_FLAGS  => 1,
  BITS_REGEX  => 2,
  BITS_DEFAULT => 3
}; 

our $REG = { 
  ARG_STR,	 	qr//,
  ARG_INT,	 	qr/^\d+$/, 
  ARG_FLOAT, 	qr/^\d+(?:\.\d+)?$/,  
  ARG_BOOL,     qr/^[01]$/,
  ARG_NOTNULL,	qr/.+/
}; 


our $OPT = {}; 

AUTOLOAD { 
  no strict 'refs';
  our $AUTOLOAD;
  my($sub) = $AUTOLOAD =~ /.*::(.*)/;
  $sub =~ y/A-Z/a-z/;
  exists $OPT->{$sub}
    or croak "Call to undefined subroutine &$AUTOLOAD";
  *$AUTOLOAD = sub { 
    return $_[0]->{ARGV}->{$sub} 
	  unless defined $_[1]; 
	$_[0]->{ARGV}->{$sub} = $_[1]
  };
  &$AUTOLOAD 
  
}



sub fsit { # thats, FORK STUCK IN TOASTER
  my($script) = $0 =~ m#.*[\\/](.*)#i; 
 print "\n"; 
  print '-' . "  " . $script . ': ' . $_ . "\n" 
    for(@_); 
  exit(1); 
} 


sub grab { 
  my $Class = ref $_[0] ? ref shift : shift; 
  my %args = @_; 
  defined($OPT = delete $args{Rules}) 
    && ref $OPT eq 'HASH' 
	  or croak 'Required argument MAP was not supplied'; 
  my $Self = bless { 
    Rules				=> $OPT, 
	Format				=> ((ref $args{Format} eq 'ARRAY' && @{$args{Format}} && delete $args{Format}) 
	                         or croak sprintf "%s->new(FORMAT, must be array reference, and not empty.", __PACKAGE__), 
	ALLOW_SHORT_OPTS	=> (scalar grep {defined $_ && $_ ne ''} map {ref $OPT->{$_}->[0] ? @{$OPT->{$_}->[0]} : $OPT->{$_}->[0]} keys %$OPT) ? true : false,
	ARGV				=> {}
  }, $Class;
  $Self->{DASH_OPT_LEN} = $Self->{ALLOW_SHORT_OPTS} ?  '1,2' : 2;
  $OPT->{$_}->[BITS_FLAGS] & OPT_MANDATORY 
    && defined $OPT->{$_}->[BITS_DEFAULT]
	  && croak 'Arguments marked as *MANDATORY* cannot be assigned a default value'
	    foreach(keys %$OPT); 
  $Self->parse;
  $Self
} 



sub parse($) { 
  my $Self = shift; 
  my($format, $argv) = ($Self->{Format}, {}); 
  argv:while(defined(local $_ = shift @ARGV)) { 
	if(s/\-{$Self->{DASH_OPT_LEN}}//) { 
      y/A-Z/a-z/;
	  my $key = $_;
	  ($key) = (exists $OPT->{$_} ? $_ : grep {grep {defined $_ && $key eq $_} ref $OPT->{$_}->[0] ? @{$OPT->{$_}->[0]} : $OPT->{$_}->[0]} keys %$OPT) 
	    or fsit 'Unknown argument: ' . $& . $_;
      my $parm = shift @ARGV 
        unless SvD::GetOpt::isarg($ARGV[0]) || $OPT->{$key}->[BITS_FLAGS] & ARG_NONE;
      fsit 'Bad data supplied for argument "' . $_ . '"'
	    unless $Self->checkparm($key, $parm);
	  $Self->{ARGV}->{$key} = $parm || $OPT->{$key}->[BITS_DEFAULT];
	  @$format = grep {$key ne $_} @$format
	} else { 
	  scalar @$format 
	    or fsit 'What am I intended to do with "' . $_ . '"?'; 
	  fsit 'Bad data supplied for argument "' .$format->[0] . '"'
        unless $Self->checkparm($format->[0], $_);
      $Self->{ARGV}->{(shift @$format)} = $_ || $OPT->{$_}->[BITS_DEFAULT]  # this should never happen 
	}
  }
  defined $Self->{ARGV}->{$_} or ($Self->{ARGV}->{$_} = $OPT->{$_}->[BITS_DEFAULT] || undef)
    foreach(@$format); # set any [leftover] defaults before checking for null.. 
  (defined $Self->{ARGV}->{$_}
    && $Self->{ARGV}->{$_} ne '') 
	  || ($OPT->{$_}->[BITS_FLAGS] & ARG_NOTNULL 
	      && fsit 'Required argument "' . $_ . '", was not supplied.')
	        for(grep {$OPT->{$_}->[BITS_FLAGS] & OPT_MANDATORY} keys %$OPT); 
  print $_ . ' => ' . (defined $Self->{ARGV}->{$_} ? $Self->{ARGV}->{$_} : '(undefined)') . "\n" foreach(keys %{ $Self->{ARGV} }); 
} 


sub isarg {
   defined $_[1] 
     && ($_[1] =~ /\-{$_[0]->{DASH_OPT_LEN}}/ 
	   ? true
	     : false
     ) || undef;
} 


sub checkparm {  
  my($Self, $bit, $data, $ok) = (@_[0..2], true); 
  exists $Self->{Rules}->{$bit}
    or fsit 'Unknown argument "'  . $bit . '"';
  my $rules = $Self->{Rules}->{$bit};   
  ($rules->[BITS_FLAGS] & $_)
    && ($ok = ($data =~ /$REG->{$_}/) 
	    ? true 
	  : false
	) for(keys %$REG);
  $ok = ($data =~ /$rules->[BITS_REGEX]/)
    if defined $rules->[BITS_REGEX];
  $ok
}


true

__END__