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