pyldb: avoid segfault when adding an element with no name
[kai/samba-autobuild/.git] / pidl / lib / Parse / Pidl / Typelist.pm
1 ###################################################
2 # Samba4 parser generator for IDL structures
3 # Copyright jelmer@samba.org 2005
4 # released under the GNU GPL
5
6 package Parse::Pidl::Typelist;
7
8 require Exporter;
9 @ISA = qw(Exporter);
10 @EXPORT_OK = qw(hasType getType resolveType mapTypeName scalar_is_reference expandAlias
11         mapScalarType addType typeIs is_signed is_scalar enum_type_fn
12         bitmap_type_fn mapType typeHasBody is_fixed_size_scalar
13 );
14 use vars qw($VERSION);
15 $VERSION = '0.01';
16
17 use Parse::Pidl::Util qw(has_property);
18 use strict;
19
20 my %types = ();
21
22 my @reference_scalars = (
23         "string", "string_array", "nbt_string", "dns_string",
24         "wrepl_nbt_name", "dnsp_name", "dnsp_string",
25         "ipv4address", "ipv6address"
26 );
27
28 my @non_fixed_size_scalars = (
29         "string", "string_array", "nbt_string", "dns_string",
30         "wrepl_nbt_name", "dnsp_name", "dnsp_string"
31 );
32
33 # a list of known scalar types
34 my %scalars = (
35         "void"          => "void",
36         "char"          => "char",
37         "int8"          => "int8_t",
38         "uint8"         => "uint8_t",
39         "int16"         => "int16_t",
40         "uint16"        => "uint16_t",
41         "int1632"       => "int16_t",
42         "uint1632"      => "uint16_t",
43         "int32"         => "int32_t",
44         "uint32"        => "uint32_t",
45         "int3264"       => "int32_t",
46         "uint3264"      => "uint32_t",
47         "hyper"         => "uint64_t",
48         "dlong"         => "int64_t",
49         "udlong"        => "uint64_t",
50         "udlongr"       => "uint64_t",
51         "double"        => "double",
52         "pointer"       => "void*",
53         "DATA_BLOB"     => "DATA_BLOB",
54         "string"        => "const char *",
55         "string_array"  => "const char **",
56         "time_t"        => "time_t",
57         "uid_t"         => "uid_t",
58         "gid_t"         => "gid_t",
59         "NTTIME"        => "NTTIME",
60         "NTTIME_1sec"   => "NTTIME",
61         "NTTIME_hyper"  => "NTTIME",
62         "WERROR"        => "WERROR",
63         "HRESULT"       => "HRESULT",
64         "NTSTATUS"      => "NTSTATUS",
65         "COMRESULT" => "COMRESULT",
66         "dns_string"    => "const char *",
67         "nbt_string"    => "const char *",
68         "wrepl_nbt_name"=> "struct nbt_name *",
69         "ipv4address"   => "const char *",
70         "ipv6address"   => "const char *",
71         "dnsp_name"     => "const char *",
72         "dnsp_string"   => "const char *",
73 );
74
75 my %aliases = (
76         "error_status_t" => "uint32",
77         "boolean8" => "uint8",
78         "boolean32" => "uint32",
79         "DWORD" => "uint32",
80         "uint" => "uint32",
81         "int" => "int32",
82         "WORD" => "uint16",
83         "char" => "uint8",
84         "long" => "int32",
85         "short" => "int16",
86         "HYPER_T" => "hyper",
87         "mode_t"        => "uint32",
88 );
89
90 sub expandAlias($)
91 {
92         my $name = shift;
93
94         return $aliases{$name} if defined($aliases{$name});
95
96         return $name;
97 }
98
99 # map from a IDL type to a C header type
100 sub mapScalarType($)
101 {
102         my $name = shift;
103
104         # it's a bug when a type is not in the list
105         # of known scalars or has no mapping
106         return $scalars{$name} if defined($scalars{$name});
107
108         die("Unknown scalar type $name");
109 }
110
111 sub addType($)
112 {
113         my $t = shift;
114         $types{$t->{NAME}} = $t;
115 }
116
117 sub resolveType($)
118 {
119         my ($ctype) = @_;
120
121         if (not hasType($ctype)) {
122                 # assume struct typedef
123                 return { TYPE => "TYPEDEF", NAME => $ctype, DATA => { TYPE => "STRUCT" } };
124         } else {
125                 return getType($ctype);
126         }
127
128         return $ctype;
129 }
130
131 sub getType($)
132 {
133         my $t = shift;
134         return ($t) if (ref($t) eq "HASH" and not defined($t->{NAME}));
135         return undef if not hasType($t);
136         return $types{$t->{NAME}} if (ref($t) eq "HASH");
137         return $types{$t};
138 }
139
140 sub typeIs($$);
141 sub typeIs($$)
142 {
143         my ($t,$tt) = @_;
144
145         if (ref($t) eq "HASH") {
146                 return 1 if ($t->{TYPE} eq "TYPEDEF" and $t->{DATA}->{TYPE} eq $tt);
147                 return 1 if ($t->{TYPE} eq $tt);
148                 return 0;
149         }
150         if (hasType($t) and getType($t)->{TYPE} eq "TYPEDEF") {
151                 return typeIs(getType($t)->{DATA}, $tt);
152          }
153         return 0;
154 }
155
156 sub hasType($)
157 {
158         my $t = shift;
159         if (ref($t) eq "HASH") {
160                 return 1 if (not defined($t->{NAME}));
161                 return 1 if (defined($types{$t->{NAME}}) and 
162                         $types{$t->{NAME}}->{TYPE} eq $t->{TYPE});
163                 return 0;
164         }
165         return 1 if defined($types{$t});
166         return 0;
167 }
168
169 sub is_signed($)
170 {
171     my $t = shift;
172
173     return ($t eq "int8"
174             or $t eq "int16"
175             or $t eq "int32"
176             or $t eq "dlong"
177             or $t eq "int"
178             or $t eq "long"
179             or $t eq "short");
180 }
181
182 sub is_scalar($)
183 {
184         sub is_scalar($);
185         my $type = shift;
186
187         return 1 if (ref($type) eq "HASH" and 
188                 ($type->{TYPE} eq "SCALAR" or $type->{TYPE} eq "ENUM" or 
189                  $type->{TYPE} eq "BITMAP"));
190
191         if (my $dt = getType($type)) {
192                 return is_scalar($dt->{DATA}) if ($dt->{TYPE} eq "TYPEDEF");
193                 return 1 if ($dt->{TYPE} eq "SCALAR" or $dt->{TYPE} eq "ENUM" or 
194                                  $dt->{TYPE} eq "BITMAP");
195         }
196
197         return 0;
198 }
199
200 sub is_fixed_size_scalar($)
201 {
202         my $name = shift;
203
204         return 0 unless is_scalar($name);
205         return 0 if (grep(/^$name$/, @non_fixed_size_scalars));
206         return 1;
207 }
208
209 sub scalar_is_reference($)
210 {
211         my $name = shift;
212
213         return 1 if (grep(/^$name$/, @reference_scalars));
214         return 0;
215 }
216
217 sub RegisterScalars()
218 {
219         foreach (keys %scalars) {
220                 addType({
221                         NAME => $_,
222                         TYPE => "TYPEDEF",
223                         BASEFILE => "<builtin>",
224                         DATA => {
225                                 TYPE => "SCALAR",
226                                 NAME => $_
227                         }
228                 }
229                 );
230         }
231 }
232
233 sub enum_type_fn($)
234 {
235         my $enum = shift;
236         $enum->{TYPE} eq "ENUM" or die("not an enum");
237
238         # for typedef enum { } we need to check $enum->{PARENT}
239         if (has_property($enum, "enum8bit")) {
240                 return "uint8";
241         } elsif (has_property($enum, "enum16bit")) {
242                 return "uint16";
243         } elsif (has_property($enum, "v1_enum")) {
244                 return "uint32";
245         } elsif (has_property($enum->{PARENT}, "enum8bit")) {
246                 return "uint8";
247         } elsif (has_property($enum->{PARENT}, "enum16bit")) {
248                 return "uint16";
249         } elsif (has_property($enum->{PARENT}, "v1_enum")) {
250                 return "uint32";
251         }
252         return "uint1632";
253 }
254
255 sub bitmap_type_fn($)
256 {
257         my $bitmap = shift;
258
259         $bitmap->{TYPE} eq "BITMAP" or die("not a bitmap");
260
261         if (has_property($bitmap, "bitmap8bit")) {
262                 return "uint8";
263         } elsif (has_property($bitmap, "bitmap16bit")) {
264                 return "uint16";
265         } elsif (has_property($bitmap, "bitmap64bit")) {
266                 return "hyper";
267         }
268         return "uint32";
269 }
270
271 sub typeHasBody($)
272 {
273         sub typeHasBody($);
274         my ($e) = @_;
275
276         if ($e->{TYPE} eq "TYPEDEF") {
277                 return 0 unless(defined($e->{DATA}));
278                 return typeHasBody($e->{DATA});
279         }
280
281         return defined($e->{ELEMENTS});
282 }
283
284 sub mapType($$)
285 {
286         sub mapType($$);
287         my ($t, $n) = @_;
288
289         return mapType($t->{DATA}, $n) if ($t->{TYPE} eq "TYPEDEF");
290         return mapScalarType($n) if ($t->{TYPE} eq "SCALAR");
291         return "enum $n" if ($t->{TYPE} eq "ENUM");
292         return "struct $n" if ($t->{TYPE} eq "STRUCT" or $t->{TYPE} eq "INTERFACE");
293         return "union $n" if ($t->{TYPE} eq "UNION");
294         return mapScalarType(bitmap_type_fn($t)) if ($t->{TYPE} eq "BITMAP");
295         return "struct $n" if ($t->{TYPE} eq "PIPE");
296         die("Unknown type $t->{TYPE}");
297 }
298
299 sub mapTypeName($)
300 {
301         my $t = shift;
302         return "void" unless defined($t);
303         my $dt;
304         $t = expandAlias($t);
305
306         if ($dt = getType($t)) {
307                 return mapType($dt, $dt->{NAME});
308         } elsif (ref($t) eq "HASH" and defined($t->{NAME})) {
309                 return mapType($t, $t->{NAME});
310         } else {
311                 # Best guess
312                 return "struct $t";
313         }
314
315 }
316
317 sub LoadIdl($;$)
318 {
319         my $idl = shift;
320         my $basename = shift;
321
322         foreach my $x (@{$idl}) {
323                 next if $x->{TYPE} ne "INTERFACE";
324
325                 # DCOM interfaces can be types as well
326                 addType({
327                         NAME => $x->{NAME},
328                         TYPE => "TYPEDEF",
329                         DATA => $x,
330                         BASEFILE => $basename,
331                         }) if (has_property($x, "object"));
332
333                 foreach my $y (@{$x->{DATA}}) {
334                         if ($y->{TYPE} eq "TYPEDEF"
335                             or $y->{TYPE} eq "UNION"
336                             or $y->{TYPE} eq "STRUCT"
337                             or $y->{TYPE} eq "ENUM"
338                             or $y->{TYPE} eq "BITMAP"
339                             or $y->{TYPE} eq "PIPE") {
340                                 $y->{BASEFILE} = $basename;
341                                 addType($y);
342                         }
343                 }
344         }
345 }
346
347 sub GenerateTypeLib()
348 {
349         return Parse::Pidl::Util::MyDumper(\%types);
350 }
351
352 RegisterScalars();
353
354 1;