r10006: Insert correct header file.
[kai/samba.git] / source4 / pidl / pidl
1 #!/usr/bin/perl -w
2
3 ###################################################
4 # package to parse IDL files and generate code for
5 # rpc functions in Samba
6 # Copyright tridge@samba.org 2000-2003
7 # Copyright jelmer@samba.org 2005
8 # released under the GNU GPL
9
10 use strict;
11 use FindBin qw($RealBin);
12 use lib "$RealBin";
13 use lib "$RealBin/lib";
14 use Getopt::Long;
15 use File::Basename;
16 use Parse::Pidl;
17 use Parse::Pidl::Util;
18
19 #####################################################################
20 # save a data structure into a file
21 sub SaveStructure($$)
22 {
23         my($filename,$v) = @_;
24         FileSave($filename, Parse::Pidl::Util::MyDumper($v));
25 }
26
27 #####################################################################
28 # load a data structure from a file (as saved with SaveStructure)
29 sub LoadStructure($)
30 {
31         my $f = shift;
32         my $contents = FileLoad($f);
33         defined $contents || return undef;
34         return eval "$contents";
35 }
36
37 #####################################################################
38 # read a file into a string
39 sub FileLoad($)
40 {
41     my($filename) = shift;
42     local(*INPUTFILE);
43     open(INPUTFILE, $filename) || return undef;
44     my($saved_delim) = $/;
45     undef $/;
46     my($data) = <INPUTFILE>;
47     close(INPUTFILE);
48     $/ = $saved_delim;
49     return $data;
50 }
51
52 #####################################################################
53 # write a string into a file
54 sub FileSave($$)
55 {
56     my($filename) = shift;
57     my($v) = shift;
58     local(*FILE);
59     open(FILE, ">$filename") || die "can't open $filename";    
60     print FILE $v;
61     close(FILE);
62 }
63
64 my($opt_help) = 0;
65 my($opt_parse) = 0;
66 my($opt_dump) = 0;
67 my($opt_uint_enums) = 0;
68 my($opt_diff) = 0;
69 my($opt_header);
70 my($opt_ndr_header);
71 my($opt_template) = 0;
72 my($opt_client);
73 my($opt_server);
74 my($opt_ndr_parser);
75 my($opt_tdr_header);
76 my($opt_tdr_parser);
77 my($opt_eth_parser);
78 my($opt_keep);
79 my($opt_swig);
80 my($opt_dcom_proxy);
81 my($opt_com_header);
82 my($opt_ejs);
83 my($opt_odl) = 0;
84 my($opt_quiet) = 0;
85 my($opt_outputdir) = '.';
86 my($opt_verbose) = 0;
87 my($opt_warn_compat) = 0;
88
89 #########################################
90 # display help text
91 sub ShowHelp()
92 {
93 print "perl IDL parser and code generator
94 Copyright (C) tridge\@samba.org
95
96 Usage: pidl [options] [--] <idlfile> [<idlfile>...]
97
98 Generic Options:
99  --help                  this help page
100  --outputdir=OUTDIR      put output in OUTDIR/ [.]
101  --parse                 parse a idl file to a .pidl file
102  --dump                  dump a pidl file back to idl
103  --diff                  run diff on the idl and dumped output
104  --keep[=OUTFILE]        keep the .pidl file [BASENAME.pidl]
105  --odl                   accept ODL input
106  --warn-compat           warn about incompatibility with other compilers
107  --quiet                 be quiet
108  --verbose               be verbose
109
110 Samba 4 output:
111  --header[=OUTFILE]      create generic header file [BASENAME.h]
112  --uint-enums            don't use C enums, instead use uint* types
113  --ndr-header[=OUTFILE]  create a C NDR-specific header file [ndr_BASENAME.h]
114  --ndr-parser[=OUTFILE]  create a C NDR parser [ndr_BASENAME.c]
115  --client[=OUTFILE]      create a C NDR client [ndr_BASENAME_c.c]
116  --tdr-header[=OUTFILE]  create a C TDR header file [tdr_BASENAME.h]
117  --tdr-parser[=OUTFILE]  create a C TDR parser [tdr_BASENAME.c]
118  --ejs[=OUTFILE]         create ejs wrapper file [BASENAME_ejs.c]
119  --swig[=OUTFILE]        create swig wrapper file [BASENAME.i]
120  --server[=OUTFILE]      create server boilerplate [ndr_BASENAME_s.c]
121  --template              print a template for a pipe
122  --dcom-proxy[=OUTFILE]  create DCOM proxy (implies --odl) [ndr_BASENAME_p.c]
123  --com-header[=OUTFILE]  create header for COM (implies --odl) [com_BASENAME.h]
124
125 Ethereal parsers:
126  --eth-parser[=OUTFILE]  create ethereal parser and header
127 \n";
128     exit(0);
129 }
130
131 # main program
132 GetOptions (
133             'help|h|?' => \$opt_help, 
134             'outputdir=s' => \$opt_outputdir,
135             'parse' => \$opt_parse,
136             'dump' => \$opt_dump,
137             'uint-enums' => \$opt_uint_enums,
138             'ndr-header:s' => \$opt_ndr_header,
139                 'header:s' => \$opt_header,
140             'server:s' => \$opt_server,
141             'tdr-header:s' => \$opt_tdr_header,
142             'tdr-parser:s' => \$opt_tdr_parser,
143             'template' => \$opt_template,
144             'ndr-parser:s' => \$opt_ndr_parser,
145             'client:s' => \$opt_client,
146             'eth-parser:s' => \$opt_eth_parser,
147             'ejs' => \$opt_ejs,
148             'diff' => \$opt_diff,
149             'odl' => \$opt_odl,
150             'keep:s' => \$opt_keep,
151             'swig:s' => \$opt_swig,
152             'dcom-proxy:s' => \$opt_dcom_proxy,
153             'com-header:s' => \$opt_com_header,
154             'quiet' => \$opt_quiet,
155                 'verbose' => \$opt_verbose,
156             'warn-compat' => \$opt_warn_compat
157             );
158
159 if ($opt_help) {
160     ShowHelp();
161     exit(0);
162 }
163
164 sub process_file($)
165 {
166         my $idl_file = shift;
167         my $outputdir = $opt_outputdir;
168         my $pidl;
169         my $ndr;
170
171         my $basename = basename($idl_file, ".idl");
172
173         my($pidl_file) = ($opt_keep or "$outputdir/$basename.pidl");
174
175         unless ($opt_quiet) { print "Compiling $idl_file\n"; }
176
177         if ($opt_parse) {
178                 require Parse::Pidl::IDL;
179                 my $idl_parser = new Parse::Pidl::IDL;
180
181                 $pidl = $idl_parser->parse_idl($idl_file);
182                 defined @$pidl || die "Failed to parse $idl_file";
183                 require Parse::Pidl::Typelist;
184                 Parse::Pidl::Typelist::LoadIdl($pidl);
185                 if (defined($opt_keep) && !SaveStructure($pidl_file, $pidl)) {
186                             die "Failed to save $pidl_file\n";
187                 }
188         } else {
189                 $pidl = LoadStructure($pidl_file);
190                 defined $pidl || die "Failed to load $pidl_file - maybe you need --parse\n";
191         }
192
193         if ($opt_uint_enums) {
194                 Parse::Pidl::Util::setUseUintEnums(1);
195         }
196
197         if ($opt_dump) {
198                 require Parse::Pidl::Dump;
199                 print Parse::Pidl::Dump($pidl);
200         }
201
202         if ($opt_diff) {
203                 my($tempfile) = "$outputdir/$basename.tmp";
204                 FileSave($tempfile, IdlDump::Dump($pidl));
205                 system("diff -wu $idl_file $tempfile");
206                 unlink($tempfile);
207         }
208
209         if (defined($opt_com_header)) {
210                 require Parse::Pidl::Samba::COM::Header;
211                 my $res = Parse::Pidl::Samba::COM::Header::Parse($pidl);
212                 if ($res) {
213                         my $comh_filename = ($opt_com_header or "$outputdir/com_$basename.h");
214                         FileSave($comh_filename, 
215                         "#include \"librpc/gen_ndr/ndr_orpc.h\"\n" . 
216                         "#include \"$outputdir/ndr_$basename.h\"\n" . 
217                         $res);
218                 }
219                 $opt_odl = 1;
220         }
221
222         if (defined($opt_dcom_proxy)) {
223                 require Parse::Pidl::Samba::COM::Proxy;
224                 my $res = Parse::Pidl::Samba::COM::Proxy::Parse($pidl);
225                 if ($res) {
226                         my ($client) = ($opt_dcom_proxy or "$outputdir/$basename\_p.c");
227                         FileSave($client, 
228                         "#include \"includes.h\"\n" .
229                         "#include \"$outputdir/com_$basename.h\"\n" . 
230                         "#include \"lib/com/dcom/dcom.h\"\n" .$res);
231                 }
232                 $opt_odl = 1;
233         }
234
235         if ($opt_warn_compat) {
236                 require Parse::Pidl::Compat;
237                 Parse::Pidl::Compat::Check($pidl);
238         }
239
240         if ($opt_odl) {
241                 require Parse::Pidl::ODL;
242                 $pidl = Parse::Pidl::ODL::ODL2IDL($pidl);
243         }
244
245         if (defined($opt_ndr_header) or defined($opt_eth_parser) or 
246             defined($opt_client) or defined($opt_server) or 
247             defined($opt_ndr_parser) or defined($opt_ejs)) {
248                 require Parse::Pidl::NDR;
249                 Parse::Pidl::NDR::Validate($pidl);
250                 $ndr = Parse::Pidl::NDR::Parse($pidl);
251         }
252
253         if (defined($opt_header)) {
254                 my $header = ($opt_header or "$outputdir/$basename.h");
255                 require Parse::Pidl::Samba::Header;
256                 FileSave($header, Parse::Pidl::Samba::Header::Parse($pidl));
257         }
258
259         if (defined($opt_ndr_header)) {
260                 my $header = ($opt_ndr_header or "$outputdir/ndr_$basename.h");
261                 require Parse::Pidl::Samba::NDR::Header;
262                 FileSave($header, Parse::Pidl::Samba::NDR::Header::Parse($pidl, $basename));
263                 if (defined($opt_swig)) {
264                   require Parse::Pidl::Samba::SWIG;
265                   my($filename) = ($opt_swig or "$outputdir/$basename.i");
266                   Parse::Pidl::Samba::SWIG::RewriteHeader($pidl, $header, $filename);
267                 }
268         }
269
270         my $h_filename = "$outputdir/ndr_$basename.h";
271         if (defined($opt_client)) {
272                 require Parse::Pidl::Samba::NDR::Client;
273                 my ($client) = ($opt_client or "$outputdir/ndr_$basename\_c.c");
274
275                 FileSave($client, Parse::Pidl::Samba::NDR::Client::Parse($ndr,$h_filename));
276         }
277
278         if (defined($opt_ejs)) {
279                 require Parse::Pidl::Samba::EJS;
280                 require Parse::Pidl::Samba::EJSHeader;
281                 FileSave("$outputdir/ndr_$basename\_ejs.c", Parse::Pidl::Samba::EJS::Parse($ndr, $h_filename));
282
283                 FileSave("$outputdir/ndr_$basename\_ejs.h", Parse::Pidl::Samba::EJSHeader::Parse($ndr));
284         }
285
286         if (defined($opt_server)) {
287                 require Parse::Pidl::Samba::NDR::Server;
288                 my $dcom = "";
289
290                 foreach my $x (@{$pidl}) {
291                         next if ($x->{TYPE} ne "INTERFACE");
292
293                         if (Parse::Pidl::Util::has_property($x, "object")) {
294                                 require Parse::Pidl::Samba::COM::Stub;
295                                 $dcom .= Parse::Pidl::Samba::COM::Stub::ParseInterface($x);
296                         }
297                 }
298
299                 FileSave(($opt_server or "$outputdir/ndr_$basename\_s.c"), Parse::Pidl::Samba::NDR::Server::Parse($ndr,$h_filename));
300
301                 if ($dcom ne "") {
302                         $dcom = "
303 #include \"includes.h\"
304 #include \"$h_filename\"
305 #include \"rpc_server/dcerpc_server.h\"
306 #include \"rpc_server/common/common.h\"
307
308 $dcom
309 ";
310         FileSave("$outputdir/$basename\_d.c", $dcom);
311                 }
312         }
313
314         if (defined($opt_ndr_parser)) {
315                 my $parser = ($opt_ndr_parser or "$outputdir/ndr_$basename.c");
316                 require Parse::Pidl::Samba::NDR::Parser;
317                 FileSave($parser, Parse::Pidl::Samba::NDR::Parser::Parse($ndr, $parser));
318         }
319
320         if (defined($opt_eth_parser)) {
321           require Parse::Pidl::Ethereal::NDR;
322           my($eparser) = ($opt_eth_parser or "$outputdir/packet-dcerpc-$basename.c");
323           my $eheader = $eparser;
324           $eheader =~ s/\.c$/\.h/;
325           my $cnffile = $idl_file;
326           $cnffile =~ s/\.idl$/\.cnf/;
327
328           my ($dp, $dh) = Parse::Pidl::Ethereal::NDR::Parse($ndr, $idl_file, $eheader, $cnffile);
329           FileSave($eparser, $dp) if defined($dp);
330           FileSave($eheader, $dh) if defined($dh);
331         }
332
333         my $tdr_parser = ($opt_tdr_parser or "$outputdir/tdr_$basename.c");
334         my $tdr_header = ($opt_tdr_header or "$outputdir/tdr_$basename.h");
335         if (defined($opt_tdr_parser)) {
336                 require Parse::Pidl::Samba::TDR;
337                 FileSave($tdr_parser, Parse::Pidl::Samba::TDR::Parser($pidl, $tdr_header));
338         }
339
340         if (defined($opt_tdr_header)) {
341                 require Parse::Pidl::Samba::TDR;
342                 FileSave($tdr_header, Parse::Pidl::Samba::TDR::Header($pidl, $outputdir,$basename));
343         }
344
345         if ($opt_template) {
346                 require Parse::Pidl::Samba::Template;
347                 print Parse::Pidl::Samba::Template::Parse($pidl);
348         }
349 }
350
351 if (scalar(@ARGV) == 0) {
352         print "pidl: no input files\n";
353         exit(0);
354 }
355
356 process_file($_) foreach (@ARGV);