r12462: Hide oo magic from callers of the parser
[samba.git] / source4 / 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 =pod
11
12 =head1 NAME
13
14 pidl - An IDL compiler written in Perl
15
16 =head1 SYNOPSIS
17
18 pidl --help
19
20 pidl [--outputdir[=OUTNAME]] [--parse-idl-tree] [--dump-idl-tree] [--dump-ndr-tree] [--ndr-header[=OUTPUT]] [--header[=OUTPUT]] [--ejs[=OUTPUT]] [--swig[=OUTPUT]] [--uint-enums] [--ndr-parser[=OUTPUT]] [--client] [--server] [--dcom-proxy] [--com-header] [--warn-compat] [--quiet] [--verbose] [--template] [--eth-parser[=OUTPUT]] [--diff] [--dump-idl] [--tdr-header=[OUTPUT]] [--tdr-parser[=OUTPUT]] [--samba3-header[=OUTPUT]] [--samba3-parser=[OUTPUT]] [--samba3-server=[OUTPUT]] [--samba3-template[=OUTPUT]] [--samba3-client[=OUTPUT]] [<idlfile>.idl]...
21
22 =head1 DESCRIPTION
23
24 pidl is an IDL compiler written in Perl that aims to be somewhat 
25 compatible with the midl compiler. IDL is short for 
26 "Interface Definition Language".
27
28 pidl can generate stubs for DCE/RPC server code, DCE/RPC 
29 client code and ethereal dissectors for DCE/RPC traffic.
30
31 IDL compilers like pidl take a description 
32 of an interface as their input and use it to generate C 
33 (though support for other languages may be added later) code that 
34 can use these interfaces, pretty print data sent 
35 using these interfaces, or even generate ethereal 
36 dissectors that can parse data sent over the 
37 wire by these interfaces. 
38
39 pidl takes IDL files in the same format as is used by midl, 
40 converts it to a .pidl file (which contains pidl's internal representation of the interface) and can then generate whatever output you need.
41 .pidl files should be used for debugging purposes only. Write your 
42 interface definitions in .idl format.
43
44 The goal of pidl is to implement a IDL compiler that can be used 
45 while developing the RPC subsystem in Samba (for 
46 both marshalling/unmarshalling and debugging purposes).
47
48 =head1 OPTIONS
49
50 =over 4
51
52 =item I<--help>
53
54 Show list of available options.
55                 
56 =item I<--outputdir OUTNAME>
57
58 Write output files to the specified directory.  Defaults to the current 
59 directory.
60                 
61 =item I<--parse-idl-tree>
62
63 Read internal tree structure from input files rather 
64 then assuming they contain IDL.
65
66 =item I<--dump-idl>
67
68 Generate a new IDL file. File will be named OUTNAME.idl.
69
70 =item I<--header>
71
72 Generate a C header file for the specified interface. Filename defaults to OUTNAME.h.
73
74 =item I<--ndr-header>
75
76 Generate a C header file with the prototypes for the NDR parsers. Filename defaults to ndr_OUTNAME.h.
77
78 =item I<--ndr-parser>
79
80 Generate a C file containing NDR parsers. Filename defaults to ndr_OUTNAME.c.
81
82 =item I<--server>
83
84 Generate boilerplate for the RPC server that implements 
85 the interface. Filename defaults to ndr_OUTNAME_s.c.
86
87 =item I<--template>
88
89 Generate stubs for a RPC server that implements the interface. Output will 
90 be written to stdout.
91
92 =item I<--eth-parser>
93
94 Generate an Ethereal dissector (in C) and header file. The dissector filename
95 defaults to packet-dcerpc-OUTNAME.c while the header filename defaults to 
96 packet-dcerpc-OUTNAME.h.
97         
98 Pidl will read additional data from an ethereal conformance file if present. 
99 Such a file should have the same location as the IDL file but with the 
100 extension I<cnf> rather then I<idl>. See L<Parse::Pidl::Ethereal::Conformance>
101 for details on the format of this file.
102
103 =item I<--diff>
104
105 Parse an IDL file,  generate a new IDL file based on the internal data 
106 structures and see if there are any differences with the original IDL file. 
107 Useful for debugging pidl.
108
109 =item I<--dump-idl-tree>
110
111 Tell pidl to dump the internal tree representation of an IDL 
112 file the to disk. Useful for debugging pidl.
113
114 =item I<--dump-ndr-tree>
115
116 Tell pidl to dump the internal NDR information tree it generated 
117 from the IDL file to disk.  Useful for debugging pidl.
118
119 =item I<--samba3-header>
120
121 Generate Samba3-style RPC header file. Filename defaults to rpc_BASENAME.h.
122
123 =item I<--samba3-parser>
124
125 Generate parser file for Samba3, to be placed in rpc_parse/. Filename defaults 
126 to parse_BASENAME.c.
127
128 =item I<--samba3-server>
129
130 Generate server file for Samba3, to be placed in rpc_server/. Filename defaults 
131 to srv_BASENAME.c.
132
133 =item I<--samba3-template>
134
135 Generate template for server-side implementation in Samba3, to be placed in 
136 rpc_server/. Filename defaults to srv_BASENAME_nt.c
137
138 =item I<--samba3-client>
139
140 Generate client calls for Samba 3, to be placed in rpc_client/. Filename 
141 defaults to cli_BASENAME.c.
142
143 =back
144
145 =head1 IDL SYNTAX
146
147 IDL files are always preprocessed using the C preprocessor.
148
149 Pretty much everything in an interface (the interface itself, functions, 
150 parameters) can have attributes (or properties whatever name you give them). 
151 Attributes always prepend the element they apply to and are surrounded 
152 by square brackets ([]). Multiple attributes are separated by comma's; 
153 arguments to attributes are specified between parentheses. 
154
155 See the section COMPATIBILITY for the list of attributes that 
156 pidl supports.
157
158 C-style comments can be used.
159         
160 =head2 CONFORMANT ARRAYS
161
162 A conformant array is one with that ends in [*] or []. The strange
163 things about conformant arrays are that they can only appear as the last 
164 element of a structure (unless there is a pointer to the conformant array, 
165 of course) and the array size appears before the structure itself on the wire. 
166
167 So, in this example:
168
169         typedef struct {
170                 long abc;
171                 long count;     
172                 long foo;
173                 [size_is(count)] long s[*];
174         } Struct1;
175
176 it appears like this:
177
178         [size_is] [abc] [count] [foo] [s...]
179
180 the first [size_is] field is the allocation size of the array, and
181 occurs before the array elements and even before the structure
182 alignment.
183
184 Note that size_is() can refer to a constant, but that doesn't change
185 the wire representation. It does not make the array a fixed array.
186
187 midl.exe would write the above array as the following C header:
188
189    typedef struct {
190                 long abc;
191                 long count;     
192                 long foo;
193                 long s[1];
194         } Struct1;
195
196 pidl takes a different approach, and writes it like this:
197
198     typedef struct {
199                 long abc;
200                 long count;     
201                 long foo;
202                 long *s;
203         } Struct1;
204
205 =head2 VARYING ARRAYS
206
207 A varying array looks like this:
208
209         typedef struct {
210                 long abc;
211                 long count;     
212                 long foo;
213                 [size_is(count)] long *s;
214         } Struct1;
215
216 This will look like this on the wire:
217
218         [abc] [count] [foo] [PTR_s]    [count] [s...]
219
220 =head2 FIXED ARRAYS
221
222 A fixed array looks like this:
223
224     typedef struct {
225             long s[10];
226     } Struct1;
227
228 The NDR representation looks just like 10 separate long
229 declarations. The array size is not encoded on the wire.
230
231 pidl also supports "inline" arrays, which are not part of the IDL/NDR
232 standard. These are declared like this:
233
234     typedef struct {
235             uint32 foo;
236             uint32 count;
237             uint32 bar;
238             long s[count];
239     } Struct1;
240
241 This appears like this:
242
243         [foo] [count] [bar] [s...]
244
245 Fixed arrays are an extension added to support some of the strange
246 embedded structures in security descriptors and spoolss. 
247
248 This section is by no means complete. See the OpenGroup and MSDN 
249         documentation for additional information.
250
251 =head1 COMPATIBILITY WITH MIDL
252
253 =head2 Missing features in pidl
254
255 The following MIDL features are not (yet) implemented in pidl 
256 or are implemented with an incompatible interface:
257
258 =over
259
260 =item *
261
262 Asynchronous communication
263
264 =item * 
265
266 Typelibs (.tlb files)
267
268 =item *
269
270 Datagram support (ncadg_*)
271
272 =back
273
274 =head2 Supported attributes
275
276 in, out, ref, length_is, switch_is, size_is, uuid, case, default, string, 
277 unique, ptr, pointer_default, v1_enum, object, helpstring, range, local, 
278 call_as, endpoint, switch_type, progid, coclass, iid_is, represent_as.
279
280 =head2 PIDL Specific properties
281
282 =over 4
283
284 =item public
285
286 The [public] property on a structure or union is a pidl extension that
287 forces the generated pull/push functions to be non-static. This allows
288 you to declare types that can be used between modules. If you don't
289 specify [public] then pull/push functions for other than top-level
290 functions are declared static.
291                                 
292 =item noprint
293
294 The [noprint] property is a pidl extension that allows you to specify
295 that pidl should not generate a ndr_print_*() function for that
296 structure or union. This is used when you wish to define your own
297 print function that prints a structure in a nicer manner. A good
298 example is the use of [noprint] on dom_sid, which allows the
299 pretty-printing of SIDs.
300
301 =item value
302
303 The [value(expression)] property is a pidl extension that allows you
304 to specify the value of a field when it is put on the wire. This
305 allows fields that always have a well-known value to be automatically
306 filled in, thus making the API more programmer friendly. The
307 expression can be any C expression.
308
309 =item relative
310
311 The [relative] property can be supplied on a pointer. When it is used
312 it declares the pointer as a spoolss style "relative" pointer, which
313 means it appears on the wire as an offset within the current
314 encapsulating structure. This is not part of normal IDL/NDR, but it is
315 a very useful extension as it avoids the manual encoding of many
316 complex structures.
317
318 =item subcontext(length)
319
320 Specifies that a size of I<length>
321 bytes should be read, followed by a blob of that size, 
322 which will be parsed as NDR.
323
324 =item flag
325
326 Specify boolean options, mostly used for 
327 low-level NDR options. Several options 
328 can be specified using the | character.
329 Note that flags are inherited by substructures!
330
331 =item nodiscriminant
332
333 The [nodiscriminant] property on a union means that the usual uint16
334 discriminent field at the start of the union on the wire is
335 omitted. This is not normally allowed in IDL/NDR, but is used for some
336 spoolss structures.
337
338 =item charset(name)
339
340 Specify that the array or string uses the specified 
341 charset. If this attribute is specified, pidl will 
342 take care of converting the character data from this format 
343 to the host format. Commonly used values are UCS2, DOS and UTF8.
344
345 =back
346
347 =head2 Unsupported MIDL properties
348
349 aggregatable, appobject, async_uuid, bindable, control, cpp_quote, 
350 defaultbind, defaultcollelem, defaultvalue, defaultvtable, dispinterface, 
351 displaybind, dual, entry, first_is, helpcontext, helpfile, helpstringcontext, 
352 helpstringdll, hidden, idl_module, idl_quote, id, immediatebind, importlib, 
353 import, include, includelib, last_is, lcid, licensed, max_is, module, 
354 ms_union, no_injected_text, nonbrowsable, noncreatable, nonextensible, odl, 
355 oleautomation, optional, pragma, propget, propputref, propput, readonly, 
356 requestedit, restricted, retval, source, transmit_as, uidefault, 
357 usesgetlasterror, vararg, vi_progid, wire_marshal. 
358
359 =head1 EXAMPLES
360
361         # Generating an ethereal parser
362         $ ./pidl --eth-parser -- atsvc.idl
363         
364         # Generating a TDR parser and header
365         $ ./pidl --tdr-parser --tdr-header --header -- regf.idl
366
367         # Generating a Samba3 parser, client and server
368         $ ./pidl --samba3-parser --samba3-server --samba3-client -- dfs.idl
369
370         # Generating a Samba4 NDR parser, client and server
371         $ ./pidl --ndr-parser --ndr-client --ndr-server -- samr.idl
372
373 =head1 SEE ALSO
374
375 L<http://msdn.microsoft.com/library/en-us/rpc/rpc/field_attributes.asp>,
376 L<http://wiki.ethereal.com/DCE/RPC>, 
377 L<http://www.samba.org/>,
378 L<yapp(1)>
379
380 =head1 LICENSE
381
382 pidl is licensed under the GNU General Public License L<http://www.gnu.org/licenses/gpl.html>.
383
384 =head1 AUTHOR
385
386 pidl was written by Andrew Tridgell, Stefan Metzmacher, Tim Potter and Jelmer 
387 Vernooij. The current maintainer is Jelmer Vernooij.
388
389 This manpage was written by Jelmer Vernooij, partially based on the original 
390 pidl README by Andrew Tridgell. 
391         
392 =cut
393
394
395 use strict;
396 use FindBin qw($RealBin);
397 use lib "$RealBin";
398 use lib "$RealBin/lib";
399 use Getopt::Long;
400 use File::Basename;
401 use Parse::Pidl;
402 use Parse::Pidl::Util;
403 use Parse::Pidl::ODL;
404
405 #####################################################################
406 # save a data structure into a file
407 sub SaveStructure($$)
408 {
409         my($filename,$v) = @_;
410         FileSave($filename, Parse::Pidl::Util::MyDumper($v));
411 }
412
413 #####################################################################
414 # load a data structure from a file (as saved with SaveStructure)
415 sub LoadStructure($)
416 {
417         my $f = shift;
418         my $contents = FileLoad($f);
419         defined $contents || return undef;
420         return eval "$contents";
421 }
422
423 #####################################################################
424 # read a file into a string
425 sub FileLoad($)
426 {
427     my($filename) = shift;
428     local(*INPUTFILE);
429     open(INPUTFILE, $filename) || return undef;
430     my($saved_delim) = $/;
431     undef $/;
432     my($data) = <INPUTFILE>;
433     close(INPUTFILE);
434     $/ = $saved_delim;
435     return $data;
436 }
437
438 #####################################################################
439 # write a string into a file
440 sub FileSave($$)
441 {
442     my($filename) = shift;
443     my($v) = shift;
444     local(*FILE);
445     open(FILE, ">$filename") || die "can't open $filename";    
446     print FILE $v;
447     close(FILE);
448 }
449
450 my($opt_help) = 0;
451 my($opt_parse_idl_tree) = 0;
452 my($opt_dump_idl_tree);
453 my($opt_dump_ndr_tree);
454 my($opt_dump_idl) = 0;
455 my($opt_uint_enums) = 0;
456 my($opt_diff) = 0;
457 my($opt_header);
458 my($opt_ndr_header);
459 my($opt_samba3_header);
460 my($opt_samba3_parser);
461 my($opt_samba3_server);
462 my($opt_samba3_template);
463 my($opt_samba3_client);
464 my($opt_template) = 0;
465 my($opt_client);
466 my($opt_server);
467 my($opt_ndr_parser);
468 my($opt_tdr_header);
469 my($opt_tdr_parser);
470 my($opt_eth_parser);
471 my($opt_swig);
472 my($opt_dcom_proxy);
473 my($opt_com_header);
474 my($opt_ejs);
475 my($opt_quiet) = 0;
476 my($opt_outputdir) = '.';
477 my($opt_verbose) = 0;
478 my($opt_warn_compat) = 0;
479
480 #########################################
481 # display help text
482 sub ShowHelp()
483 {
484 print "perl IDL parser and code generator
485 Copyright (C) Andrew Tridgell <tridge\@samba.org>
486 Copyright (C) Jelmer Vernooij <jelmer\@samba.org>
487
488 Usage: pidl [options] [--] <idlfile> [<idlfile>...]
489
490 Generic Options:
491  --help                  this help page
492  --outputdir=OUTDIR      put output in OUTDIR/ [.]
493  --warn-compat           warn about incompatibility with other compilers
494  --quiet                 be quiet
495  --verbose               be verbose
496
497 Debugging:
498  --dump-idl-tree[=FILE]  dump internal representation to file [BASENAME.pidl]
499  --parse-idl-tree        read internal representation instead of IDL
500  --dump-ndr-tree[=FILE]  dump internal NDR data tree to file [BASENAME.ndr]
501  --dump-idl              regenerate IDL file
502  --diff                  run diff on original IDL and dumped output
503
504 Samba 4 output:
505  --header[=OUTFILE]      create generic header file [BASENAME.h]
506  --uint-enums            don't use C enums, instead use uint* types
507  --ndr-header[=OUTFILE]  create a C NDR-specific header file [ndr_BASENAME.h]
508  --ndr-parser[=OUTFILE]  create a C NDR parser [ndr_BASENAME.c]
509  --client[=OUTFILE]      create a C NDR client [ndr_BASENAME_c.c]
510  --tdr-header[=OUTFILE]  create a C TDR header file [tdr_BASENAME.h]
511  --tdr-parser[=OUTFILE]  create a C TDR parser [tdr_BASENAME.c]
512  --ejs[=OUTFILE]         create ejs wrapper file [BASENAME_ejs.c]
513  --swig[=OUTFILE]        create swig wrapper file [BASENAME.i]
514  --server[=OUTFILE]      create server boilerplate [ndr_BASENAME_s.c]
515  --template              print a template for a pipe
516  --dcom-proxy[=OUTFILE]  create DCOM proxy [ndr_BASENAME_p.c]
517  --com-header[=OUTFILE]  create header for COM [com_BASENAME.h]
518
519 Samba 3 output:
520  --samba3-header[=OUTF]  create Samba3-style header [rpc_BASENAME.h]
521  --samba3-parser[=OUTF]  create parser for Samba3 [parse_BASENAME.c]
522  --samba3-template[=OUTF]create template implementation [srv_BASENAME_nt.c]
523  --samba3-server[=OUTF]  create server side wrappers for Samba3 [srv_BASENAME.c]
524  --samba3-client[=OUTF]  create client calls for Samba3 [cli_BASENAME.c]
525
526 Ethereal parsers:
527  --eth-parser[=OUTFILE]  create ethereal parser and header
528 \n";
529     exit(0);
530 }
531
532 # main program
533 my $result = GetOptions (
534             'help|h|?' => \$opt_help, 
535             'outputdir=s' => \$opt_outputdir,
536             'dump-idl' => \$opt_dump_idl,
537                 'dump-idl-tree:s' => \$opt_dump_idl_tree,
538                 'parse-idl-tree' => \$opt_parse_idl_tree,
539                 'dump-ndr-tree:s' => \$opt_dump_ndr_tree,
540             'uint-enums' => \$opt_uint_enums,
541             'ndr-header:s' => \$opt_ndr_header,
542                 'samba3-header:s' => \$opt_samba3_header,
543                 'samba3-parser:s' => \$opt_samba3_parser,
544                 'samba3-server:s' => \$opt_samba3_server,
545                 'samba3-template:s' => \$opt_samba3_template,
546                 'samba3-client:s' => \$opt_samba3_client,
547                 'header:s' => \$opt_header,
548             'server:s' => \$opt_server,
549             'tdr-header:s' => \$opt_tdr_header,
550             'tdr-parser:s' => \$opt_tdr_parser,
551             'template' => \$opt_template,
552             'ndr-parser:s' => \$opt_ndr_parser,
553             'client:s' => \$opt_client,
554             'eth-parser:s' => \$opt_eth_parser,
555             'ejs' => \$opt_ejs,
556             'diff' => \$opt_diff,
557             'swig:s' => \$opt_swig,
558             'dcom-proxy:s' => \$opt_dcom_proxy,
559             'com-header:s' => \$opt_com_header,
560             'quiet' => \$opt_quiet,
561                 'verbose' => \$opt_verbose,
562             'warn-compat' => \$opt_warn_compat
563             );
564
565 if (not $result) {
566         exit(1);
567 }
568
569 if ($opt_help) {
570     ShowHelp();
571     exit(0);
572 }
573
574 sub process_file($)
575 {
576         my $idl_file = shift;
577         my $outputdir = $opt_outputdir;
578         my $pidl;
579         my $ndr;
580
581         my $basename = basename($idl_file, ".idl");
582
583         unless ($opt_quiet) { print "Compiling $idl_file\n"; }
584
585         if ($opt_parse_idl_tree) {
586                 $pidl = LoadStructure($idl_file);
587                 defined $pidl || die "Failed to load $idl_file";
588         } else {
589                 require Parse::Pidl::IDL;
590
591                 $pidl = Parse::Pidl::IDL::parse_file($idl_file);
592                 defined @$pidl || die "Failed to parse $idl_file";
593                 require Parse::Pidl::Typelist;
594                 Parse::Pidl::Typelist::LoadIdl($pidl);
595         }
596         
597         if (defined($opt_dump_idl_tree)) {
598                 my($pidl_file) = ($opt_dump_idl_tree or "$outputdir/$basename.pidl");
599                 SaveStructure($pidl_file, $pidl) or die "Failed to save $pidl_file\n";
600         }
601
602         if ($opt_uint_enums) {
603                 Parse::Pidl::Util::setUseUintEnums(1);
604         }
605
606         if ($opt_dump_idl) {
607                 require Parse::Pidl::Dump;
608                 print Parse::Pidl::Dump($pidl);
609         }
610
611         if ($opt_diff) {
612                 my($tempfile) = "$outputdir/$basename.tmp";
613                 FileSave($tempfile, IdlDump::Dump($pidl));
614                 system("diff -wu $idl_file $tempfile");
615                 unlink($tempfile);
616         }
617
618         if (defined($opt_com_header)) {
619                 require Parse::Pidl::Samba::COM::Header;
620                 my $res = Parse::Pidl::Samba::COM::Header::Parse($pidl);
621                 if ($res) {
622                         my $comh_filename = ($opt_com_header or "$outputdir/com_$basename.h");
623                         FileSave($comh_filename, 
624                         "#include \"librpc/gen_ndr/ndr_orpc.h\"\n" . 
625                         "#include \"$outputdir/ndr_$basename.h\"\n" . 
626                         $res);
627                 }
628         }
629
630         if (defined($opt_dcom_proxy)) {
631                 require Parse::Pidl::Samba::COM::Proxy;
632                 my $res = Parse::Pidl::Samba::COM::Proxy::Parse($pidl);
633                 if ($res) {
634                         my ($client) = ($opt_dcom_proxy or "$outputdir/$basename\_p.c");
635                         FileSave($client, 
636                         "#include \"includes.h\"\n" .
637                         "#include \"$outputdir/com_$basename.h\"\n" . 
638                         "#include \"lib/com/dcom/dcom.h\"\n" .$res);
639                 }
640         }
641
642         if ($opt_warn_compat) {
643                 require Parse::Pidl::Compat;
644                 Parse::Pidl::Compat::Check($pidl);
645         }
646
647         $pidl = Parse::Pidl::ODL::ODL2IDL($pidl);
648
649         if (defined($opt_ndr_header) or defined($opt_eth_parser) or 
650             defined($opt_client) or defined($opt_server) or 
651             defined($opt_ndr_parser) or defined($opt_ejs) or 
652                 defined($opt_dump_ndr_tree) or defined($opt_samba3_header) or 
653             defined($opt_samba3_header) or defined($opt_samba3_server) or 
654                 defined($opt_samba3_template) or defined($opt_samba3_client)) {
655                 require Parse::Pidl::NDR;
656                 Parse::Pidl::NDR::Validate($pidl);
657                 $ndr = Parse::Pidl::NDR::Parse($pidl);
658         }
659
660         if (defined($opt_dump_ndr_tree)) {
661                 my($ndr_file) = ($opt_dump_ndr_tree or "$outputdir/$basename.ndr");
662                 SaveStructure($ndr_file, $ndr) or die "Failed to save $ndr_file\n";
663         }
664
665         if (defined($opt_header)) {
666                 my $header = ($opt_header or "$outputdir/$basename.h");
667                 require Parse::Pidl::Samba::Header;
668                 FileSave($header, Parse::Pidl::Samba::Header::Parse($pidl));
669         }
670
671         if (defined($opt_ndr_header)) {
672                 my $header = ($opt_ndr_header or "$outputdir/ndr_$basename.h");
673                 require Parse::Pidl::Samba::NDR::Header;
674                 FileSave($header, Parse::Pidl::Samba::NDR::Header::Parse($pidl, $basename));
675                 if (defined($opt_swig)) {
676                   require Parse::Pidl::Samba::SWIG;
677                   my($filename) = ($opt_swig or "$outputdir/$basename.i");
678                   Parse::Pidl::Samba::SWIG::RewriteHeader($pidl, $header, $filename);
679                 }
680         }
681
682         my $h_filename = "$outputdir/ndr_$basename.h";
683         if (defined($opt_client)) {
684                 require Parse::Pidl::Samba::NDR::Client;
685                 my ($client) = ($opt_client or "$outputdir/ndr_$basename\_c.c");
686
687                 FileSave($client, Parse::Pidl::Samba::NDR::Client::Parse($ndr,$h_filename));
688         }
689
690         if (defined($opt_ejs)) {
691                 require Parse::Pidl::Samba::EJS;
692                 require Parse::Pidl::Samba::EJSHeader;
693                 FileSave("$outputdir/ndr_$basename\_ejs.c", Parse::Pidl::Samba::EJS::Parse($ndr, $h_filename));
694
695                 FileSave("$outputdir/ndr_$basename\_ejs.h", Parse::Pidl::Samba::EJSHeader::Parse($ndr));
696         }
697
698         if (defined($opt_server)) {
699                 require Parse::Pidl::Samba::NDR::Server;
700                 my $dcom = "";
701
702                 foreach my $x (@{$pidl}) {
703                         next if ($x->{TYPE} ne "INTERFACE");
704
705                         if (Parse::Pidl::Util::has_property($x, "object")) {
706                                 require Parse::Pidl::Samba::COM::Stub;
707                                 $dcom .= Parse::Pidl::Samba::COM::Stub::ParseInterface($x);
708                         }
709                 }
710
711                 FileSave(($opt_server or "$outputdir/ndr_$basename\_s.c"), Parse::Pidl::Samba::NDR::Server::Parse($ndr,$h_filename));
712
713                 if ($dcom ne "") {
714                         $dcom = "
715 #include \"includes.h\"
716 #include \"$h_filename\"
717 #include \"rpc_server/dcerpc_server.h\"
718 #include \"rpc_server/common/common.h\"
719
720 $dcom
721 ";
722         FileSave("$outputdir/$basename\_d.c", $dcom);
723                 }
724         }
725
726         if (defined($opt_ndr_parser)) {
727                 my $parser = ($opt_ndr_parser or "$outputdir/ndr_$basename.c");
728                 require Parse::Pidl::Samba::NDR::Parser;
729                 FileSave($parser, Parse::Pidl::Samba::NDR::Parser::Parse($ndr, $parser));
730         }
731
732         if (defined($opt_eth_parser)) {
733           require Parse::Pidl::Ethereal::NDR;
734           my($eparser) = ($opt_eth_parser or "$outputdir/packet-dcerpc-$basename.c");
735           my $eheader = $eparser;
736           $eheader =~ s/\.c$/\.h/;
737           my $cnffile = $idl_file;
738           $cnffile =~ s/\.idl$/\.cnf/;
739
740           my ($dp, $dh) = Parse::Pidl::Ethereal::NDR::Parse($ndr, $idl_file, $eheader, $cnffile);
741           FileSave($eparser, $dp) if defined($dp);
742           FileSave($eheader, $dh) if defined($dh);
743         }
744
745         my $tdr_parser = ($opt_tdr_parser or "$outputdir/tdr_$basename.c");
746         my $tdr_header = ($opt_tdr_header or "$outputdir/tdr_$basename.h");
747         if (defined($opt_tdr_parser)) {
748                 require Parse::Pidl::Samba::TDR;
749                 FileSave($tdr_parser, Parse::Pidl::Samba::TDR::Parser($pidl, $tdr_header));
750         }
751
752         if (defined($opt_tdr_header)) {
753                 require Parse::Pidl::Samba::TDR;
754                 FileSave($tdr_header, Parse::Pidl::Samba::TDR::Header($pidl, $outputdir,$basename));
755         }
756
757         if ($opt_template) {
758                 require Parse::Pidl::Samba::Template;
759                 print Parse::Pidl::Samba::Template::Parse($pidl);
760         }
761
762         if (defined($opt_samba3_header) or defined($opt_samba3_parser) or
763                 defined($opt_samba3_server) or defined($opt_samba3_client) or
764                 defined($opt_samba3_template)) {
765                 require Parse::Pidl::Samba3::Types;
766                 Parse::Pidl::Samba3::Types::LoadTypes($ndr);
767         }
768
769         if (defined($opt_samba3_header)) {
770                 my $header = ($opt_samba3_header or "$outputdir/rpc_$basename.h");
771                 require Parse::Pidl::Samba3::Header;
772                 FileSave($header, Parse::Pidl::Samba3::Header::Parse($ndr, $basename));
773         }
774
775         if (defined($opt_samba3_parser)) {
776                 my $header = ($opt_samba3_parser or "$outputdir/parse_$basename.c");
777                 require Parse::Pidl::Samba3::Parser;
778                 FileSave($header, Parse::Pidl::Samba3::Parser::Parse($ndr, $basename));
779         }
780
781         if (defined($opt_samba3_server)) {
782                 my $header = ($opt_samba3_server or "$outputdir/srv_$basename.c");
783                 require Parse::Pidl::Samba3::Server;
784                 FileSave($header, Parse::Pidl::Samba3::Server::Parse($ndr, $basename));
785         }
786
787         if (defined($opt_samba3_template)) {
788                 my $header = ($opt_samba3_template or "$outputdir/srv_$basename\_nt.c");
789                 require Parse::Pidl::Samba3::Template;
790                 FileSave($header, Parse::Pidl::Samba3::Template::Parse($ndr, $basename));
791         }
792
793         if (defined($opt_samba3_client)) {
794                 my $header = ($opt_samba3_client or "$outputdir/cli_$basename.c");
795                 require Parse::Pidl::Samba3::Client;
796                 FileSave($header, Parse::Pidl::Samba3::Client::Parse($ndr, $basename));
797         }
798
799 }
800
801 if (scalar(@ARGV) == 0) {
802         print "pidl: no input files\n";
803         exit(1);
804 }
805
806 process_file($_) foreach (@ARGV);