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