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