r4469: Version n + 1 of the pidl ethereal parser generator. This version is
[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 header;
19 use server;
20 use client;
21 use proxy;
22 use stub;
23 use parser;
24 use eparser;
25 use validator;
26 use util;
27 use template;
28 use swig;
29
30 my($opt_help) = 0;
31 my($opt_parse) = 0;
32 my($opt_dump) = 0;
33 my($opt_diff) = 0;
34 my($opt_header) = 0;
35 my($opt_template) = 0;
36 my($opt_client) = 0;
37 my($opt_server) = 0;
38 my($opt_parser) = 0;
39 my($opt_eparser) = 0;
40 my($opt_keep) = 0;
41 my($opt_swig) = 0;
42 my($opt_output);
43
44 my $idl_parser = new idl;
45
46 #####################################################################
47 # parse an IDL file returning a structure containing all the data
48 sub IdlParse($)
49 {
50     my $filename = shift;
51     my $idl = $idl_parser->parse_idl($filename);
52     util::CleanData($idl);
53     return $idl;
54 }
55
56
57 #########################################
58 # display help text
59 sub ShowHelp()
60 {
61     print "
62            perl IDL parser and code generator
63            Copyright (C) tridge\@samba.org
64
65            Usage: pidl.pl [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              --header              create a C header file
73              --parser              create a C parser
74              --client              create a C client
75              --server              create server boilerplate
76              --template            print a template for a pipe
77              --eparser             create an ethereal parser
78              --swig                create swig wrapper file
79              --diff                run diff on the idl and dumped output
80              --keep                keep the .pidl file
81            \n";
82     exit(0);
83 }
84
85 # main program
86 GetOptions (
87             'help|h|?' => \$opt_help, 
88             'output=s' => \$opt_output,
89             'parse' => \$opt_parse,
90             'dump' => \$opt_dump,
91             'header' => \$opt_header,
92             'server' => \$opt_server,
93             'template' => \$opt_template,
94             'parser' => \$opt_parser,
95         'client' => \$opt_client,
96             'eparser' => \$opt_eparser,
97             'diff' => \$opt_diff,
98             'keep' => \$opt_keep,
99             'swig' => \$opt_swig
100             );
101
102 if ($opt_help) {
103     ShowHelp();
104     exit(0);
105 }
106
107 sub process_file($)
108 {
109         my $idl_file = shift;
110         my $output;
111         my $pidl;
112
113         my $basename = basename($idl_file, ".idl");
114
115         if (!defined($opt_output)) {
116                 $output = $idl_file;
117         } else {
118                 $output = $opt_output . $basename;
119         }
120
121         my($pidl_file) = util::ChangeExtension($output, ".pidl");
122
123         print "Compiling $idl_file\n";
124
125         if ($opt_parse) {
126                 $pidl = IdlParse($idl_file);
127                 defined @$pidl || die "Failed to parse $idl_file";
128                 IdlValidator::Validate($pidl);
129                 if ($opt_keep && !util::SaveStructure($pidl_file, $pidl)) {
130                             die "Failed to save $pidl_file\n";
131                 }
132         } else {
133                 $pidl = util::LoadStructure($pidl_file);
134                 defined $pidl || die "Failed to load $pidl_file - maybe you need --parse\n";
135         }
136
137         if ($opt_dump) {
138                 print IdlDump::Dump($pidl);
139         }
140
141         if ($opt_header) {
142                 my($header) = util::ChangeExtension($output, ".h");
143                 util::FileSave($header, IdlHeader::Parse($pidl));
144         }
145
146         if ($opt_client) {
147                 my ($client) = util::ChangeExtension($output, "_c.c");
148                 my $res = "";
149                 my $h_filename = util::ChangeExtension($output, ".h");
150                 my $need_dcom_register = 0;
151
152                 $res .= "#include \"includes.h\"\n";
153                 $res .= "#include \"$h_filename\"\n\n";
154
155                 foreach my $x (@{$pidl}) {
156                         if (util::has_property($x, "object")) {
157                                 $res .= IdlProxy::ParseInterface($x);
158                                 $need_dcom_register = 1;
159                         } else {
160                                 $res .= IdlClient::ParseInterface($x);
161                         }
162                 }
163
164                 if ($need_dcom_register) {
165                         $res .= IdlProxy::RegistrationFunction($pidl, $basename);
166                 }
167                 util::FileSave($client, $res);
168         }
169
170         if ($opt_server) {
171                 my $h_filename = util::ChangeExtension($output, ".h");
172                 my $plain = "";
173                 my $dcom = "";
174
175                 foreach my $x (@{$pidl}) {
176                         next if ($x->{TYPE} ne "INTERFACE");
177
178                         if (util::has_property($x, "object")) {
179                                 $dcom .= IdlStub::ParseInterface($x);
180                         } else {
181                                 $plain .= IdlServer::ParseInterface($x);
182                         }
183                 }
184
185                 if ($plain ne "") {
186                         util::FileSave(util::ChangeExtension($output, "_s.c"), $plain);
187                 }
188
189                 if ($dcom ne "") {
190                         $dcom = "
191 #include \"includes.h\"
192 #include \"$h_filename\"
193 #include \"rpc_server/dcerpc_server.h\"
194 #include \"rpc_server/common/common.h\"
195
196 $dcom
197 ";
198                         util::FileSave(util::ChangeExtension($output, "_d.c"), $dcom);
199                 }
200         }
201
202         if ($opt_parser) {
203                 my($parser) = util::ChangeExtension($output, ".c");
204                 IdlParser::Parse($pidl, $parser);
205         }
206
207         if ($opt_eparser) {
208
209           # Generate regular .c and .h files for marshaling and
210           # unmarshaling.
211
212           my($parser) = util::ChangeExtension($output, ".c");
213           IdlParser::Parse($pidl, $parser);
214
215           my($header) = util::ChangeExtension($output, ".h");
216           util::FileSave($header, IdlHeader::Parse($pidl));
217
218           # Postprocess to produce ethereal parsers.
219
220           my($eparser) = dirname($output) . "/packet-dcerpc-$basename.c";
221           IdlEParser::RewriteC($pidl, $parser, $eparser);
222
223           my($eparserhdr) = dirname($output) . "/packet-dcerpc-$basename.h";
224           IdlEParser::RewriteHeader($pidl, $header, $eparserhdr);
225         }
226
227         if ($opt_swig) {
228                 my($filename) = $output;
229                 $filename =~ s/\/ndr_/\//;
230                 $filename = util::ChangeExtension($filename, ".i");
231                 util::FileSave($filename, IdlSwig::Parse($pidl));
232         }
233
234         if ($opt_diff) {
235                 my($tempfile) = util::ChangeExtension($output, ".tmp");
236                 util::FileSave($tempfile, IdlDump::Dump($pidl));
237                 system("diff -wu $idl_file $tempfile");
238                 unlink($tempfile);
239         }
240
241         if ($opt_template) {
242                 print IdlTemplate::Parse($pidl);
243         }
244 }
245
246
247 foreach my $filename (@ARGV) {
248         process_file($filename);
249 }