r6973: Merge new version of pidl into the main SAMBA_4_0 branch.
[samba.git] / source / build / pidl / pidl.pl
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 FindBin qw($RealBin);
13 use lib "$RealBin";
14 use lib "$RealBin/lib";
15 use Getopt::Long;
16 use File::Basename;
17 use idl;
18 use dump;
19 use ndr_client;
20 use ndr_header;
21 use ndr_parser;
22 use server;
23 use dcom_proxy;
24 use dcom_stub;
25 use com_header;
26 use odl;
27 use eth_parser;
28 use eth_header;
29 use validator;
30 use typelist;
31 use util;
32 use template;
33 use swig;
34 use compat;
35
36 my($opt_help) = 0;
37 my($opt_parse) = 0;
38 my($opt_dump) = 0;
39 my($opt_diff) = 0;
40 my($opt_header);
41 my($opt_template) = 0;
42 my($opt_client) = 0;
43 my($opt_server) = 0;
44 my($opt_parser);
45 my($opt_eth_parser);
46 my($opt_eth_header);
47 my($opt_keep) = 0;
48 my($opt_swig) = 0;
49 my($opt_dcom_proxy) = 0;
50 my($opt_com_header) = 0;
51 my($opt_odl) = 0;
52 my($opt_quiet) = 0;
53 my($opt_output);
54 my($opt_warn_compat) = 0;
55
56 my $idl_parser = new idl;
57
58 #########################################
59 # display help text
60 sub ShowHelp()
61 {
62     print "
63        perl IDL parser and code generator
64        Copyright (C) tridge\@samba.org
65
66        Usage: pidl.pl [options] <idlfile>
67
68        Options:
69          --help                this help page
70          --output=OUTNAME      put output in OUTNAME.*
71          --parse               parse a idl file to a .pidl file
72          --dump                dump a pidl file back to idl
73          --header[=OUTFILE]    create a C NDR header file
74          --parser[=OUTFILE]    create a C NDR parser
75          --client              create a C NDR client
76          --server              create server boilerplate
77          --template            print a template for a pipe
78          --eth-parser          create an ethereal parser
79                  --eth-header          create an ethereal header file
80          --swig                create swig wrapper file
81          --diff                run diff on the idl and dumped output
82          --keep                keep the .pidl file
83          --odl                 accept ODL input
84          --dcom-proxy          create DCOM proxy (implies --odl)
85          --com-header          create header for COM interfaces (implies --odl)
86                  --warn-compat         warn about incompatibility with other compilers
87                  --quiet               be quiet
88          \n";
89     exit(0);
90 }
91
92 # main program
93 GetOptions (
94             'help|h|?' => \$opt_help, 
95             'output=s' => \$opt_output,
96             'parse' => \$opt_parse,
97             'dump' => \$opt_dump,
98             'header:s' => \$opt_header,
99             'server' => \$opt_server,
100             'template' => \$opt_template,
101             'parser:s' => \$opt_parser,
102         'client' => \$opt_client,
103             'eth-parser:s' => \$opt_eth_parser,
104                 'eth-header:s' => \$opt_eth_header,
105             'diff' => \$opt_diff,
106                 'odl' => \$opt_odl,
107             'keep' => \$opt_keep,
108             'swig' => \$opt_swig,
109                 'dcom-proxy' => \$opt_dcom_proxy,
110                 'com-header' => \$opt_com_header,
111                 'quiet' => \$opt_quiet,
112                 'warn-compat' => \$opt_warn_compat
113             );
114
115 if ($opt_help) {
116     ShowHelp();
117     exit(0);
118 }
119
120 sub process_file($)
121 {
122         my $idl_file = shift;
123         my $output;
124         my $pidl;
125         my $ndr;
126
127         my $basename = basename($idl_file, ".idl");
128
129         if (!defined($opt_output)) {
130                 $output = $idl_file;
131         } else {
132                 $output = $opt_output . $basename;
133         }
134
135         my($pidl_file) = util::ChangeExtension($output, ".pidl");
136
137         unless ($opt_quiet) { print "Compiling $idl_file\n"; }
138
139         if ($opt_parse) {
140                 $pidl = $idl_parser->parse_idl($idl_file);
141                 defined @$pidl || die "Failed to parse $idl_file";
142                 typelist::LoadIdl($pidl);
143                 IdlValidator::Validate($pidl);
144                 if ($opt_keep && !util::SaveStructure($pidl_file, $pidl)) {
145                             die "Failed to save $pidl_file\n";
146                 }
147         } else {
148                 $pidl = util::LoadStructure($pidl_file);
149                 defined $pidl || die "Failed to load $pidl_file - maybe you need --parse\n";
150         }
151
152         if ($opt_dump) {
153                 print IdlDump::Dump($pidl);
154         }
155
156         if ($opt_diff) {
157                 my($tempfile) = util::ChangeExtension($output, ".tmp");
158                 util::FileSave($tempfile, IdlDump::Dump($pidl));
159                 system("diff -wu $idl_file $tempfile");
160                 unlink($tempfile);
161         }
162
163         if ($opt_com_header) {
164                 my $res = COMHeader::Parse($pidl);
165                 if ($res) {
166                         my $h_filename = dirname($output) . "/com_$basename.h";
167                         util::FileSave($h_filename, 
168                         "#include \"librpc/gen_ndr/ndr_orpc.h\"\n" . 
169                         "#include \"librpc/gen_ndr/ndr_$basename.h\"\n" . 
170                         $res);
171                 }
172                 $opt_odl = 1;
173         }
174
175         if ($opt_dcom_proxy) {
176                 my $res = DCOMProxy::Parse($pidl);
177                 if ($res) {
178                         my ($client) = util::ChangeExtension($output, "_p.c");
179                         util::FileSave($client, 
180                         "#include \"includes.h\"\n" .
181                         "#include \"librpc/gen_ndr/com_$basename.h\"\n" . 
182                         "#include \"lib/com/dcom/dcom.h\"\n" .$res);
183                 }
184                 $opt_odl = 1;
185         }
186
187         if ($opt_warn_compat) {
188                 IDLCompat::Check($pidl);
189         }
190
191         if ($opt_odl) {
192                 $pidl = ODL::ODL2IDL($pidl);
193         }
194
195         if (defined($opt_header) or defined($opt_eth_parser) or defined($opt_eth_header) or $opt_client or $opt_server or defined($opt_parser)) {
196                 $ndr = Ndr::Parse($pidl);
197 #               print util::MyDumper($ndr);
198         }
199
200         if (defined($opt_header)) {
201                 my $header = $opt_header;
202                 if ($header eq "") {
203                         $header = util::ChangeExtension($output, ".h");
204                 }
205                 util::FileSave($header, NdrHeader::Parse($ndr));
206                 if ($opt_swig) {
207                   my($filename) = $output;
208                   $filename =~ s/\/ndr_/\//;
209                   $filename = util::ChangeExtension($filename, ".i");
210                   IdlSwig::RewriteHeader($pidl, $header, $filename);
211                 }
212         }
213
214         if (defined($opt_eth_header)) {
215           my($eparserhdr) = $opt_eth_header;
216           if ($eparserhdr eq "") {
217                   $eparserhdr = dirname($output) . "/packet-dcerpc-$basename.h";
218           }
219
220           util::FileSave($eparserhdr, EthHeader::Parse($ndr));
221         }
222
223         if ($opt_client) {
224                 my ($client) = util::ChangeExtension($output, "_c.c");
225                 my $res = "";
226                 my $h_filename = util::ChangeExtension($output, ".h");
227
228                 $res .= "#include \"includes.h\"\n";
229                 $res .= "#include \"$h_filename\"\n\n";
230
231                 foreach my $x (@{$pidl}) {
232                         $res .= NdrClient::ParseInterface($x);
233                 }
234
235                 util::FileSave($client, $res);
236         }
237
238         if ($opt_server) {
239                 my $h_filename = util::ChangeExtension($output, ".h");
240                 my $plain = "";
241                 my $dcom = "";
242
243                 foreach my $x (@{$pidl}) {
244                         next if ($x->{TYPE} ne "INTERFACE");
245
246                         if (util::has_property($x, "object")) {
247                                 $dcom .= DCOMStub::ParseInterface($x);
248                         } else {
249                                 $plain .= IdlServer::ParseInterface($x);
250                         }
251                 }
252
253                 if ($plain ne "") {
254                         util::FileSave(util::ChangeExtension($output, "_s.c"), $plain);
255                 }
256
257                 if ($dcom ne "") {
258                         $dcom = "
259 #include \"includes.h\"
260 #include \"$h_filename\"
261 #include \"rpc_server/dcerpc_server.h\"
262 #include \"rpc_server/common/common.h\"
263
264 $dcom
265 ";
266                         util::FileSave(util::ChangeExtension($output, "_d.c"), $dcom);
267                 }
268         }
269
270         if (defined($opt_parser)) {
271                 my $parser = $opt_parser;
272                 if ($parser eq "") {
273                         $parser = util::ChangeExtension($output, ".c");
274                 }
275                 
276                 util::FileSave($parser, NdrParser::Parse($ndr, $parser));
277         }
278
279         if (defined($opt_eth_parser)) {
280           my($eparser) = $opt_eth_parser;
281           if ($eparser eq "") {
282                   $eparser = dirname($output) . "/packet-dcerpc-$basename.c";
283           }
284           util::FileSave($eparser, EthParser::Parse($ndr, $basename, $eparser));
285         }
286
287
288         if ($opt_template) {
289                 print IdlTemplate::Parse($pidl);
290         }
291 }
292
293 foreach my $filename (@ARGV) {
294         process_file($filename);
295 }