1
0
mirror of https://github.com/samba-team/samba.git synced 2025-12-02 00:23:50 +03:00
Files
samba-mirror/source/pidl/lib/Parse/Pidl/Samba/TDR.pm

279 lines
6.4 KiB
Perl

###################################################
# Trivial Parser Generator
# Copyright jelmer@samba.org 2005
# released under the GNU GPL
package Parse::Pidl::Samba::TDR;
use Parse::Pidl::Util qw(has_property ParseExpr is_constant);
use Data::Dumper;
use strict;
my $ret = "";
my $tabs = "";
sub indent() { $tabs.="\t"; }
sub deindent() { $tabs = substr($tabs, 1); }
sub pidl($) { $ret .= $tabs.(shift)."\n"; }
sub fatal($$) { my ($e,$s) = @_; die("$e->{FILE}:$e->{LINE}: $s\n"); }
sub static($) { my $p = shift; return("static ") unless ($p); return ""; }
sub typearg($) {
my $t = shift;
return(", const char *name") if ($t eq "print");
return(", TALLOC_CTX *mem_ctx") if ($t eq "pull");
return("");
}
sub ContainsArray($)
{
my $e = shift;
foreach (@{$e->{ELEMENTS}}) {
next if (has_property($_, "charset") and
scalar(@{$_->{ARRAY_LEN}}) == 1);
return 1 if (defined($_->{ARRAY_LEN}) and
scalar(@{$_->{ARRAY_LEN}}) > 0);
}
return 0;
}
sub ParserElement($$$)
{
my ($e,$t,$env) = @_;
my $switch = "";
my $array = "";
my $name = "";
my $mem_ctx = "mem_ctx";
fatal($e,"Pointers not supported in TDR") if ($e->{POINTERS} > 0);
fatal($e,"size_is() not supported in TDR") if (has_property($e, "size_is"));
fatal($e,"length_is() not supported in TDR") if (has_property($e, "length_is"));
if ($t eq "print") {
$name = ", \"$e->{NAME}\"$array";
}
if (has_property($e, "flag")) {
pidl "{";
indent;
pidl "uint32_t saved_flags = tdr->flags;";
pidl "tdr->flags |= $e->{PROPERTIES}->{flag};";
}
if (has_property($e, "charset")) {
fatal($e,"charset() on non-array element") unless (defined($e->{ARRAY_LEN}) and scalar(@{$e->{ARRAY_LEN}}) > 0);
my $len = ParseExpr(@{$e->{ARRAY_LEN}}[0], $env);
if ($len eq "*") { $len = "-1"; }
$name = ", mem_ctx" if ($t eq "pull");
pidl "TDR_CHECK(tdr_$t\_charset(tdr$name, &v->$e->{NAME}, $len, sizeof($e->{TYPE}_t), CH_$e->{PROPERTIES}->{charset}));";
return;
}
if (has_property($e, "switch_is")) {
$switch = ", " . ParseExpr($e->{PROPERTIES}->{switch_is}, $env);
}
if (defined($e->{ARRAY_LEN}) and scalar(@{$e->{ARRAY_LEN}}) > 0) {
my $len = ParseExpr($e->{ARRAY_LEN}[0], $env);
if ($t eq "pull" and not is_constant($len)) {
pidl "TDR_ALLOC(mem_ctx, v->$e->{NAME}, $len);";
$mem_ctx = "v->$e->{NAME}";
}
pidl "for (i = 0; i < $len; i++) {";
indent;
$array = "[i]";
}
if ($t eq "pull") {
$name = ", $mem_ctx";
}
if (has_property($e, "value") && $t eq "push") {
pidl "v->$e->{NAME} = ".ParseExpr($e->{PROPERTIES}->{value}, $env).";";
}
pidl "TDR_CHECK(tdr_$t\_$e->{TYPE}(tdr$name$switch, &v->$e->{NAME}$array));";
if ($array) { deindent; pidl "}"; }
if (has_property($e, "flag")) {
pidl "tdr->flags = saved_flags;";
deindent;
pidl "}";
}
}
sub ParserStruct($$$$)
{
my ($e,$n,$t,$p) = @_;
pidl static($p)."NTSTATUS tdr_$t\_$n (struct tdr_$t *tdr".typearg($t).", struct $n *v)";
pidl "{"; indent;
pidl "int i;" if (ContainsArray($e));
if ($t eq "print") {
pidl "tdr->print(tdr, \"\%-25s: struct $n\", name);";
pidl "tdr->level++;";
}
my %env = map { $_->{NAME} => "v->$_->{NAME}" } @{$e->{ELEMENTS}};
$env{"this"} = "v";
ParserElement($_, $t, \%env) foreach (@{$e->{ELEMENTS}});
if ($t eq "print") {
pidl "tdr->level--;";
}
pidl "return NT_STATUS_OK;";
deindent; pidl "}";
}
sub ParserUnion($$$$)
{
my ($e,$n,$t,$p) = @_;
pidl static($p)."NTSTATUS tdr_$t\_$n(struct tdr_$t *tdr".typearg($t).", int level, union $n *v)";
pidl "{"; indent;
pidl "int i;" if (ContainsArray($e));
if ($t eq "print") {
pidl "tdr->print(tdr, \"\%-25s: union $n\", name);";
pidl "tdr->level++;";
}
pidl "switch (level) {"; indent;
foreach (@{$e->{ELEMENTS}}) {
if (has_property($_, "case")) {
pidl "case " . $_->{PROPERTIES}->{case} . ":";
} elsif (has_property($_, "default")) {
pidl "default:";
}
indent; ParserElement($_, $t, {}); deindent;
pidl "break;";
}
deindent; pidl "}";
if ($t eq "print") {
pidl "tdr->level--;";
}
pidl "return NT_STATUS_OK;\n";
deindent; pidl "}";
}
sub ParserBitmap($$$$)
{
my ($e,$n,$t,$p) = @_;
return if ($p);
pidl "#define tdr_$t\_$n tdr_$t\_" . Parse::Pidl::Typelist::bitmap_type_fn($e);
}
sub ParserEnum($$$$)
{
my ($e,$n,$t,$p) = @_;
my $bt = ($e->{PROPERTIES}->{base_type} or "uint8");
pidl static($p)."NTSTATUS tdr_$t\_$n (struct tdr_$t *tdr".typearg($t).", enum $n *v)";
pidl "{";
if ($t eq "pull") {
pidl "\t$bt\_t r;";
pidl "\tTDR_CHECK(tdr_$t\_$bt(tdr, mem_ctx, \&r));";
pidl "\t*v = r;";
} elsif ($t eq "push") {
pidl "\tTDR_CHECK(tdr_$t\_$bt(tdr, ($bt\_t *)v));";
} elsif ($t eq "print") {
pidl "\t/* FIXME */";
}
pidl "\treturn NT_STATUS_OK;";
pidl "}";
}
sub ParserTypedef($$)
{
my ($e,$t) = @_;
return if (has_property($e, "no$t"));
$e->{DATA}->{PROPERTIES} = $e->{PROPERTIES};
{ STRUCT => \&ParserStruct, UNION => \&ParserUnion,
ENUM => \&ParserEnum, BITMAP => \&ParserBitmap
}->{$e->{DATA}->{TYPE}}($e->{DATA}, $e->{NAME}, $t, has_property($e, "public"));
pidl "";
}
sub ParserInterface($)
{
my $x = shift;
foreach (@{$x->{DATA}}) {
next if ($_->{TYPE} ne "TYPEDEF");
ParserTypedef($_, "pull");
ParserTypedef($_, "push");
ParserTypedef($_, "print");
}
}
sub Parser($$)
{
my ($idl,$hdrname) = @_;
$ret = "";
pidl "/* autogenerated by pidl */";
pidl "#include \"includes.h\"";
pidl "#include \"$hdrname\"";
pidl "";
foreach (@$idl) { ParserInterface($_) if ($_->{TYPE} eq "INTERFACE"); }
return $ret;
}
sub HeaderInterface($$)
{
my ($x,$outputdir) = @_;
pidl "#ifndef __TDR_$x->{NAME}_HEADER__";
pidl "#define __TDR_$x->{NAME}_HEADER__";
foreach my $e (@{$x->{DATA}}) {
next unless ($e->{TYPE} eq "TYPEDEF");
next unless has_property($e, "public");
my $switch = "";
$switch = ", int level" if ($e->{DATA}->{TYPE} eq "UNION");
if ($e->{DATA}->{TYPE} eq "BITMAP") {
# FIXME
} else {
my ($n, $d) = ($e->{NAME}, lc($e->{DATA}->{TYPE}));
pidl "NTSTATUS tdr_pull\_$n(struct tdr_pull *tdr, TALLOC_CTX *ctx$switch, $d $n *v);";
pidl "NTSTATUS tdr_print\_$n(struct tdr_print *tdr, const char *name$switch, $d $n *v);";
pidl "NTSTATUS tdr_push\_$n(struct tdr_push *tdr$switch, $d $n *v);";
}
pidl "";
}
pidl "#endif /* __TDR_$x->{NAME}_HEADER__ */";
}
sub Header($$$)
{
my ($idl,$outputdir,$basename) = @_;
$ret = "";
pidl "/* Generated by pidl */";
pidl "#include \"$outputdir/$basename.h\"";
pidl "";
foreach (@$idl) {
HeaderInterface($_, $outputdir) if ($_->{TYPE} eq "INTERFACE");
}
return $ret;
}
1;