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