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