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