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