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