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