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