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