msi: Handle environment strings without a value.
[wine/multimedia.git] / tools / winapi / c_type.pm
blob4e54270625e2bb9a88329d0920bbae813b6b9f77
2 # Copyright 2002 Patrik Stridvall
4 # This library is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU Lesser General Public
6 # License as published by the Free Software Foundation; either
7 # version 2.1 of the License, or (at your option) any later version.
9 # This library is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # Lesser General Public License for more details.
14 # You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 package c_type;
21 use strict;
23 use output qw($output);
25 sub _refresh($);
27 sub new($)
29 my ($proto) = @_;
30 my $class = ref($proto) || $proto;
31 my $self = {};
32 bless $self, $class;
34 return $self;
38 # Callback setters
41 sub set_find_align_callback($$)
43 my ($self, $find_align) = @_;
44 $self->{FIND_ALIGN} = $find_align;
47 sub set_find_kind_callback($$)
49 my ($self, $find_kind) = @_;
50 $self->{FIND_KIND} = $find_kind;
53 sub set_find_size_callback($$)
55 my ($self, $find_size) = @_;
56 $self->{FIND_SIZE} = $find_size;
59 sub set_find_count_callback($$)
61 my ($self, $find_count) = @_;
62 $self->{FIND_COUNT} = $find_count;
67 # Property setter / getter functions (each does both)
70 sub kind($;$)
72 my ($self, $kind) = @_;
73 if (defined $kind)
75 $self->{KIND} = $kind;
76 $self->{DIRTY} = 1;
78 $self->_refresh() if (!defined $self->{KIND});
79 return $self->{KIND};
82 sub _name($;$)
84 my ($self, $_name) = @_;
85 if (defined $_name)
87 $self->{_NAME} = $_name;
88 $self->{DIRTY} = 1;
90 return $self->{_NAME};
93 sub name($;$)
95 my ($self, $name) = @_;
96 if (defined $name)
98 $self->{NAME} = $name;
99 $self->{DIRTY} = 1;
101 return $self->{NAME} if ($self->{NAME});
102 return "$self->{KIND} $self->{_NAME}";
105 sub pack($;$)
107 my ($self, $pack) = @_;
108 if (defined $pack)
110 $self->{PACK} = $pack;
111 $self->{DIRTY} = 1;
113 return $self->{PACK};
116 sub align($)
118 my ($self) = @_;
119 $self->_refresh();
120 return $self->{ALIGN};
123 sub fields($)
125 my ($self) = @_;
127 my $count = $self->field_count;
129 my @fields = ();
130 for (my $n = 0; $n < $count; $n++) {
131 my $field = 'c_type_field'->new($self, $n);
132 push @fields, $field;
134 return @fields;
137 sub field_base_sizes($)
139 my ($self) = @_;
140 $self->_refresh();
141 return $self->{FIELD_BASE_SIZES};
144 sub field_aligns($)
146 my ($self) = @_;
147 $self->_refresh();
148 return $self->{FIELD_ALIGNS};
151 sub field_count($)
153 my ($self) = @_;
154 return scalar @{$self->{FIELD_TYPE_NAMES}};
157 sub field_names($;$)
159 my ($self, $field_names) = @_;
160 if (defined $field_names)
162 $self->{FIELD_NAMES} = $field_names;
163 $self->{DIRTY} = 1;
165 return $self->{FIELD_NAMES};
168 sub field_offsets($)
170 my ($self) = @_;
171 $self->_refresh();
172 return $self->{FIELD_OFFSETS};
175 sub field_sizes($)
177 my ($self) = @_;
178 $self->_refresh();
179 return $self->{FIELD_SIZES};
182 sub field_type_names($;$)
184 my ($self, $field_type_names) = @_;
185 if (defined $field_type_names)
187 $self->{FIELD_TYPE_NAMES} = $field_type_names;
188 $self->{DIRTY} = 1;
190 return $self->{FIELD_TYPE_NAMES};
193 sub size($)
195 my ($self) = @_;
196 $self->_refresh();
197 return $self->{SIZE};
200 sub _refresh($)
202 my ($self) = @_;
203 return if (!$self->{DIRTY});
205 my $pack = $self->pack;
206 $pack = 8 if !defined($pack);
208 my $max_field_align = 0;
210 my $offset = 0;
211 my $bitfield_size = 0;
212 my $bitfield_bits = 0;
214 my $n = 0;
215 foreach my $field ($self->fields())
217 my $type_name = $field->type_name;
219 my $bits;
220 my $count;
221 if ($type_name =~ s/^(.*?)\s*(?:\[\s*(.*?)\s*\]|:(\d+))?$/$1/)
223 $count = $2;
224 $bits = $3;
226 my $declspec_align;
227 if ($type_name =~ s/\s+DECLSPEC_ALIGN\((\d+)\)//)
229 $declspec_align=$1;
231 my $base_size = $self->{FIND_SIZE}($type_name);
232 my $type_size=$base_size;
233 if (defined $count)
235 $count=$self->{FIND_COUNT}($count) if ($count !~ /^\d+$/);
236 if (!defined $count)
238 $type_size=undef;
240 else
242 print STDERR "$type_name -> type_size=undef, count=$count\n" if (!defined $type_size);
243 $type_size *= int($count);
246 if ($bitfield_size != 0)
248 if (($type_name eq "" and defined $bits and $bits == 0) or
249 (defined $type_size and $bitfield_size != $type_size) or
250 !defined $bits or
251 $bitfield_bits + $bits > 8 * $bitfield_size)
253 # This marks the end of the previous bitfield
254 $bitfield_size=0;
255 $bitfield_bits=0;
257 else
259 $bitfield_bits+=$bits;
260 $n++;
261 next;
265 $self->{ALIGN} = $self->{FIND_ALIGN}($type_name);
266 $self->{ALIGN} = $declspec_align if (defined $declspec_align);
268 if (defined $self->{ALIGN})
270 $self->{ALIGN} = $pack if ($self->{ALIGN} > $pack);
271 $max_field_align = $self->{ALIGN} if ($self->{ALIGN}) > $max_field_align;
273 if ($offset % $self->{ALIGN} != 0) {
274 $offset = (int($offset / $self->{ALIGN}) + 1) * $self->{ALIGN};
278 if ($self->{KIND} !~ /^(?:struct|union)$/)
280 $self->{KIND} = $self->{FIND_KIND}($type_name) || "";
283 if (!$type_size)
285 $self->{ALIGN} = undef;
286 $self->{SIZE} = undef;
287 return;
290 $self->{FIELD_ALIGNS}->[$n] = $self->{ALIGN};
291 $self->{FIELD_BASE_SIZES}->[$n] = $base_size;
292 $self->{FIELD_OFFSETS}->[$n] = $offset;
293 $self->{FIELD_SIZES}->[$n] = $type_size;
294 $offset += $type_size;
296 if ($bits)
298 $bitfield_size=$type_size;
299 $bitfield_bits=$bits;
301 $n++;
304 $self->{ALIGN} = $pack;
305 $self->{ALIGN} = $max_field_align if ($max_field_align < $pack);
307 $self->{SIZE} = $offset;
308 if ($self->{KIND} =~ /^(?:struct|union)$/) {
309 if ($self->{SIZE} % $self->{ALIGN} != 0) {
310 $self->{SIZE} = (int($self->{SIZE} / $self->{ALIGN}) + 1) * $self->{ALIGN};
314 $self->{DIRTY} = 0;
317 package c_type_field;
319 sub new($$$)
321 my ($proto, $type, $number) = @_;
322 my $class = ref($proto) || $proto;
323 my $self = {TYPE=> $type,
324 NUMBER => $number
326 bless $self, $class;
327 return $self;
330 sub align($)
332 my ($self) = @_;
333 return $self->{TYPE}->field_aligns()->[$self->{NUMBER}];
336 sub base_size($)
338 my ($self) = @_;
339 return $self->{TYPE}->field_base_sizes()->[$self->{NUMBER}];
342 sub name($)
344 my ($self) = @_;
345 return $self->{TYPE}->field_names()->[$self->{NUMBER}];
348 sub offset($)
350 my ($self) = @_;
351 return $self->{TYPE}->field_offsets()->[$self->{NUMBER}];
354 sub size($)
356 my ($self) = @_;
357 return $self->{TYPE}->field_sizes()->[$self->{NUMBER}];
360 sub type_name($)
362 my ($self) = @_;
363 return $self->{TYPE}->field_type_names()->[$self->{NUMBER}];