r10829: Documentation updates
[samba.git] / source / 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.
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                 my $idl_parser = new Parse::Pidl::IDL;
591
592                 $pidl = $idl_parser->parse_idl($idl_file);
593                 defined @$pidl || die "Failed to parse $idl_file";
594                 require Parse::Pidl::Typelist;
595                 Parse::Pidl::Typelist::LoadIdl($pidl);
596         }
597         
598         if (defined($opt_dump_idl_tree)) {
599                 my($pidl_file) = ($opt_dump_idl_tree or "$outputdir/$basename.pidl");
600                 SaveStructure($pidl_file, $pidl) or die "Failed to save $pidl_file\n";
601         }
602
603         if ($opt_uint_enums) {
604                 Parse::Pidl::Util::setUseUintEnums(1);
605         }
606
607         if ($opt_dump_idl) {
608                 require Parse::Pidl::Dump;
609                 print Parse::Pidl::Dump($pidl);
610         }
611
612         if ($opt_diff) {
613                 my($tempfile) = "$outputdir/$basename.tmp";
614                 FileSave($tempfile, IdlDump::Dump($pidl));
615                 system("diff -wu $idl_file $tempfile");
616                 unlink($tempfile);
617         }
618
619         if (defined($opt_com_header)) {
620                 require Parse::Pidl::Samba::COM::Header;
621                 my $res = Parse::Pidl::Samba::COM::Header::Parse($pidl);
622                 if ($res) {
623                         my $comh_filename = ($opt_com_header or "$outputdir/com_$basename.h");
624                         FileSave($comh_filename, 
625                         "#include \"librpc/gen_ndr/ndr_orpc.h\"\n" . 
626                         "#include \"$outputdir/ndr_$basename.h\"\n" . 
627                         $res);
628                 }
629         }
630
631         if (defined($opt_dcom_proxy)) {
632                 require Parse::Pidl::Samba::COM::Proxy;
633                 my $res = Parse::Pidl::Samba::COM::Proxy::Parse($pidl);
634                 if ($res) {
635                         my ($client) = ($opt_dcom_proxy or "$outputdir/$basename\_p.c");
636                         FileSave($client, 
637                         "#include \"includes.h\"\n" .
638                         "#include \"$outputdir/com_$basename.h\"\n" . 
639                         "#include \"lib/com/dcom/dcom.h\"\n" .$res);
640                 }
641         }
642
643         if ($opt_warn_compat) {
644                 require Parse::Pidl::Compat;
645                 Parse::Pidl::Compat::Check($pidl);
646         }
647
648         $pidl = Parse::Pidl::ODL::ODL2IDL($pidl);
649
650         if (defined($opt_ndr_header) or defined($opt_eth_parser) or 
651             defined($opt_client) or defined($opt_server) or 
652             defined($opt_ndr_parser) or defined($opt_ejs) or 
653                 defined($opt_dump_ndr_tree) or defined($opt_samba3_header) or 
654             defined($opt_samba3_header) or defined($opt_samba3_server) or 
655                 defined($opt_samba3_template) or defined($opt_samba3_client)) {
656                 require Parse::Pidl::NDR;
657                 Parse::Pidl::NDR::Validate($pidl);
658                 $ndr = Parse::Pidl::NDR::Parse($pidl);
659         }
660
661         if (defined($opt_dump_ndr_tree)) {
662                 my($ndr_file) = ($opt_dump_ndr_tree or "$outputdir/$basename.ndr");
663                 SaveStructure($ndr_file, $ndr) or die "Failed to save $ndr_file\n";
664         }
665
666         if (defined($opt_header)) {
667                 my $header = ($opt_header or "$outputdir/$basename.h");
668                 require Parse::Pidl::Samba::Header;
669                 FileSave($header, Parse::Pidl::Samba::Header::Parse($pidl));
670         }
671
672         if (defined($opt_ndr_header)) {
673                 my $header = ($opt_ndr_header or "$outputdir/ndr_$basename.h");
674                 require Parse::Pidl::Samba::NDR::Header;
675                 FileSave($header, Parse::Pidl::Samba::NDR::Header::Parse($pidl, $basename));
676                 if (defined($opt_swig)) {
677                   require Parse::Pidl::Samba::SWIG;
678                   my($filename) = ($opt_swig or "$outputdir/$basename.i");
679                   Parse::Pidl::Samba::SWIG::RewriteHeader($pidl, $header, $filename);
680                 }
681         }
682
683         my $h_filename = "$outputdir/ndr_$basename.h";
684         if (defined($opt_client)) {
685                 require Parse::Pidl::Samba::NDR::Client;
686                 my ($client) = ($opt_client or "$outputdir/ndr_$basename\_c.c");
687
688                 FileSave($client, Parse::Pidl::Samba::NDR::Client::Parse($ndr,$h_filename));
689         }
690
691         if (defined($opt_ejs)) {
692                 require Parse::Pidl::Samba::EJS;
693                 require Parse::Pidl::Samba::EJSHeader;
694                 FileSave("$outputdir/ndr_$basename\_ejs.c", Parse::Pidl::Samba::EJS::Parse($ndr, $h_filename));
695
696                 FileSave("$outputdir/ndr_$basename\_ejs.h", Parse::Pidl::Samba::EJSHeader::Parse($ndr));
697         }
698
699         if (defined($opt_server)) {
700                 require Parse::Pidl::Samba::NDR::Server;
701                 my $dcom = "";
702
703                 foreach my $x (@{$pidl}) {
704                         next if ($x->{TYPE} ne "INTERFACE");
705
706                         if (Parse::Pidl::Util::has_property($x, "object")) {
707                                 require Parse::Pidl::Samba::COM::Stub;
708                                 $dcom .= Parse::Pidl::Samba::COM::Stub::ParseInterface($x);
709                         }
710                 }
711
712                 FileSave(($opt_server or "$outputdir/ndr_$basename\_s.c"), Parse::Pidl::Samba::NDR::Server::Parse($ndr,$h_filename));
713
714                 if ($dcom ne "") {
715                         $dcom = "
716 #include \"includes.h\"
717 #include \"$h_filename\"
718 #include \"rpc_server/dcerpc_server.h\"
719 #include \"rpc_server/common/common.h\"
720
721 $dcom
722 ";
723         FileSave("$outputdir/$basename\_d.c", $dcom);
724                 }
725         }
726
727         if (defined($opt_ndr_parser)) {
728                 my $parser = ($opt_ndr_parser or "$outputdir/ndr_$basename.c");
729                 require Parse::Pidl::Samba::NDR::Parser;
730                 FileSave($parser, Parse::Pidl::Samba::NDR::Parser::Parse($ndr, $parser));
731         }
732
733         if (defined($opt_eth_parser)) {
734           require Parse::Pidl::Ethereal::NDR;
735           my($eparser) = ($opt_eth_parser or "$outputdir/packet-dcerpc-$basename.c");
736           my $eheader = $eparser;
737           $eheader =~ s/\.c$/\.h/;
738           my $cnffile = $idl_file;
739           $cnffile =~ s/\.idl$/\.cnf/;
740
741           my ($dp, $dh) = Parse::Pidl::Ethereal::NDR::Parse($ndr, $idl_file, $eheader, $cnffile);
742           FileSave($eparser, $dp) if defined($dp);
743           FileSave($eheader, $dh) if defined($dh);
744         }
745
746         my $tdr_parser = ($opt_tdr_parser or "$outputdir/tdr_$basename.c");
747         my $tdr_header = ($opt_tdr_header or "$outputdir/tdr_$basename.h");
748         if (defined($opt_tdr_parser)) {
749                 require Parse::Pidl::Samba::TDR;
750                 FileSave($tdr_parser, Parse::Pidl::Samba::TDR::Parser($pidl, $tdr_header));
751         }
752
753         if (defined($opt_tdr_header)) {
754                 require Parse::Pidl::Samba::TDR;
755                 FileSave($tdr_header, Parse::Pidl::Samba::TDR::Header($pidl, $outputdir,$basename));
756         }
757
758         if ($opt_template) {
759                 require Parse::Pidl::Samba::Template;
760                 print Parse::Pidl::Samba::Template::Parse($pidl);
761         }
762
763         if (defined($opt_samba3_header) or defined($opt_samba3_parser) or
764                 defined($opt_samba3_server) or defined($opt_samba3_client) or
765                 defined($opt_samba3_template)) {
766                 require Parse::Pidl::Samba3::Types;
767                 Parse::Pidl::Samba3::Types::LoadTypes($ndr);
768         }
769
770         if (defined($opt_samba3_header)) {
771                 my $header = ($opt_samba3_header or "$outputdir/rpc_$basename.h");
772                 require Parse::Pidl::Samba3::Header;
773                 FileSave($header, Parse::Pidl::Samba3::Header::Parse($ndr, $basename));
774         }
775
776         if (defined($opt_samba3_parser)) {
777                 my $header = ($opt_samba3_parser or "$outputdir/parse_$basename.c");
778                 require Parse::Pidl::Samba3::Parser;
779                 FileSave($header, Parse::Pidl::Samba3::Parser::Parse($ndr, $basename));
780         }
781
782         if (defined($opt_samba3_server)) {
783                 my $header = ($opt_samba3_server or "$outputdir/srv_$basename.c");
784                 require Parse::Pidl::Samba3::Server;
785                 FileSave($header, Parse::Pidl::Samba3::Server::Parse($ndr, $basename));
786         }
787
788         if (defined($opt_samba3_template)) {
789                 my $header = ($opt_samba3_template or "$outputdir/srv_$basename\_nt.c");
790                 require Parse::Pidl::Samba3::Template;
791                 FileSave($header, Parse::Pidl::Samba3::Template::Parse($ndr, $basename));
792         }
793
794         if (defined($opt_samba3_client)) {
795                 my $header = ($opt_samba3_client or "$outputdir/cli_$basename.c");
796                 require Parse::Pidl::Samba3::Client;
797                 FileSave($header, Parse::Pidl::Samba3::Client::Parse($ndr, $basename));
798         }
799
800 }
801
802 if (scalar(@ARGV) == 0) {
803         print "pidl: no input files\n";
804         exit(1);
805 }
806
807 process_file($_) foreach (@ARGV);