Reorganized the code for better support of data structures parsing.
[wine] / tools / winapi / c_type.pm
1 #
2 # Copyright 2002 Patrik Stridvall
3 #
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.
8 #
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.
13 #
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 #
18
19 package c_type;
20
21 use strict;
22
23 use output qw($output);
24
25 sub new {
26     my $proto = shift;
27     my $class = ref($proto) || $proto;
28     my $self  = {};
29     bless ($self, $class);
30
31     return $self;
32 }
33
34 sub kind {
35     my $self = shift;
36     my $kind = \${$self->{KIND}};
37
38     local $_ = shift;
39
40     if(defined($_)) { $$kind = $_; }
41
42     return $$kind;
43 }
44
45 sub _name {
46     my $self = shift;
47     my $_name = \${$self->{_NAME}};
48
49     local $_ = shift;
50
51     if(defined($_)) { $$_name = $_; }
52
53     return $$_name;
54 }
55
56 sub name {
57     my $self = shift;
58     my $name = \${$self->{NAME}};
59
60     local $_ = shift;
61
62     if(defined($_)) { $$name = $_; }
63
64     if($$name) {
65         return $$name;
66     } else {
67         my $kind = \${$self->{KIND}};
68         my $_name = \${$self->{_NAME}};
69
70         return "$$kind $$_name";
71     }
72 }
73
74 sub pack {
75     my $self = shift;
76     my $pack = \${$self->{PACK}};
77     
78     local $_ = shift;
79
80     if(defined($_)) { $$pack = $_; }
81
82     return $$pack;
83 }
84
85 sub fields {
86     my $self = shift;
87
88     my $find_size = shift;
89
90     if (defined($find_size)) {
91         $self->_refresh($find_size);
92     }
93
94     my $count = $self->field_count;
95
96     my @fields = ();
97     for (my $n = 0; $n < $count; $n++) {
98         my $field = 'c_type_field'->new($self, $n);
99         push @fields, $field;
100     }
101     return @fields;
102 }
103
104 sub field_aligns {
105     my $self = shift;
106     my $field_aligns = \${$self->{FIELD_ALIGNS}};
107
108     my $find_size = shift;
109
110     if (defined($find_size)) {
111         $self->_refresh($find_size);
112     }
113
114     return $$field_aligns;
115 }
116
117 sub field_count {
118     my $self = shift;
119     my $field_type_names = \${$self->{FIELD_TYPE_NAMES}};
120
121     my @field_type_names = @{$$field_type_names}; 
122     my $count = scalar(@field_type_names);
123
124     return $count;
125 }
126
127 sub field_names {
128     my $self = shift;
129     my $field_names = \${$self->{FIELD_NAMES}};
130
131     local $_ = shift;
132
133     if(defined($_)) { $$field_names = $_; }
134
135     return $$field_names;
136 }
137
138 sub field_offsets {
139     my $self = shift;
140     my $field_offsets = \${$self->{FIELD_OFFSETS}};
141
142     my $find_size = shift;
143
144     if (defined($find_size)) {
145         $self->_refresh($find_size);
146     }
147
148     return $$field_offsets;
149 }
150
151 sub field_sizes {
152     my $self = shift;
153     my $field_sizes = \${$self->{FIELD_SIZES}};
154
155     my $find_size = shift;
156
157     if (defined($find_size)) {
158         $self->_refresh($find_size);
159     }
160
161     return $$field_sizes;
162 }
163
164 sub field_type_names {
165     my $self = shift;
166     my $field_type_names = \${$self->{FIELD_TYPE_NAMES}};
167
168     local $_ = shift;
169
170     if(defined($_)) { $$field_type_names = $_; }
171
172     return $$field_type_names;
173 }
174
175 sub size {
176     my $self = shift;
177
178     my $size = \${$self->{SIZE}};
179
180     my $find_size = shift;
181     if (defined($find_size)) {
182         $self->_refresh($find_size);
183     }
184
185     return $$size;
186 }
187
188 sub _refresh {
189     my $self = shift;
190
191     my $field_aligns = \${$self->{FIELD_ALIGNS}};
192     my $field_offsets = \${$self->{FIELD_OFFSETS}};
193     my $field_sizes = \${$self->{FIELD_SIZES}};
194     my $size = \${$self->{SIZE}};
195
196     my $find_size = shift;
197
198     my $pack = $self->pack;
199
200     my $offset = 0;
201     my $offset_bits = 0;
202
203     my $n = 0;
204     foreach my $field ($self->fields) {
205         my $type_name = $field->type_name;
206         my $size = &$find_size($type_name);
207
208
209         my $base_type_name = $type_name;
210         if ($base_type_name =~ s/^(.*?)\s*(?:\[\s*(.*?)\s*\]|:(\d+))?$/$1/) {
211             my $count = $2;
212             my $bits = $3;
213         }
214         my $base_size = &$find_size($base_type_name);
215
216         my $align = 0;
217         $align = $base_size % 4 if defined($base_size);
218         $align = 4 if !$align;
219
220         if (!defined($size)) {
221             $$size = undef;
222             return;
223         } elsif ($size >= 0) {
224             if ($offset_bits) {
225                 $offset += $pack * int(($offset_bits + 8 * $pack - 1 ) / (8 * $pack));
226                 $offset_bits = 0;
227             }
228
229             $$$field_aligns[$n] = $align;
230             $$$field_offsets[$n] = $offset;
231             $$$field_sizes[$n] = $size;
232
233             $offset += $size;
234         } else {
235             $$$field_aligns[$n] = $align;
236             $$$field_offsets[$n] = $offset;
237             $$$field_sizes[$n] = $size;
238
239             $offset_bits += -$size;
240         }
241
242         $n++;
243     }
244
245     $$size = $offset;
246     if (1) {
247         if ($$size % $pack != 0) {
248             $$size = (int($$size / $pack) + 1) * $pack;
249         }
250     }
251 }
252
253 package c_type_field;
254
255 sub new {
256     my $proto = shift;
257     my $class = ref($proto) || $proto;
258     my $self  = {};
259     bless ($self, $class);
260
261     my $type = \${$self->{TYPE}};
262     my $number = \${$self->{NUMBER}};
263
264     $$type = shift;
265     $$number = shift;
266
267     return $self;
268 }
269
270 sub align {
271     my $self = shift;
272     my $type = \${$self->{TYPE}};
273     my $number = \${$self->{NUMBER}};
274
275     my $field_aligns = $$type->field_aligns;
276
277     return $$field_aligns[$$number];
278 }
279
280 sub name {
281     my $self = shift;
282     my $type = \${$self->{TYPE}};
283     my $number = \${$self->{NUMBER}};
284
285     my $field_names = $$type->field_names;
286
287     return $$field_names[$$number];
288 }
289
290 sub offset {
291     my $self = shift;
292     my $type = \${$self->{TYPE}};
293     my $number = \${$self->{NUMBER}};
294
295     my $field_offsets = $$type->field_offsets;
296
297     return $$field_offsets[$$number];
298 }
299
300 sub size {
301     my $self = shift;
302     my $type = \${$self->{TYPE}};
303     my $number = \${$self->{NUMBER}};
304
305     my $field_sizes = $$type->field_sizes;
306
307     return $$field_sizes[$$number];
308 }
309
310 sub type_name {
311     my $self = shift;
312     my $type = \${$self->{TYPE}};
313     my $number = \${$self->{NUMBER}};
314
315     my $field_type_names = $$type->field_type_names;
316
317     return $$field_type_names[$$number];
318 }
319
320 1;