2002-09-23 22:38:30 +02:00
|
|
|
#
|
|
|
|
# Copyright 2002 Patrik Stridvall
|
|
|
|
#
|
|
|
|
# This library is free software; you can redistribute it and/or
|
|
|
|
# modify it under the terms of the GNU Lesser General Public
|
|
|
|
# License as published by the Free Software Foundation; either
|
|
|
|
# version 2.1 of the License, or (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This library is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
# Lesser General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU Lesser General Public
|
|
|
|
# License along with this library; if not, write to the Free Software
|
2006-05-18 14:49:52 +02:00
|
|
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
2002-09-23 22:38:30 +02:00
|
|
|
#
|
|
|
|
|
|
|
|
package c_type;
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
|
2002-10-09 20:12:02 +02:00
|
|
|
use output qw($output);
|
|
|
|
|
2004-10-26 02:12:21 +02:00
|
|
|
sub _refresh($);
|
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
sub new($)
|
|
|
|
{
|
|
|
|
my ($proto) = @_;
|
2002-09-23 22:38:30 +02:00
|
|
|
my $class = ref($proto) || $proto;
|
|
|
|
my $self = {};
|
2009-07-06 08:08:10 +02:00
|
|
|
bless $self, $class;
|
2002-09-23 22:38:30 +02:00
|
|
|
|
|
|
|
return $self;
|
|
|
|
}
|
|
|
|
|
2002-10-11 19:53:13 +02:00
|
|
|
#
|
2009-07-06 08:08:10 +02:00
|
|
|
# Callback setters
|
2002-11-04 23:40:13 +01:00
|
|
|
#
|
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
sub set_find_align_callback($$)
|
|
|
|
{
|
|
|
|
my ($self, $find_align) = @_;
|
|
|
|
$self->{FIND_ALIGN} = $find_align;
|
2002-11-04 23:40:13 +01:00
|
|
|
}
|
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
sub set_find_kind_callback($$)
|
|
|
|
{
|
|
|
|
my ($self, $find_kind) = @_;
|
|
|
|
$self->{FIND_KIND} = $find_kind;
|
2002-10-11 19:53:13 +02:00
|
|
|
}
|
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
sub set_find_size_callback($$)
|
|
|
|
{
|
|
|
|
my ($self, $find_size) = @_;
|
|
|
|
$self->{FIND_SIZE} = $find_size;
|
|
|
|
}
|
2004-08-20 21:33:17 +02:00
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
sub set_find_count_callback($$)
|
|
|
|
{
|
|
|
|
my ($self, $find_count) = @_;
|
|
|
|
$self->{FIND_COUNT} = $find_count;
|
2004-08-20 21:33:17 +02:00
|
|
|
}
|
|
|
|
|
2009-04-20 15:09:09 +02:00
|
|
|
|
|
|
|
#
|
|
|
|
# Property setter / getter functions (each does both)
|
|
|
|
#
|
|
|
|
|
|
|
|
sub kind($;$)
|
|
|
|
{
|
2009-07-06 08:08:10 +02:00
|
|
|
my ($self, $kind) = @_;
|
|
|
|
if (defined $kind)
|
|
|
|
{
|
|
|
|
$self->{KIND} = $kind;
|
|
|
|
$self->{DIRTY} = 1;
|
2002-11-04 23:40:13 +01:00
|
|
|
}
|
2009-07-06 08:08:10 +02:00
|
|
|
$self->_refresh() if (!defined $self->{KIND});
|
|
|
|
return $self->{KIND};
|
2002-09-23 22:38:30 +02:00
|
|
|
}
|
|
|
|
|
2009-04-20 15:09:09 +02:00
|
|
|
sub _name($;$)
|
|
|
|
{
|
2009-07-06 08:08:10 +02:00
|
|
|
my ($self, $_name) = @_;
|
|
|
|
if (defined $_name)
|
|
|
|
{
|
|
|
|
$self->{_NAME} = $_name;
|
|
|
|
$self->{DIRTY} = 1;
|
|
|
|
}
|
|
|
|
return $self->{_NAME};
|
2002-09-23 22:38:30 +02:00
|
|
|
}
|
|
|
|
|
2009-04-20 15:09:09 +02:00
|
|
|
sub name($;$)
|
|
|
|
{
|
2009-07-06 08:08:10 +02:00
|
|
|
my ($self, $name) = @_;
|
|
|
|
if (defined $name)
|
|
|
|
{
|
|
|
|
$self->{NAME} = $name;
|
|
|
|
$self->{DIRTY} = 1;
|
2002-10-01 20:10:54 +02:00
|
|
|
}
|
2009-07-06 08:08:10 +02:00
|
|
|
return $self->{NAME} if ($self->{NAME});
|
|
|
|
return "$self->{KIND} $self->{_NAME}";
|
2002-09-23 22:38:30 +02:00
|
|
|
}
|
|
|
|
|
2009-04-20 15:09:09 +02:00
|
|
|
sub pack($;$)
|
|
|
|
{
|
2009-07-06 08:08:10 +02:00
|
|
|
my ($self, $pack) = @_;
|
|
|
|
if (defined $pack)
|
|
|
|
{
|
|
|
|
$self->{PACK} = $pack;
|
|
|
|
$self->{DIRTY} = 1;
|
|
|
|
}
|
|
|
|
return $self->{PACK};
|
2002-10-02 21:54:14 +02:00
|
|
|
}
|
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
sub align($)
|
|
|
|
{
|
|
|
|
my ($self) = @_;
|
2002-10-11 19:53:13 +02:00
|
|
|
$self->_refresh();
|
2009-07-06 08:08:10 +02:00
|
|
|
return $self->{ALIGN};
|
2002-10-11 19:53:13 +02:00
|
|
|
}
|
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
sub fields($)
|
|
|
|
{
|
|
|
|
my ($self) = @_;
|
2002-10-09 20:12:02 +02:00
|
|
|
|
|
|
|
my $count = $self->field_count;
|
2002-09-23 22:38:30 +02:00
|
|
|
|
|
|
|
my @fields = ();
|
|
|
|
for (my $n = 0; $n < $count; $n++) {
|
2002-10-09 20:12:02 +02:00
|
|
|
my $field = 'c_type_field'->new($self, $n);
|
|
|
|
push @fields, $field;
|
2002-09-23 22:38:30 +02:00
|
|
|
}
|
|
|
|
return @fields;
|
|
|
|
}
|
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
sub field_base_sizes($)
|
|
|
|
{
|
|
|
|
my ($self) = @_;
|
2002-10-11 19:53:13 +02:00
|
|
|
$self->_refresh();
|
2009-07-06 08:08:10 +02:00
|
|
|
return $self->{FIELD_BASE_SIZES};
|
2002-10-11 19:53:13 +02:00
|
|
|
}
|
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
sub field_aligns($)
|
|
|
|
{
|
|
|
|
my ($self) = @_;
|
2002-10-11 19:53:13 +02:00
|
|
|
$self->_refresh();
|
2009-07-06 08:08:10 +02:00
|
|
|
return $self->{FIELD_ALIGNS};
|
2002-10-09 20:12:02 +02:00
|
|
|
}
|
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
sub field_count($)
|
|
|
|
{
|
|
|
|
my ($self) = @_;
|
|
|
|
return scalar @{$self->{FIELD_TYPE_NAMES}};
|
2002-10-09 20:12:02 +02:00
|
|
|
}
|
|
|
|
|
2009-04-20 15:09:09 +02:00
|
|
|
sub field_names($;$)
|
|
|
|
{
|
2009-07-06 08:08:10 +02:00
|
|
|
my ($self, $field_names) = @_;
|
|
|
|
if (defined $field_names)
|
|
|
|
{
|
|
|
|
$self->{FIELD_NAMES} = $field_names;
|
|
|
|
$self->{DIRTY} = 1;
|
|
|
|
}
|
|
|
|
return $self->{FIELD_NAMES};
|
2002-09-23 22:38:30 +02:00
|
|
|
}
|
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
sub field_offsets($)
|
|
|
|
{
|
|
|
|
my ($self) = @_;
|
2002-10-11 19:53:13 +02:00
|
|
|
$self->_refresh();
|
2009-07-06 08:08:10 +02:00
|
|
|
return $self->{FIELD_OFFSETS};
|
2002-10-09 20:12:02 +02:00
|
|
|
}
|
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
sub field_sizes($)
|
|
|
|
{
|
|
|
|
my ($self) = @_;
|
2002-10-11 19:53:13 +02:00
|
|
|
$self->_refresh();
|
2009-07-06 08:08:10 +02:00
|
|
|
return $self->{FIELD_SIZES};
|
2002-10-09 20:12:02 +02:00
|
|
|
}
|
|
|
|
|
2009-04-20 15:09:09 +02:00
|
|
|
sub field_type_names($;$)
|
|
|
|
{
|
2009-07-06 08:08:10 +02:00
|
|
|
my ($self, $field_type_names) = @_;
|
|
|
|
if (defined $field_type_names)
|
|
|
|
{
|
|
|
|
$self->{FIELD_TYPE_NAMES} = $field_type_names;
|
|
|
|
$self->{DIRTY} = 1;
|
|
|
|
}
|
|
|
|
return $self->{FIELD_TYPE_NAMES};
|
2002-10-09 20:12:02 +02:00
|
|
|
}
|
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
sub size($)
|
|
|
|
{
|
|
|
|
my ($self) = @_;
|
2002-10-11 19:53:13 +02:00
|
|
|
$self->_refresh();
|
2009-07-06 08:08:10 +02:00
|
|
|
return $self->{SIZE};
|
2002-10-09 20:12:02 +02:00
|
|
|
}
|
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
sub _refresh($)
|
|
|
|
{
|
|
|
|
my ($self) = @_;
|
|
|
|
return if (!$self->{DIRTY});
|
2002-10-09 20:12:02 +02:00
|
|
|
|
|
|
|
my $pack = $self->pack;
|
2004-05-04 02:38:27 +02:00
|
|
|
$pack = 8 if !defined($pack);
|
2002-10-09 20:12:02 +02:00
|
|
|
|
2002-10-11 19:53:13 +02:00
|
|
|
my $max_field_align = 0;
|
|
|
|
|
2002-10-09 20:12:02 +02:00
|
|
|
my $offset = 0;
|
2004-08-20 21:33:17 +02:00
|
|
|
my $bitfield_size = 0;
|
|
|
|
my $bitfield_bits = 0;
|
2002-10-09 20:12:02 +02:00
|
|
|
|
|
|
|
my $n = 0;
|
2009-07-06 08:08:10 +02:00
|
|
|
foreach my $field ($self->fields())
|
|
|
|
{
|
2002-10-09 20:12:02 +02:00
|
|
|
my $type_name = $field->type_name;
|
|
|
|
|
2004-08-20 21:33:17 +02:00
|
|
|
my $bits;
|
|
|
|
my $count;
|
|
|
|
if ($type_name =~ s/^(.*?)\s*(?:\[\s*(.*?)\s*\]|:(\d+))?$/$1/)
|
|
|
|
{
|
|
|
|
$count = $2;
|
|
|
|
$bits = $3;
|
2002-10-09 20:12:02 +02:00
|
|
|
}
|
2004-08-20 21:33:17 +02:00
|
|
|
my $declspec_align;
|
|
|
|
if ($type_name =~ s/\s+DECLSPEC_ALIGN\((\d+)\)//)
|
|
|
|
{
|
|
|
|
$declspec_align=$1;
|
|
|
|
}
|
2009-07-06 08:08:10 +02:00
|
|
|
my $base_size = $self->{FIND_SIZE}($type_name);
|
2004-08-20 21:33:17 +02:00
|
|
|
my $type_size=$base_size;
|
|
|
|
if (defined $count)
|
|
|
|
{
|
2009-07-06 08:08:10 +02:00
|
|
|
$count=$self->{FIND_COUNT}($count) if ($count !~ /^\d+$/);
|
2004-08-20 21:33:17 +02:00
|
|
|
if (!defined $count)
|
|
|
|
{
|
|
|
|
$type_size=undef;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-07-06 08:08:10 +02:00
|
|
|
print STDERR "$type_name -> type_size=undef, count=$count\n" if (!defined $type_size);
|
2004-08-20 21:33:17 +02:00
|
|
|
$type_size *= int($count);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ($bitfield_size != 0)
|
|
|
|
{
|
|
|
|
if (($type_name eq "" and defined $bits and $bits == 0) or
|
|
|
|
(defined $type_size and $bitfield_size != $type_size) or
|
|
|
|
!defined $bits or
|
|
|
|
$bitfield_bits + $bits > 8 * $bitfield_size)
|
|
|
|
{
|
|
|
|
# This marks the end of the previous bitfield
|
|
|
|
$bitfield_size=0;
|
|
|
|
$bitfield_bits=0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$bitfield_bits+=$bits;
|
|
|
|
$n++;
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
$self->{ALIGN} = $self->{FIND_ALIGN}($type_name);
|
|
|
|
$self->{ALIGN} = $declspec_align if (defined $declspec_align);
|
2004-08-20 21:33:17 +02:00
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
if (defined $self->{ALIGN})
|
2004-08-20 21:33:17 +02:00
|
|
|
{
|
2009-07-06 08:08:10 +02:00
|
|
|
$self->{ALIGN} = $pack if ($self->{ALIGN} > $pack);
|
|
|
|
$max_field_align = $self->{ALIGN} if ($self->{ALIGN}) > $max_field_align;
|
2004-08-20 21:33:17 +02:00
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
if ($offset % $self->{ALIGN} != 0) {
|
|
|
|
$offset = (int($offset / $self->{ALIGN}) + 1) * $self->{ALIGN};
|
2004-08-20 21:33:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
if ($self->{KIND} !~ /^(?:struct|union)$/)
|
2004-08-20 21:33:17 +02:00
|
|
|
{
|
2009-07-06 08:08:10 +02:00
|
|
|
$self->{KIND} = $self->{FIND_KIND}($type_name) || "";
|
2004-08-20 21:33:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!$type_size)
|
|
|
|
{
|
2009-07-06 08:08:10 +02:00
|
|
|
$self->{ALIGN} = undef;
|
|
|
|
$self->{SIZE} = undef;
|
2004-08-20 21:33:17 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
$self->{FIELD_ALIGNS}->[$n] = $self->{ALIGN};
|
|
|
|
$self->{FIELD_BASE_SIZES}->[$n] = $base_size;
|
|
|
|
$self->{FIELD_OFFSETS}->[$n] = $offset;
|
|
|
|
$self->{FIELD_SIZES}->[$n] = $type_size;
|
2004-08-20 21:33:17 +02:00
|
|
|
$offset += $type_size;
|
|
|
|
|
|
|
|
if ($bits)
|
|
|
|
{
|
|
|
|
$bitfield_size=$type_size;
|
|
|
|
$bitfield_bits=$bits;
|
|
|
|
}
|
2002-10-09 20:12:02 +02:00
|
|
|
$n++;
|
|
|
|
}
|
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
$self->{ALIGN} = $pack;
|
|
|
|
$self->{ALIGN} = $max_field_align if ($max_field_align < $pack);
|
2002-10-11 19:53:13 +02:00
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
$self->{SIZE} = $offset;
|
|
|
|
if ($self->{KIND} =~ /^(?:struct|union)$/) {
|
|
|
|
if ($self->{SIZE} % $self->{ALIGN} != 0) {
|
|
|
|
$self->{SIZE} = (int($self->{SIZE} / $self->{ALIGN}) + 1) * $self->{ALIGN};
|
2002-10-09 20:12:02 +02:00
|
|
|
}
|
|
|
|
}
|
2002-10-11 19:53:13 +02:00
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
$self->{DIRTY} = 0;
|
2002-10-09 20:12:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
package c_type_field;
|
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
sub new($$$)
|
|
|
|
{
|
|
|
|
my ($proto, $type, $number) = @_;
|
2002-10-09 20:12:02 +02:00
|
|
|
my $class = ref($proto) || $proto;
|
2009-07-06 08:08:10 +02:00
|
|
|
my $self = {TYPE=> $type,
|
|
|
|
NUMBER => $number
|
|
|
|
};
|
|
|
|
bless $self, $class;
|
2002-10-09 20:12:02 +02:00
|
|
|
return $self;
|
|
|
|
}
|
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
sub align($)
|
|
|
|
{
|
|
|
|
my ($self) = @_;
|
|
|
|
return $self->{TYPE}->field_aligns()->[$self->{NUMBER}];
|
2002-10-09 20:12:02 +02:00
|
|
|
}
|
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
sub base_size($)
|
|
|
|
{
|
|
|
|
my ($self) = @_;
|
|
|
|
return $self->{TYPE}->field_base_sizes()->[$self->{NUMBER}];
|
2002-10-11 19:53:13 +02:00
|
|
|
}
|
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
sub name($)
|
|
|
|
{
|
|
|
|
my ($self) = @_;
|
|
|
|
return $self->{TYPE}->field_names()->[$self->{NUMBER}];
|
2002-10-09 20:12:02 +02:00
|
|
|
}
|
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
sub offset($)
|
|
|
|
{
|
|
|
|
my ($self) = @_;
|
|
|
|
return $self->{TYPE}->field_offsets()->[$self->{NUMBER}];
|
2002-10-09 20:12:02 +02:00
|
|
|
}
|
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
sub size($)
|
|
|
|
{
|
|
|
|
my ($self) = @_;
|
|
|
|
return $self->{TYPE}->field_sizes()->[$self->{NUMBER}];
|
2002-10-09 20:12:02 +02:00
|
|
|
}
|
|
|
|
|
2009-07-06 08:08:10 +02:00
|
|
|
sub type_name($)
|
|
|
|
{
|
|
|
|
my ($self) = @_;
|
|
|
|
return $self->{TYPE}->field_type_names()->[$self->{NUMBER}];
|
2002-09-23 22:38:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
1;
|