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