r7605: Display properties in header files again.
[bbaumbach/samba-autobuild/.git] / source4 / build / pidl / ndr_header.pm
1 ###################################################
2 # create C header files for an IDL structure
3 # Copyright tridge@samba.org 2000
4 # Copyright jelmer@samba.org 2005
5 # released under the GNU GPL
6
7 package NdrHeader;
8
9 use strict;
10 use pidl::typelist;
11
12 my($res);
13 my($tab_depth);
14
15 sub pidl ($)
16 {
17         $res .= shift;
18 }
19
20 sub tabs()
21 {
22         for (my($i)=0; $i < $tab_depth; $i++) {
23                 pidl "\t";
24         }
25 }
26
27 #####################################################################
28 # parse a properties list
29 sub HeaderProperties($$)
30 {
31     my($props,$ignores) = @_;
32         my $ret = "";
33
34     foreach my $d (keys %{$props}) {
35                 next if (grep(/^$d$/, @$ignores));
36                 if($props->{$d} ne "1") {
37                         $ret.= "$d($props->{$d}),";
38                 } else {
39                         $ret.="$d,";
40                 }
41         }
42
43         if ($ret) {
44                 pidl "/* [" . substr($ret, 0, -1) . "] */";
45         }
46 }
47
48 #####################################################################
49 # parse a structure element
50 sub HeaderElement($)
51 {
52         my($element) = shift;
53
54         pidl tabs();
55         HeaderType($element, $element->{TYPE}, "");
56         pidl " ";
57         my $prefix = "";
58         my $postfix = "";
59         foreach my $l (@{$element->{LEVELS}}) 
60         {
61                 if (($l->{TYPE} eq "POINTER")) {
62                         my $nl = Ndr::GetNextLevel($element, $l);
63                         $nl = Ndr::GetNextLevel($element, $nl) if ($nl->{TYPE} eq "SUBCONTEXT");
64                         next if ($nl->{TYPE} eq "DATA" and typelist::scalar_is_reference($nl->{DATA_TYPE}));
65                         $prefix .= "*";
66                 } elsif ($l->{TYPE} eq "ARRAY") {
67                         my $pl = Ndr::GetPrevLevel($element, $l);
68                         next if ($pl and $pl->{TYPE} eq "POINTER");
69
70                         if ($l->{IS_FIXED}) { 
71                                 $postfix .= "[$l->{SIZE_IS}]"; 
72                         } else {
73                                 $prefix .= "*";
74                         }
75                 } elsif ($l->{TYPE} eq "DATA") {
76                         pidl "$prefix$element->{NAME}$postfix";
77                 }
78         }
79
80         if (defined $element->{ARRAY_LEN}[0] && util::is_constant($element->{ARRAY_LEN}[0])) {
81                 pidl "[$element->{ARRAY_LEN}[0]]";
82         }
83         pidl ";";
84         if (defined $element->{PROPERTIES}) {
85                 HeaderProperties($element->{PROPERTIES}, ["in", "out"]);
86         }
87         pidl "\n";
88 }
89
90 #####################################################################
91 # parse a struct
92 sub HeaderStruct($$)
93 {
94     my($struct,$name) = @_;
95     pidl "\nstruct $name {\n";
96     $tab_depth++;
97     my $el_count=0;
98     if (defined $struct->{ELEMENTS}) {
99                 foreach my $e (@{$struct->{ELEMENTS}}) {
100                     HeaderElement($e);
101                     $el_count++;
102                 }
103     }
104     if ($el_count == 0) {
105             # some compilers can't handle empty structures
106             pidl "\tchar _empty_;\n";
107     }
108     $tab_depth--;
109     pidl "}";
110         if (defined $struct->{PROPERTIES}) {
111                 HeaderProperties($struct->{PROPERTIES}, []);
112         }
113 }
114
115 #####################################################################
116 # parse a enum
117 sub HeaderEnum($$)
118 {
119     my($enum,$name) = @_;
120     my $first = 1;
121
122     if (not util::useUintEnums()) {
123         pidl "\nenum $name {\n";
124         $tab_depth++;
125         foreach my $e (@{$enum->{ELEMENTS}}) {
126             unless ($first) { pidl ",\n"; }
127             $first = 0;
128             tabs();
129             pidl $e;
130         }
131         pidl "\n";
132         $tab_depth--;
133         pidl "}";
134     } else {
135         my $count = 0;
136         pidl "\nenum $name { __donnot_use_enum_$name=0x7FFFFFFF};\n";
137         my $with_val = 0;
138         my $without_val = 0;
139         foreach my $e (@{$enum->{ELEMENTS}}) {
140             my $t = "$e";
141             my $name;
142             my $value;
143             if ($t =~ /(.*)=(.*)/) {
144                 $name = $1;
145                 $value = $2;
146                 $with_val = 1;
147                 die ("you can't mix enum member with values and without values when using --uint-enums!")
148                         unless ($without_val == 0);
149             } else {
150                 $name = $t;
151                 $value = $count++;
152                 $without_val = 1;
153                 die ("you can't mix enum member with values and without values when using --uint-enums!")
154                         unless ($with_val == 0);
155             }
156             pidl "#define $name ( $value )\n";
157         }
158         pidl "\n";
159     }
160 }
161
162 #####################################################################
163 # parse a bitmap
164 sub HeaderBitmap($$)
165 {
166     my($bitmap,$name) = @_;
167
168     pidl "\n/* bitmap $name */\n";
169
170     foreach my $e (@{$bitmap->{ELEMENTS}})
171     {
172             pidl "#define $e\n";
173     }
174
175     pidl "\n";
176 }
177
178 #####################################################################
179 # parse a union
180 sub HeaderUnion($$)
181 {
182         my($union,$name) = @_;
183         my %done = ();
184
185         pidl "\nunion $name {\n";
186         $tab_depth++;
187         foreach my $e (@{$union->{ELEMENTS}}) {
188                 if ($e->{TYPE} ne "EMPTY") {
189                         if (! defined $done{$e->{NAME}}) {
190                                 HeaderElement($e);
191                         }
192                         $done{$e->{NAME}} = 1;
193                 }
194         }
195         $tab_depth--;
196         pidl "}";
197
198         if (defined $union->{PROPERTIES}) {
199                 HeaderProperties($union->{PROPERTIES}, []);
200         }
201 }
202
203 #####################################################################
204 # parse a type
205 sub HeaderType($$$)
206 {
207         my($e,$data,$name) = @_;
208         if (ref($data) eq "HASH") {
209                 ($data->{TYPE} eq "ENUM") && HeaderEnum($data, $name);
210                 ($data->{TYPE} eq "BITMAP") && HeaderBitmap($data, $name);
211                 ($data->{TYPE} eq "STRUCT") && HeaderStruct($data, $name);
212                 ($data->{TYPE} eq "UNION") && HeaderUnion($data, $name);
213                 return;
214         }
215
216         pidl typelist::mapType($e->{TYPE});
217 }
218
219 #####################################################################
220 # parse a typedef
221 sub HeaderTypedef($)
222 {
223     my($typedef) = shift;
224     HeaderType($typedef, $typedef->{DATA}, $typedef->{NAME});
225     pidl ";\n" unless ($typedef->{DATA}->{TYPE} eq "BITMAP");
226 }
227
228 #####################################################################
229 # prototype a typedef
230 sub HeaderTypedefProto($)
231 {
232     my($d) = shift;
233
234         my $tf = NdrParser::get_typefamily($d->{DATA}{TYPE});
235
236     if (util::has_property($d, "gensize")) {
237                 my $size_args = $tf->{SIZE_FN_ARGS}->($d);
238                 pidl "size_t ndr_size_$d->{NAME}($size_args);\n";
239     }
240
241     return unless util::has_property($d, "public");
242
243         my $pull_args = $tf->{PULL_FN_ARGS}->($d);
244         my $push_args = $tf->{PUSH_FN_ARGS}->($d);
245         my $print_args = $tf->{PRINT_FN_ARGS}->($d);
246         unless (util::has_property($d, "nopush")) {
247                 pidl "NTSTATUS ndr_push_$d->{NAME}($push_args);\n";
248         }
249         unless (util::has_property($d, "nopull")) {
250             pidl "NTSTATUS ndr_pull_$d->{NAME}($pull_args);\n";
251         }
252     unless (util::has_property($d, "noprint")) {
253             pidl "void ndr_print_$d->{NAME}($print_args);\n";
254     }
255 }
256
257 #####################################################################
258 # parse a const
259 sub HeaderConst($)
260 {
261     my($const) = shift;
262     if (!defined($const->{ARRAY_LEN}[0])) {
263         pidl "#define $const->{NAME}\t( $const->{VALUE} )\n";
264     } else {
265         pidl "#define $const->{NAME}\t $const->{VALUE}\n";
266     }
267 }
268
269 #####################################################################
270 # parse a function
271 sub HeaderFunctionInOut($$)
272 {
273     my($fn,$prop) = @_;
274
275     foreach my $e (@{$fn->{ELEMENTS}}) {
276             if (util::has_property($e, $prop)) {
277                     HeaderElement($e);
278             }
279     }
280 }
281
282 #####################################################################
283 # determine if we need an "in" or "out" section
284 sub HeaderFunctionInOut_needed($$)
285 {
286     my($fn,$prop) = @_;
287
288     if ($prop eq "out" && $fn->{RETURN_TYPE}) {
289             return 1;
290     }
291
292     foreach my $e (@{$fn->{ELEMENTS}}) {
293             if (util::has_property($e, $prop)) {
294                     return 1;
295             }
296     }
297
298     return undef;
299 }
300
301 my %headerstructs = ();
302
303 #####################################################################
304 # parse a function
305 sub HeaderFunction($)
306 {
307     my($fn) = shift;
308
309     return if ($headerstructs{$fn->{NAME}});
310
311     $headerstructs{$fn->{NAME}} = 1;
312
313     pidl "\nstruct $fn->{NAME} {\n";
314     $tab_depth++;
315     my $needed = 0;
316
317     if (HeaderFunctionInOut_needed($fn, "in")) {
318             tabs();
319             pidl "struct {\n";
320             $tab_depth++;
321             HeaderFunctionInOut($fn, "in");
322             $tab_depth--;
323             tabs();
324             pidl "} in;\n\n";
325             $needed++;
326     }
327
328     if (HeaderFunctionInOut_needed($fn, "out")) {
329             tabs();
330             pidl "struct {\n";
331             $tab_depth++;
332             HeaderFunctionInOut($fn, "out");
333             if ($fn->{RETURN_TYPE}) {
334                     tabs();
335                     pidl typelist::mapType($fn->{RETURN_TYPE}) . " result;\n";
336             }
337             $tab_depth--;
338             tabs();
339             pidl "} out;\n\n";
340             $needed++;
341     }
342
343     if (! $needed) {
344             # sigh - some compilers don't like empty structures
345             tabs();
346             pidl "int _dummy_element;\n";
347     }
348
349     $tab_depth--;
350     pidl "};\n\n";
351 }
352
353 #####################################################################
354 # output prototypes for a IDL function
355 sub HeaderFnProto($$)
356 {
357         my ($interface,$fn) = @_;
358         my $name = $fn->{NAME};
359
360         pidl "void ndr_print_$name(struct ndr_print *ndr, const char *name, int flags, struct $name *r);\n";
361
362         if (defined($fn->{OPNUM})) {
363                 pidl "NTSTATUS dcerpc_$name(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct $name *r);\n";
364                 pidl "struct rpc_request *dcerpc_$name\_send(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, struct $name *r);\n";
365         }
366
367         return unless util::has_property($fn, "public");
368
369         pidl "NTSTATUS ndr_push_$name(struct ndr_push *ndr, int flags, struct $name *r);\n";
370         pidl "NTSTATUS ndr_pull_$name(struct ndr_pull *ndr, int flags, struct $name *r);\n";
371
372         pidl "\n";
373 }
374
375 #####################################################################
376 # parse the interface definitions
377 sub HeaderInterface($)
378 {
379         my($interface) = shift;
380
381         my $count = 0;
382
383         pidl "#ifndef _HEADER_NDR_$interface->{NAME}\n";
384         pidl "#define _HEADER_NDR_$interface->{NAME}\n\n";
385
386         if (defined $interface->{PROPERTIES}->{depends}) {
387                 my @d = split / /, $interface->{PROPERTIES}->{depends};
388                 foreach my $i (@d) {
389                         pidl "#include \"librpc/gen_ndr/ndr_$i\.h\"\n";
390                 }
391         }
392
393         if (defined $interface->{PROPERTIES}->{uuid}) {
394                 my $name = uc $interface->{NAME};
395                 pidl "#define DCERPC_$name\_UUID " . 
396                 util::make_str($interface->{PROPERTIES}->{uuid}) . "\n";
397
398                 if(!defined $interface->{PROPERTIES}->{version}) { $interface->{PROPERTIES}->{version} = "0.0"; }
399                 pidl "#define DCERPC_$name\_VERSION $interface->{PROPERTIES}->{version}\n";
400
401                 pidl "#define DCERPC_$name\_NAME \"$interface->{NAME}\"\n";
402
403                 if(!defined $interface->{PROPERTIES}->{helpstring}) { $interface->{PROPERTIES}->{helpstring} = "NULL"; }
404                 pidl "#define DCERPC_$name\_HELPSTRING $interface->{PROPERTIES}->{helpstring}\n";
405
406                 pidl "\nextern const struct dcerpc_interface_table dcerpc_table_$interface->{NAME};\n";
407                 pidl "NTSTATUS dcerpc_server_$interface->{NAME}_init(void);\n\n";
408         }
409
410         foreach my $d (@{$interface->{FUNCTIONS}}) {
411                 next if not defined($d->{OPNUM});
412                 my $u_name = uc $d->{NAME};
413                 pidl "#define DCERPC_$u_name (";
414         
415                 if (defined($interface->{BASE})) {
416                         pidl "DCERPC_" . uc $interface->{BASE} . "_CALL_COUNT + ";
417                 }
418
419                 if ($d->{OPNUM} != $count) {
420                         die ("Function ".$d->{NAME}." has: wrong opnum [".$d->{OPNUM}."] should be [".$count."]");
421                 }
422
423                 pidl sprintf("0x%02x", $count) . ")\n";
424                 $count++;
425         }
426
427         pidl "\n#define DCERPC_" . uc $interface->{NAME} . "_CALL_COUNT (";
428         
429         if (defined($interface->{BASE})) {
430                 pidl "DCERPC_" . uc $interface->{BASE} . "_CALL_COUNT + ";
431         }
432         
433         pidl "$count)\n\n";
434
435         foreach my $d (@{$interface->{CONSTS}}) {
436                 HeaderConst($d);
437         }
438
439         foreach my $d (@{$interface->{TYPEDEFS}}) {
440                 HeaderTypedef($d);
441                 HeaderTypedefProto($d);
442         }
443
444         foreach my $d (@{$interface->{FUNCTIONS}}) {
445                 HeaderFunction($d);
446                 HeaderFnProto($interface, $d);
447         }
448
449         pidl "#endif /* _HEADER_NDR_$interface->{NAME} */\n";
450 }
451
452 #####################################################################
453 # parse a parsed IDL into a C header
454 sub Parse($)
455 {
456     my($idl) = shift;
457     $tab_depth = 0;
458
459         $res = "";
460     pidl "/* header auto-generated by pidl */\n\n";
461     foreach my $x (@{$idl}) {
462             ($x->{TYPE} eq "INTERFACE") && HeaderInterface($x);
463     }
464     return $res;
465 }
466
467 1;