C-DynaLib

 view release on metacpan or  search on metacpan

lib/C/DynaLib/Struct.pm  view on Meta::CPAN

sub TIESCALAR {
    my ($class, @member) = @_;
    defined (${"${class}::template"})
	or croak "Class \"$class\" has not been defined as a Struct";
    bless [ undef, \@member ], $class;
}

sub AUTOLOAD {
    my $self = shift;
    my $class = ref ($self);
    (my $member = $AUTOLOAD) =~ s/.*:://;
    my $template = ${"${class}::template"};
    defined ($template)
	or croak "Class \"$class\" has not been defined as a Struct";
    my $index = ${"${class}::fieldno"}{$member};
    unless (defined ($index)) {
	carp "Struct \"$class\" has no member \"$member\""
	    unless $member eq 'DESTROY';
	return undef;
    }
    $self->[1] ||= [ unpack ($template, $self->[0]) ];
    if (@_ == 0) {
	return $self->[1]->[$index];
    } elsif (@_ == 1) {
	undef $self->[0];
	return $self->[1]->[$index] = $_[0];
    } else {
	croak "Usage: \$structref->$member( [\$new_value] )";
    }
}

sub FETCH {
    return $_[0]->[0] if defined ($_[0]->[0]);
    return $_[0]->[0] = pack (${ref ($_[0]) . "::template"}, @{$_[0]->[1]});
}

sub STORE {
    undef $_[0]->[1];
    $_[0]->[0] = $_[1];
}

sub Unpack {
    $_[0]->[1] = [ unpack (${ref ($_[0]) . "::template"}, $_[0]->[0]) ]
	if defined ($_[0]->[0]);
    return @{$_[0]->[1]} if wantarray;
}

package C::DynaLib::Struct;

use Carp;

sub Define {
    my ($class, $new_class) = splice(@_, 0, 2);
    if (defined (${"${new_class}::template"})) {
	carp "Redefinition of Struct $new_class";
    }
    *{"${new_class}::TIESCALAR"} = \&C::DynaLib::Struct::Imp::TIESCALAR;
    *{"${new_class}::AUTOLOAD"} = \&C::DynaLib::Struct::Imp::AUTOLOAD;
    @{"${new_class}::ISA"} = qw (C::DynaLib::Struct::Imp);
    my ($template, %fieldno) = ("");
    my ($index, $template_fragment, $fields) = (0);
    while (1) {
	($template_fragment, $fields) = splice(@_, 0, 2);
	last unless defined ($template_fragment);
	ref ($fields) eq 'ARRAY'
	    or die 'Usage: Define C::DynaLib::Struct( $struct_name, $template, \@field_names )';
	$template .= $template_fragment;
	my $i;
	for $i (0 .. $#$fields) {
	    defined (&{"C::DynaLib::Struct::Imp::$fields->[$i]"})
		and croak "Illegal Struct member name: \"$fields->[$i]\"";
	    $fieldno{$fields->[$i]} = $index;
	    ++ $index;
	}
    }
    *{"${new_class}::fieldno"} = \%fieldno;
    *{"${new_class}::template"} = \$template;
}

sub Parse {
  my $definition = shift;
  $definition = shift if $definition eq 'C::DynaLib::Struct';
  my $c;
  if (eval "require Convert::Binary::C;") {
    Convert::Binary::C->import;
    if (ref $definition eq 'Convert::Binary::C') {
      $c = $definition;
      $c->parse(@_);
    } else {
      require C::DynaLib::PerlTypes;
      $c = Convert::Binary::C->new(%$C::DynaLib::PerlTypes::PerlTypes);
      $c->parse($definition, @_);
    }
    # all structs and unions
    for my $s ($c->compound) {
      my $record = $s->{identifier};
      if (defined (${"${record}::template"})) { # already parsed
	carp "Redefinition of ".$s->{type}." $record\n";
      }
      # Convert::Binary::C bug in 0.74
      # fixup wrong declarations: 'char'(type) '*baz'(declarator) => 'char*' 'baz'
      for (0..@{$s->{declarations}}) {
	  my $d = $s->{declarations}->[$_];
	  if ($d and $d->{declarators}[0]->{declarator} 
	      and substr($d->{declarators}[0]->{declarator},0,1) eq '*')
	  {
	      $s->{declarations}->[$_]->{declarators}[0]->{declarator} =
		  substr($d->{declarators}[0]->{declarator},1);
	      $s->{declarations}->[$_]->{type} .= "*";
	  }
      }
      my @members = _members(@{$s->{declarations}});
      Define C::DynaLib::Struct($record,
				_pack_names(@{$s->{declarations}}),
				\@members);
    }
  } else {
    # XXX use GCC::TranslationUnit (does not work yet)
    my $node = C::DynaLib::Parse::GCC_prepare($definition);
    while ($node) {
      if ($node->isa('GCC::Node::function_decl')) {
	declare_func(process_func($node));
      }
      if ($node->isa('GCC::Node::record_type')) {
	declare_struct(process_struct($node));
      }
    } continue {



( run in 1.460 second using v1.01-cache-2.11-cpan-364913b4093 )