#!/usr/bin/perl -w ################################################### # package to parse IDL files and generate code for # rpc functions in Samba # Copyright tridge@samba.org 2000-2003 # Copyright jelmer@samba.org 2005 # released under the GNU GPL use strict; use lib "lib"; use Getopt::Long; use File::Basename; use Parse::Pidl; use Parse::Pidl::Util; ##################################################################### # save a data structure into a file sub SaveStructure($$) { my($filename,$v) = @_; FileSave($filename, Parse::Pidl::Util::MyDumper($v)); } ##################################################################### # load a data structure from a file (as saved with SaveStructure) sub LoadStructure($) { my $f = shift; my $contents = FileLoad($f); defined $contents || return undef; return eval "$contents"; } ##################################################################### # read a file into a string sub FileLoad($) { my($filename) = shift; local(*INPUTFILE); open(INPUTFILE, $filename) || return undef; my($saved_delim) = $/; undef $/; my($data) = ; close(INPUTFILE); $/ = $saved_delim; return $data; } ##################################################################### # write a string into a file sub FileSave($$) { my($filename) = shift; my($v) = shift; local(*FILE); open(FILE, ">$filename") || die "can't open $filename"; print FILE $v; close(FILE); } my($opt_help) = 0; my($opt_parse) = 0; my($opt_dump) = 0; my($opt_uint_enums) = 0; my($opt_diff) = 0; my($opt_header); my($opt_ndr_header); my($opt_template) = 0; my($opt_client); my($opt_server); my($opt_ndr_parser); my($opt_tdr_header); my($opt_tdr_parser); my($opt_eth_parser); my($opt_keep); my($opt_swig); my($opt_dcom_proxy); my($opt_com_header); my($opt_ejs); my($opt_odl) = 0; my($opt_quiet) = 0; my($opt_outputdir) = '.'; my($opt_verbose) = 0; my($opt_warn_compat) = 0; ######################################### # display help text sub ShowHelp() { print "perl IDL parser and code generator Copyright (C) tridge\@samba.org Usage: pidl [options] [--] [...] Generic Options: --help this help page --outputdir=OUTDIR put output in OUTDIR/ [.] --parse parse a idl file to a .pidl file --dump dump a pidl file back to idl --diff run diff on the idl and dumped output --keep[=OUTFILE] keep the .pidl file --odl accept ODL input --warn-compat warn about incompatibility with other compilers --quiet be quiet --verbose be verbose Samba 4 output: --header[=OUTFILE] create generic header file --uint-enums don't use C enums, instead use uint* types --ndr-header[=OUTFILE] create a C NDR-specific header file --ndr-parser[=OUTFILE] create a C NDR parser --client[=OUTFILE] create a C NDR client --tdr-header[=OUTFILE] create a C TDR header file --tdr-parser[=OUTFILE] create a C TDR parser --ejs[=OUTFILE] create ejs wrapper file --swig[=OUTFILE] create swig wrapper file --server[=OUTFILE] create server boilerplate --template print a template for a pipe --dcom-proxy[=OUTFILE] create DCOM proxy (implies --odl) --com-header[=OUTFILE] create header for COM interfaces (implies --odl) Ethereal parsers: --eth-parser[=OUTFILE] create ethereal parser and header \n"; exit(0); } # main program GetOptions ( 'help|h|?' => \$opt_help, 'outputdir=s' => \$opt_outputdir, 'parse' => \$opt_parse, 'dump' => \$opt_dump, 'uint-enums' => \$opt_uint_enums, 'ndr-header:s' => \$opt_ndr_header, 'header:s' => \$opt_header, 'server:s' => \$opt_server, 'tdr-header:s' => \$opt_tdr_header, 'tdr-parser:s' => \$opt_tdr_parser, 'template' => \$opt_template, 'ndr-parser:s' => \$opt_ndr_parser, 'client:s' => \$opt_client, 'eth-parser:s' => \$opt_eth_parser, 'ejs' => \$opt_ejs, 'diff' => \$opt_diff, 'odl' => \$opt_odl, 'keep:s' => \$opt_keep, 'swig:s' => \$opt_swig, 'dcom-proxy:s' => \$opt_dcom_proxy, 'com-header:s' => \$opt_com_header, 'quiet' => \$opt_quiet, 'verbose' => \$opt_verbose, 'warn-compat' => \$opt_warn_compat ); if ($opt_help) { ShowHelp(); exit(0); } sub process_file($) { my $idl_file = shift; my $outputdir = $opt_outputdir; my $pidl; my $ndr; my $basename = basename($idl_file, ".idl"); my($pidl_file) = ($opt_keep or "$outputdir/$basename.pidl"); unless ($opt_quiet) { print "Compiling $idl_file\n"; } if ($opt_parse) { require Parse::Pidl::IDL; my $idl_parser = new Parse::Pidl::IDL; $pidl = $idl_parser->parse_idl($idl_file); defined @$pidl || die "Failed to parse $idl_file"; require Parse::Pidl::Typelist; Parse::Pidl::Typelist::LoadIdl($pidl); if (defined($opt_keep) && !SaveStructure($pidl_file, $pidl)) { die "Failed to save $pidl_file\n"; } } else { $pidl = LoadStructure($pidl_file); defined $pidl || die "Failed to load $pidl_file - maybe you need --parse\n"; } if ($opt_uint_enums) { Parse::Pidl::Util::setUseUintEnums(1); } if ($opt_dump) { require Parse::Pidl::Dump; print Parse::Pidl::Dump($pidl); } if ($opt_diff) { my($tempfile) = "$outputdir/$basename.tmp"; FileSave($tempfile, IdlDump::Dump($pidl)); system("diff -wu $idl_file $tempfile"); unlink($tempfile); } if (defined($opt_com_header)) { require Parse::Pidl::Samba::COM::Header; my $res = Parse::Pidl::Samba::COM::Header::Parse($pidl); if ($res) { my $comh_filename = ($opt_com_header or "$outputdir/com_$basename.h"); FileSave($comh_filename, "#include \"librpc/gen_ndr/ndr_orpc.h\"\n" . "#include \"$outputdir/ndr_$basename.h\"\n" . $res); } $opt_odl = 1; } if (defined($opt_dcom_proxy)) { require Parse::Pidl::Samba::COM::Proxy; my $res = Parse::Pidl::Samba::COM::Proxy::Parse($pidl); if ($res) { my ($client) = ($opt_dcom_proxy or "$outputdir/$basename\_p.c"); FileSave($client, "#include \"includes.h\"\n" . "#include \"$outputdir/com_$basename.h\"\n" . "#include \"lib/com/dcom/dcom.h\"\n" .$res); } $opt_odl = 1; } if ($opt_warn_compat) { require Parse::Pidl::Compat; Parse::Pidl::Compat::Check($pidl); } if ($opt_odl) { require Parse::Pidl::ODL; $pidl = Parse::Pidl::ODL::ODL2IDL($pidl); } if (defined($opt_ndr_header) or defined($opt_eth_parser) or defined($opt_client) or defined($opt_server) or defined($opt_ndr_parser) or defined($opt_ejs)) { require Parse::Pidl::NDR; Parse::Pidl::NDR::Validate($pidl); $ndr = Parse::Pidl::NDR::Parse($pidl); } if (defined($opt_header)) { my $header = ($opt_header or "$outputdir/$basename.h"); require Parse::Pidl::Samba::Header; FileSave($header, Parse::Pidl::Samba::Header::Parse($pidl)); } if (defined($opt_ndr_header)) { my $header = ($opt_ndr_header or "$outputdir/ndr_$basename.h"); require Parse::Pidl::Samba::NDR::Header; FileSave($header, Parse::Pidl::Samba::NDR::Header::Parse($pidl, $basename)); if (defined($opt_swig)) { require Parse::Pidl::Samba::SWIG; my($filename) = ($opt_swig or "$outputdir/$basename.i"); Parse::Pidl::Samba::SWIG::RewriteHeader($pidl, $header, $filename); } } my $h_filename = "$outputdir/ndr_$basename.h"; if (defined($opt_client)) { require Parse::Pidl::Samba::NDR::Client; my ($client) = ($opt_client or "$outputdir/ndr_$basename\_c.c"); FileSave($client, Parse::Pidl::Samba::NDR::Client::Parse($ndr,$h_filename)); } if (defined($opt_ejs)) { require Parse::Pidl::Samba::EJS; require Parse::Pidl::Samba::EJSHeader; FileSave("$outputdir/ndr_$basename\_ejs.c", Parse::Pidl::Samba::EJS::Parse($ndr, $h_filename)); FileSave("$outputdir/ndr_$basename\_ejs.h", Parse::Pidl::Samba::EJSHeader::Parse($ndr)); } if (defined($opt_server)) { require Parse::Pidl::Samba::NDR::Server; my $dcom = ""; foreach my $x (@{$pidl}) { next if ($x->{TYPE} ne "INTERFACE"); if (Parse::Pidl::Util::has_property($x, "object")) { require Parse::Pidl::Samba::COM::Stub; $dcom .= Parse::Pidl::Samba::COM::Stub::ParseInterface($x); } } FileSave(($opt_server or "$outputdir/ndr_$basename\_s.c"), Parse::Pidl::Samba::NDR::Server::Parse($ndr,$h_filename)); if ($dcom ne "") { $dcom = " #include \"includes.h\" #include \"$h_filename\" #include \"rpc_server/dcerpc_server.h\" #include \"rpc_server/common/common.h\" $dcom "; FileSave("$outputdir/$basename\_d.c", $dcom); } } if (defined($opt_ndr_parser)) { my $parser = ($opt_ndr_parser or "$outputdir/ndr_$basename.c"); require Parse::Pidl::Samba::NDR::Parser; FileSave($parser, Parse::Pidl::Samba::NDR::Parser::Parse($ndr, $parser)); } if (defined($opt_eth_parser)) { require Parse::Pidl::Ethereal::NDR; my($eparser) = ($opt_eth_parser or "$outputdir/packet-dcerpc-$basename.c"); my $eheader = $eparser; $eheader =~ s/\.c$/\.h/; my $cnffile = $idl_file; $cnffile =~ s/\.idl$/\.cnf/; my ($dp, $dh) = Parse::Pidl::Ethereal::NDR::Parse($ndr, $eheader, $cnffile); FileSave($eparser, $dp); FileSave($eheader, $dh); } my $tdr_parser = ($opt_tdr_parser or "$outputdir/tdr_$basename.c"); my $tdr_header = ($opt_tdr_header or "$outputdir/tdr_$basename.h"); if (defined($opt_tdr_parser)) { require Parse::Pidl::Samba::TDR; FileSave($tdr_parser, Parse::Pidl::Samba::TDR::Parser($pidl, $tdr_header)); } if (defined($opt_tdr_header)) { require Parse::Pidl::Samba::TDR; FileSave($tdr_header, Parse::Pidl::Samba::TDR::Header($pidl, $outputdir)); } if ($opt_template) { require Parse::Pidl::Samba::Template; print Parse::Pidl::Samba::Template::Parse($pidl); } } foreach my $filename (@ARGV) { process_file($filename); }