| # | |
| # 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 | |
| # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| # | |
| package c_type; | |
| use strict; | |
| use output qw($output); | |
| sub new { | |
| my $proto = shift; | |
| my $class = ref($proto) || $proto; | |
| my $self = {}; | |
| bless ($self, $class); | |
| return $self; | |
| } | |
| ######################################################################## | |
| # set_find_align_callback | |
| # | |
| sub set_find_align_callback { | |
| my $self = shift; | |
| my $find_align = \${$self->{FIND_ALIGN}}; | |
| $$find_align = shift; | |
| } | |
| ######################################################################## | |
| # set_find_kind_callback | |
| # | |
| sub set_find_kind_callback { | |
| my $self = shift; | |
| my $find_kind = \${$self->{FIND_KIND}}; | |
| $$find_kind = shift; | |
| } | |
| ######################################################################## | |
| # set_find_size_callback | |
| # | |
| sub set_find_size_callback { | |
| my $self = shift; | |
| my $find_size = \${$self->{FIND_SIZE}}; | |
| $$find_size = shift; | |
| } | |
| ######################################################################## | |
| # set_find_count_callback | |
| # | |
| sub set_find_count_callback { | |
| my $self = shift; | |
| my $find_count = \${$self->{FIND_COUNT}}; | |
| $$find_count = shift; | |
| } | |
| sub kind { | |
| my $self = shift; | |
| my $kind = \${$self->{KIND}}; | |
| my $dirty = \${$self->{DIRTY}}; | |
| local $_ = shift; | |
| if(defined($_)) { $$kind = $_; $$dirty = 1; } | |
| if (!defined($$kind)) { | |
| $self->_refresh(); | |
| } | |
| return $$kind; | |
| } | |
| sub _name { | |
| my $self = shift; | |
| my $_name = \${$self->{_NAME}}; | |
| my $dirty = \${$self->{DIRTY}}; | |
| local $_ = shift; | |
| if(defined($_)) { $$_name = $_; $$dirty = 1; } | |
| return $$_name; | |
| } | |
| sub name { | |
| my $self = shift; | |
| my $name = \${$self->{NAME}}; | |
| my $dirty = \${$self->{DIRTY}}; | |
| local $_ = shift; | |
| if(defined($_)) { $$name = $_; $$dirty = 1; } | |
| if($$name) { | |
| return $$name; | |
| } else { | |
| my $kind = \${$self->{KIND}}; | |
| my $_name = \${$self->{_NAME}}; | |
| return "$$kind $$_name"; | |
| } | |
| } | |
| sub pack { | |
| my $self = shift; | |
| my $pack = \${$self->{PACK}}; | |
| my $dirty = \${$self->{DIRTY}}; | |
| local $_ = shift; | |
| if(defined($_)) { $$pack = $_; $$dirty = 1; } | |
| return $$pack; | |
| } | |
| sub align { | |
| my $self = shift; | |
| my $align = \${$self->{ALIGN}}; | |
| $self->_refresh(); | |
| return $$align; | |
| } | |
| sub fields { | |
| my $self = shift; | |
| my $count = $self->field_count; | |
| my @fields = (); | |
| for (my $n = 0; $n < $count; $n++) { | |
| my $field = 'c_type_field'->new($self, $n); | |
| push @fields, $field; | |
| } | |
| return @fields; | |
| } | |
| sub field_base_sizes { | |
| my $self = shift; | |
| my $field_base_sizes = \${$self->{FIELD_BASE_SIZES}}; | |
| $self->_refresh(); | |
| return $$field_base_sizes; | |
| } | |
| sub field_aligns { | |
| my $self = shift; | |
| my $field_aligns = \${$self->{FIELD_ALIGNS}}; | |
| $self->_refresh(); | |
| return $$field_aligns; | |
| } | |
| sub field_count { | |
| my $self = shift; | |
| my $field_type_names = \${$self->{FIELD_TYPE_NAMES}}; | |
| my @field_type_names = @{$$field_type_names}; | |
| my $count = scalar(@field_type_names); | |
| return $count; | |
| } | |
| sub field_names { | |
| my $self = shift; | |
| my $field_names = \${$self->{FIELD_NAMES}}; | |
| my $dirty = \${$self->{DIRTY}}; | |
| local $_ = shift; | |
| if(defined($_)) { $$field_names = $_; $$dirty = 1; } | |
| return $$field_names; | |
| } | |
| sub field_offsets { | |
| my $self = shift; | |
| my $field_offsets = \${$self->{FIELD_OFFSETS}}; | |
| $self->_refresh(); | |
| return $$field_offsets; | |
| } | |
| sub field_sizes { | |
| my $self = shift; | |
| my $field_sizes = \${$self->{FIELD_SIZES}}; | |
| $self->_refresh(); | |
| return $$field_sizes; | |
| } | |
| sub field_type_names { | |
| my $self = shift; | |
| my $field_type_names = \${$self->{FIELD_TYPE_NAMES}}; | |
| my $dirty = \${$self->{DIRTY}}; | |
| local $_ = shift; | |
| if(defined($_)) { $$field_type_names = $_; $$dirty = 1; } | |
| return $$field_type_names; | |
| } | |
| sub size { | |
| my $self = shift; | |
| my $size = \${$self->{SIZE}}; | |
| $self->_refresh(); | |
| return $$size; | |
| } | |
| sub _refresh { | |
| my $self = shift; | |
| my $dirty = \${$self->{DIRTY}}; | |
| return if !$$dirty; | |
| my $find_align = \${$self->{FIND_ALIGN}}; | |
| my $find_kind = \${$self->{FIND_KIND}}; | |
| my $find_size = \${$self->{FIND_SIZE}}; | |
| my $find_count = \${$self->{FIND_COUNT}}; | |
| my $align = \${$self->{ALIGN}}; | |
| my $kind = \${$self->{KIND}}; | |
| my $size = \${$self->{SIZE}}; | |
| my $field_aligns = \${$self->{FIELD_ALIGNS}}; | |
| my $field_base_sizes = \${$self->{FIELD_BASE_SIZES}}; | |
| my $field_offsets = \${$self->{FIELD_OFFSETS}}; | |
| my $field_sizes = \${$self->{FIELD_SIZES}}; | |
| my $pack = $self->pack; | |
| $pack = 8 if !defined($pack); | |
| my $max_field_align = 0; | |
| my $offset = 0; | |
| my $bitfield_size = 0; | |
| my $bitfield_bits = 0; | |
| my $n = 0; | |
| foreach my $field ($self->fields) { | |
| my $type_name = $field->type_name; | |
| my $bits; | |
| my $count; | |
| if ($type_name =~ s/^(.*?)\s*(?:\[\s*(.*?)\s*\]|:(\d+))?$/$1/) | |
| { | |
| $count = $2; | |
| $bits = $3; | |
| } | |
| my $declspec_align; | |
| if ($type_name =~ s/\s+DECLSPEC_ALIGN\((\d+)\)//) | |
| { | |
| $declspec_align=$1; | |
| } | |
| my $base_size = &$$find_size($type_name); | |
| my $type_size=$base_size; | |
| if (defined $count) | |
| { | |
| $count=&$$find_count($count) if ($count !~ /^\d+$/); | |
| if (!defined $count) | |
| { | |
| $type_size=undef; | |
| } | |
| else | |
| { | |
| $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; | |
| } | |
| } | |
| $$align = &$$find_align($type_name); | |
| $$align=$declspec_align if (defined $declspec_align); | |
| if (defined $$align) | |
| { | |
| $$align = $pack if $$align > $pack; | |
| $max_field_align = $$align if $$align > $max_field_align; | |
| if ($offset % $$align != 0) { | |
| $offset = (int($offset / $$align) + 1) * $$align; | |
| } | |
| } | |
| if ($$kind !~ /^(?:struct|union)$/) | |
| { | |
| $$kind = &$$find_kind($type_name) || ""; | |
| } | |
| if (!$type_size) | |
| { | |
| $$align = undef; | |
| $$size = undef; | |
| return; | |
| } | |
| $$$field_aligns[$n] = $$align; | |
| $$$field_base_sizes[$n] = $base_size; | |
| $$$field_offsets[$n] = $offset; | |
| $$$field_sizes[$n] = $type_size; | |
| $offset += $type_size; | |
| if ($bits) | |
| { | |
| $bitfield_size=$type_size; | |
| $bitfield_bits=$bits; | |
| } | |
| $n++; | |
| } | |
| $$align = $pack; | |
| $$align = $max_field_align if $max_field_align < $pack; | |
| $$size = $offset; | |
| if ($$kind =~ /^(?:struct|union)$/) { | |
| if ($$size % $$align != 0) { | |
| $$size = (int($$size / $$align) + 1) * $$align; | |
| } | |
| } | |
| $$dirty = 0; | |
| } | |
| package c_type_field; | |
| sub new { | |
| my $proto = shift; | |
| my $class = ref($proto) || $proto; | |
| my $self = {}; | |
| bless ($self, $class); | |
| my $type = \${$self->{TYPE}}; | |
| my $number = \${$self->{NUMBER}}; | |
| $$type = shift; | |
| $$number = shift; | |
| return $self; | |
| } | |
| sub align { | |
| my $self = shift; | |
| my $type = \${$self->{TYPE}}; | |
| my $number = \${$self->{NUMBER}}; | |
| my $field_aligns = $$type->field_aligns; | |
| return $$field_aligns[$$number]; | |
| } | |
| sub base_size { | |
| my $self = shift; | |
| my $type = \${$self->{TYPE}}; | |
| my $number = \${$self->{NUMBER}}; | |
| my $field_base_sizes = $$type->field_base_sizes; | |
| return $$field_base_sizes[$$number]; | |
| } | |
| sub name { | |
| my $self = shift; | |
| my $type = \${$self->{TYPE}}; | |
| my $number = \${$self->{NUMBER}}; | |
| my $field_names = $$type->field_names; | |
| return $$field_names[$$number]; | |
| } | |
| sub offset { | |
| my $self = shift; | |
| my $type = \${$self->{TYPE}}; | |
| my $number = \${$self->{NUMBER}}; | |
| my $field_offsets = $$type->field_offsets; | |
| return $$field_offsets[$$number]; | |
| } | |
| sub size { | |
| my $self = shift; | |
| my $type = \${$self->{TYPE}}; | |
| my $number = \${$self->{NUMBER}}; | |
| my $field_sizes = $$type->field_sizes; | |
| return $$field_sizes[$$number]; | |
| } | |
| sub type_name { | |
| my $self = shift; | |
| my $type = \${$self->{TYPE}}; | |
| my $number = \${$self->{NUMBER}}; | |
| my $field_type_names = $$type->field_type_names; | |
| return $$field_type_names[$$number]; | |
| } | |
| 1; |