r16100: Patch from Michael Wood <mwood@icts.uct.ac.za>: s/then/than/ for correct...
[kai/samba.git] / source / pidl / lib / Parse / Pidl / Samba3 / Parser.pm
index 8518537ddb516a30185a5195661ede77344d0bd7..57fa3867f7b8d771a64085a9583f82363e9cb570 100644 (file)
@@ -9,79 +9,200 @@ use strict;
 use Parse::Pidl::Typelist qw(hasType getType mapType);
 use Parse::Pidl::Util qw(has_property ParseExpr);
 use Parse::Pidl::NDR qw(GetPrevLevel GetNextLevel ContainsDeferred);
-use Parse::Pidl::Samba3::Util qw(MapSamba3Type);
+use Parse::Pidl::Samba3::Types qw(DeclShort DeclLong InitType DissectType StringType);
 
 use vars qw($VERSION);
 $VERSION = '0.01';
 
+use constant PRIMITIVES => 1;
+use constant DEFERRED => 2;
+
 my $res = "";
 my $tabs = "";
 sub indent() { $tabs.="\t"; }
 sub deindent() { $tabs = substr($tabs, 1); }
 sub pidl($) { $res .= $tabs.(shift)."\n"; }
-sub fatal($$) { my ($e,$s) = @_; die("$e->{FILE}:$e->{LINE}: $s\n"); }
+sub fatal($$) { my ($e,$s) = @_; die("$e->{ORIGINAL}->{FILE}:$e->{ORIGINAL}->{LINE}: $s\n"); }
+
+#TODO:
+# - Add some security checks (array sizes, memory alloc == NULL, etc)
+# - Don't add seperate _p and _d functions if there is no deferred data
+# - [string] with non-varying arrays and "surrounding" strings 
+# - subcontext()
+# - DATA_BLOB
 
-sub ParseElementLevelData($$$$$)
+sub Align($$)
 {
-       my ($e,$l,$nl,$env,$varname) = @_;
+       my ($a,$b) = @_;
 
-       #FIXME: This only works for scalar types
-       pidl "if (!prs_$l->{DATA_TYPE}(\"$e->{NAME}\", ps, depth, &$varname))";
-       pidl "\treturn False;";
-       pidl "";
+       # Only align if previous element was smaller than current one
+       if ($$a < $b) {
+               pidl "if (!prs_align_custom(ps, $b))";
+               pidl "\treturn False;";
+               pidl "";
+       }
+
+       $$a = $b;
 }
 
-sub ParseElementLevelArray($$$$$)
+sub DeclareArrayVariables
 {
-       my ($e,$l,$nl,$env,$varname) = @_;
+       my $es = shift;
+       my $what = shift;
 
-       #FIXME
-       pidl "for (i=0; i<".ParseExpr("length_$e->{NAME}", $env) .";i++) {";
-       indent;
-       ParseElementLevel($e,$nl,$env,"$varname\[i]");
-       deindent;
-       pidl "}";
+       my $output = 0;
+
+       foreach my $e (@$es) {
+               foreach my $l (@{$e->{LEVELS}}) {
+                       if ($what) {
+                               next if ($l->{IS_DEFERRED} and $what == PRIMITIVES);
+                               next if (not $l->{IS_DEFERRED} and $what == DEFERRED);
+                       }
+                       if ($l->{TYPE} eq "ARRAY" and not $l->{IS_ZERO_TERMINATED}) {
+                               pidl "uint32 i_$e->{NAME}_$l->{LEVEL_INDEX};";
+                               $output = 1;
+                       }
+               }
+       }
+       pidl "" if $output;
 }
 
-sub ParseElementLevelSwitch($$$$$)
+sub ParseElementLevelData($$$$$$$)
 {
-       my ($e,$l,$nl,$env,$varname) = @_;
+       my ($e,$l,$nl,$env,$varname,$what,$align) = @_;
 
-       pidl "if (!prs_uint32(\"level\", ps, depth, " . ParseExpr("level_$e->{NAME}", $env) . ", ps, depth))";
-       pidl "\treturn False;";
-       pidl "";
+       my $c = DissectType($e,$l,$varname,$what,$align);
+       return if not $c;
 
-       ParseElementLevel($e,$nl,$env,$varname);
+       if (defined($e->{ALIGN})) {
+               Align($align, $e->{ALIGN});
+       } else {
+               # Default to 4
+               Align($align, 4);
+       }
+
+       pidl "if (!$c)";
+       pidl "\treturn False;";
 }
 
-sub ParseElementLevelPtr($$$$$)
+sub ParseElementLevelArray($$$$$$$)
 {
-       my ($e,$l,$nl,$env,$varname) = @_;
+       my ($e,$l,$nl,$env,$varname,$what,$align) = @_;
 
-       # No top-level ref pointers for Samba 3
-       return if ($l->{POINTER_TYPE} eq "ref" and $l->{LEVEL} eq "TOP");
+       if ($l->{IS_ZERO_TERMINATED}) {
+               return if ($what == DEFERRED);
+               
+               my ($t,$f) = StringType($e,$l);
 
-       pidl "if (!prs_uint32(\"ptr_$e->{NAME}\",ps,depth,&" . ParseExpr("ptr_$e->{NAME}", $env) . ", ps, depth))";
-       pidl "\treturn False;";
-       pidl "";
+               Align($align, 4);
+               pidl "if (!smb_io_$t(\"$e->{NAME}\", &$varname, 1, ps, depth))";
+               pidl "\treturn False;";
+
+               $$align = 0;
+               return;
+       }
+
+       my $len = ParseExpr($l->{LENGTH_IS}, $env);
+       my $size = ParseExpr($l->{SIZE_IS}, $env);
+
+       if ($what == PRIMITIVES) {
+               # Fetch headers
+               if ($l->{IS_CONFORMANT} and not $l->{IS_SURROUNDING}) {
+                       Align($align, 4);
+                       pidl "if (!prs_uint32(\"size_$e->{NAME}\", ps, depth, &" . ParseExpr("size_$e->{NAME}", $env) . "))";
+                       pidl "\treturn False;";
+                       pidl "";
+               }
        
-       pidl "if (" . ParseExpr("ptr_$e->{NAME}", $env) . ") {";
+               if ($l->{IS_VARYING}) {
+                       Align($align, 4);
+                       pidl "if (!prs_uint32(\"offset_$e->{NAME}\", ps, depth, &" . ParseExpr("offset_$e->{NAME}", $env) . "))";
+                       pidl "\treturn False;";
+                       pidl "";
+
+                       pidl "if (!prs_uint32(\"length_$e->{NAME}\", ps, depth, &" . ParseExpr("length_$e->{NAME}", $env) . "))";
+                       pidl "\treturn False;";
+                       pidl "";
+               }
+       }
+
+       # Everything but fixed arrays have to be allocated
+       if (!$l->{IS_FIXED} and $what == PRIMITIVES) {
+               pidl "if (UNMARSHALLING(ps)) {";
+               indent;
+               pidl "$varname = (void *)PRS_ALLOC_MEM_VOID(ps,sizeof(*$varname)*$size);";
+               deindent;
+               pidl "}";
+       }
+
+       return if ($what == DEFERRED and not ContainsDeferred($e,$l));
+
+       my $i = "i_$e->{NAME}_$l->{LEVEL_INDEX}";
+       pidl "for ($i=0; $i<$len;$i++) {";
        indent;
-       ParseElementLevel($e,$nl,$env,$varname);
+       ParseElementLevel($e,$nl,$env,$varname."[$i]",$what,$align);
        deindent;
        pidl "}";
 }
 
-sub ParseElementLevelSubcontext($$$$$)
+sub ParseElementLevelSwitch($$$$$$$)
+{
+       my ($e,$l,$nl,$env,$varname,$what,$align) = @_;
+
+       ParseElementLevel($e,$nl,$env,$varname,$what,$align);
+}
+
+sub ParseElementLevelPtr($$$$$$$)
 {
-       my ($e,$l,$nl,$env,$varname) = @_;
+       my ($e,$l,$nl,$env,$varname,$what,$align) = @_;
+
+       if ($what == PRIMITIVES) {
+               if (($l->{POINTER_TYPE} eq "ref") and ($l->{LEVEL} eq "EMBEDDED")) {
+                       # Ref pointers always have to be non-NULL
+                       pidl "if (MARSHALLING(ps) && !" . ParseExpr("ptr$l->{POINTER_INDEX}_$e->{NAME}", $env) . ")";
+                       pidl "\treturn False;";
+                       pidl "";
+               } 
+               
+               unless ($l->{POINTER_TYPE} eq "ref" and $l->{LEVEL} eq "TOP") {
+                       Align($align, 4);
+                       pidl "if (!prs_uint32(\"ptr$l->{POINTER_INDEX}_$e->{NAME}\", ps, depth, &" . ParseExpr("ptr$l->{POINTER_INDEX}_$e->{NAME}", $env) . "))";
+                       pidl "\treturn False;";
+                       pidl "";
+               }
+       }
+
+       if ($l->{POINTER_TYPE} eq "relative") {
+               fatal($e, "relative pointers not supported for Samba 3");
+               #FIXME
+       }
+       
+       if ($what == DEFERRED) {
+               if ($l->{POINTER_TYPE} ne "ref") {
+                       pidl "if (" . ParseExpr("ptr$l->{POINTER_INDEX}_$e->{NAME}", $env) . ") {";
+                       indent;
+               }
+               ParseElementLevel($e,$nl,$env,$varname,PRIMITIVES,$align);
+               ParseElementLevel($e,$nl,$env,$varname,DEFERRED,$align);
+               if ($l->{POINTER_TYPE} ne "ref") {
+                       deindent;
+                       pidl "}";
+               }
+               $$align = 0;
+       }
+}
+
+sub ParseElementLevelSubcontext($$$$$$$)
+{
+       my ($e,$l,$nl,$env,$varname,$what,$align) = @_;
 
        fatal($e, "subcontext() not supported for Samba 3");
+       #FIXME
 }
 
-sub ParseElementLevel($$$$)
+sub ParseElementLevel($$$$$$)
 {
-       my ($e,$l,$env,$varname) = @_;
+       my ($e,$l,$env,$varname,$what,$align) = @_;
 
        {
                DATA => \&ParseElementLevelData,
@@ -89,81 +210,176 @@ sub ParseElementLevel($$$$)
                POINTER => \&ParseElementLevelPtr,
                SWITCH => \&ParseElementLevelSwitch,
                ARRAY => \&ParseElementLevelArray
-       }->{$l->{TYPE}}->($e,$l,GetNextLevel($e,$l),$env,$varname);
+       }->{$l->{TYPE}}->($e,$l,GetNextLevel($e,$l),$env,$varname,$what,$align);
 }
 
-sub ParseElement($$)
+sub ParseElement($$$$)
 {
-       my ($e,$env) = @_;
+       my ($e,$env,$what,$align) = @_;
+
+       ParseElementLevel($e, $e->{LEVELS}[0], $env, ParseExpr($e->{NAME}, $env), $what, $align);
+}
 
-       ParseElementLevel($e, $e->{LEVELS}[0], $env, ParseExpr($e->{NAME}, $env));
+sub InitLevel($$$$)
+{
+       sub InitLevel($$$$);
+       my ($e,$l,$varname,$env) = @_;
+
+       if ($l->{TYPE} eq "POINTER") {
+               if ($l->{POINTER_TYPE} eq "ref") {
+                       pidl "if (!$varname)";
+                       pidl "\treturn False;";
+                       pidl "";
+               } else {
+                       pidl "if ($varname) {";
+                       indent;
+               }
+
+               unless ($l->{POINTER_TYPE} eq "ref" and $l->{LEVEL} eq "TOP") {
+                       pidl ParseExpr("ptr$l->{POINTER_INDEX}_$e->{NAME}", $env) . " = 1;";
+               }
+               InitLevel($e, GetNextLevel($e,$l), "*$varname", $env);
+               
+               if ($l->{POINTER_TYPE} ne "ref") {
+                       deindent;
+                       pidl "} else {";
+                       pidl "\t" . ParseExpr("ptr$l->{POINTER_INDEX}_$e->{NAME}", $env) . " = 0;";
+                       pidl "}";
+               }
+       } elsif ($l->{TYPE} eq "ARRAY" and $l->{IS_ZERO_TERMINATED}) {
+               my ($t,$f) = StringType($e,$l);
+               pidl "init_$t(&" . ParseExpr($e->{NAME}, $env) . ", ".substr($varname, 1) . ", $f);"; 
+       } elsif ($l->{TYPE} eq "ARRAY") {
+               pidl ParseExpr($e->{NAME}, $env) . " = $varname;";
+       } elsif ($l->{TYPE} eq "DATA") {
+               pidl InitType($e, $l, ParseExpr($e->{NAME}, $env), $varname);
+       } elsif ($l->{TYPE} eq "SWITCH") {
+               InitLevel($e, GetNextLevel($e,$l), $varname, $env);
+               pidl ParseExpr($e->{NAME}, $env) . ".switch_value = " . ParseExpr($l->{SWITCH_IS}, $env) . ";";
+       }
+}
+
+sub GenerateEnvElement($$)
+{
+       my ($e,$env) = @_;
+       foreach my $l (@{$e->{LEVELS}}) {
+               if ($l->{TYPE} eq "DATA") {
+                       $env->{$e->{NAME}} = "v->$e->{NAME}";
+               } elsif ($l->{TYPE} eq "POINTER") {
+                       $env->{"ptr$l->{POINTER_INDEX}_$e->{NAME}"} = "v->ptr$l->{POINTER_INDEX}_$e->{NAME}";
+               } elsif ($l->{TYPE} eq "SWITCH") {
+               } elsif ($l->{TYPE} eq "ARRAY" and not $l->{IS_ZERO_TERMINATED}) {
+                       $env->{"length_$e->{NAME}"} = "v->length_$e->{NAME}";
+                       $env->{"size_$e->{NAME}"} = "v->size_$e->{NAME}";
+                       $env->{"offset_$e->{NAME}"} = "v->offset_$e->{NAME}";
+               }
+       }
 }
 
-sub CreateStruct($$$)
+sub ParseStruct($$$)
 {
-       my ($fn,$s,$es) = @_;
+       my ($if,$s,$n) = @_;
+
+       my $fn = "$if->{NAME}_io_$n";
+       my $sn = uc("$if->{NAME}_$n");
+       my $ifn = "init_$if->{NAME}_$n";
 
        my $args = "";
-       foreach my $e (@$es) {
-               $args .= ", " . MapSamba3Type($_);
+       foreach (@{$s->{ELEMENTS}}) {
+               $args .= ", " . DeclLong($_);
        }
 
-       pidl "BOOL init_$fn($s *v$args)";
+       my $env = { "this" => "v" };
+       GenerateEnvElement($_, $env) foreach (@{$s->{ELEMENTS}});
+
+       pidl "BOOL $ifn($sn *v$args)";
        pidl "{";
        indent;
-       pidl "DEBUG(5,(\"init_$fn\\n\"));";
+       pidl "DEBUG(5,(\"$ifn\\n\"));";
+       pidl "";
        # Call init for all arguments
-       foreach my $e (@$es) {
-               foreach my $l (@{$e->{LEVELS}}) {
-                       #FIXME
-               }
+       foreach (@{$s->{ELEMENTS}}) {
+               InitLevel($_, $_->{LEVELS}[0], $_->{NAME}, $env);
+               pidl "";
        }
        pidl "return True;";
        deindent;
        pidl "}";
        pidl "";
+
+       my $pfn = "$fn\_p";
+       my $dfn = "$fn\_d";
        
-       pidl "BOOL $fn(const char *desc, $s *v, prs_struct *ps, int depth)";
+       pidl "BOOL $pfn(const char *desc, $sn *v, prs_struct *ps, int depth)";
        pidl "{";
        indent;
+       DeclareArrayVariables($s->{ELEMENTS}, PRIMITIVES);
        pidl "if (v == NULL)";
        pidl "\treturn False;";
        pidl "";
-       pidl "prs_debug(ps, depth, desc, \"$fn\");";
+       pidl "prs_debug(ps, depth, desc, \"$pfn\");";
        pidl "depth++;";
-       pidl "if (!prs_align(ps))";
+
+       my $align = 8;
+       if ($s->{SURROUNDING_ELEMENT}) {
+               pidl "if (!prs_uint32(\"size_$s->{SURROUNDING_ELEMENT}->{NAME}\", ps, depth, &" . ParseExpr("size_$s->{SURROUNDING_ELEMENT}->{NAME}", $env) . "))";
+               pidl "\treturn False;";
+               pidl "";
+               $align = 4;
+               
+       }
+
+       foreach (@{$s->{ELEMENTS}}) {
+               ParseElement($_, $env, PRIMITIVES, \$align); 
+               pidl "";
+       }
+
+       pidl "return True;";
+       deindent;
+       pidl "}";
+       pidl "";
+
+       pidl "BOOL $dfn(const char *desc, $sn *v, prs_struct *ps, int depth)";
+       pidl "{";
+       indent;
+       DeclareArrayVariables($s->{ELEMENTS}, DEFERRED);
+       pidl "if (v == NULL)";
        pidl "\treturn False;";
        pidl "";
+       pidl "prs_debug(ps, depth, desc, \"$dfn\");";
+       pidl "depth++;";
 
-       my $env = {};
-       foreach my $e (@$es) {
-               foreach my $l (@{$e->{LEVELS}}) {
-                       if ($l->{TYPE} eq "DATA") {
-                               $env->{"$e->{NAME}"} = $e->{"v->$e->{NAME}"};
-                       } elsif ($l->{TYPE} eq "POINTER") {
-                               $env->{"ptr_$e->{NAME}"} = $e->{"v->ptr_$e->{NAME}"};
-                       } elsif ($l->{TYPE} eq "SWITCH") {
-                               $env->{"level_$e->{NAME}"} = $e->{"v->level_$e->{NAME}"};
-                       } 
-               }
+       $align = 0;
+       foreach (@{$s->{ELEMENTS}}) {
+               ParseElement($_, $env, DEFERRED, \$align); 
+               pidl "";
        }
 
-       ParseElement($_, $env) foreach (@$es);
-
        pidl "return True;";
        deindent;
        pidl "}";
        pidl "";
 }
 
-sub ParseStruct($$$)
+sub UnionGenerateEnvElement($)
 {
-       my ($if,$s,$n) = @_;
+       my $e = shift;
+       my $env = {};
 
-       my $fn = "$if->{NAME}_io_$n";
-       my $sn = uc("$if->{NAME}_$n");
+       foreach my $l (@{$e->{LEVELS}}) {
+               if ($l->{TYPE} eq "DATA") {
+                       $env->{$e->{NAME}} = "v->u.$e->{NAME}";
+               } elsif ($l->{TYPE} eq "POINTER") {
+                       $env->{"ptr$l->{POINTER_INDEX}_$e->{NAME}"} = "v->ptr$l->{POINTER_INDEX}";
+               } elsif ($l->{TYPE} eq "SWITCH") {
+               } elsif ($l->{TYPE} eq "ARRAY" and not $l->{IS_ZERO_TERMINATED}) {
+                       $env->{"length_$e->{NAME}"} = "v->length";
+                       $env->{"size_$e->{NAME}"} = "v->size";
+                       $env->{"offset_$e->{NAME}"} = "v->offset";
+               }
+       }
 
-       CreateStruct($fn, $sn, $s->{ELEMENTS});
+       return $env;
 }
 
 sub ParseUnion($$$)
@@ -171,22 +387,46 @@ sub ParseUnion($$$)
        my ($if,$u,$n) = @_;
 
        my $fn = "$if->{NAME}_io_$n";
-       my $sn = uc("$if->{NAME}_$n");
+       my $sn = uc("$if->{NAME}_$n\_ctr");
 
-       pidl "BOOL $fn(const char *desc, $sn* v, uint32 level, prs_struct *ps, int depth)";
+       my $pfn = "$fn\_p";
+       my $dfn = "$fn\_d";
+       
+       pidl "BOOL $pfn(const char *desc, $sn* v, prs_struct *ps, int depth)";
        pidl "{";
        indent;
-       pidl "switch (level) {";
+       DeclareArrayVariables($u->{ELEMENTS});
+
+       if (defined ($u->{SWITCH_TYPE})) {
+               pidl "if (!prs_$u->{SWITCH_TYPE}(\"switch_value\", ps, depth, &v->switch_value))";
+               pidl "\treturn False;";
+               pidl "";
+       }
+
+       # Maybe check here that level and v->switch_value are equal?
+
+       pidl "switch (v->switch_value) {";
        indent;
 
        foreach (@{$u->{ELEMENTS}}) {
                pidl "$_->{CASE}:";
                indent;
-               pidl "depth++;";
-               ParseElement($_, {});
+               if ($_->{TYPE} ne "EMPTY") {
+                       pidl "depth++;";
+                       my $env = UnionGenerateEnvElement($_);
+                       my $align = 8;
+                       ParseElement($_, $env, PRIMITIVES, \$align); 
+                       pidl "depth--;";
+               }
+               pidl "break;";
                deindent;
-               pidl "depth--;";
-               pidl "break";
+               pidl "";
+       }
+
+       unless ($u->{HAS_DEFAULT}) {
+               pidl "default:";
+               pidl "\treturn False;";
+               pidl "";
        }
 
        deindent;
@@ -195,6 +435,90 @@ sub ParseUnion($$$)
        pidl "return True;";
        deindent;
        pidl "}";
+       pidl "";
+
+       pidl "BOOL $dfn(const char *desc, $sn* v, prs_struct *ps, int depth)";
+       pidl "{";
+       indent;
+       DeclareArrayVariables($u->{ELEMENTS});
+
+       if (defined($u->{SWITCH_TYPE})) {
+               pidl "switch (v->switch_value) {";
+       } else {
+               pidl "switch (level) {";
+       }
+       indent;
+
+       foreach (@{$u->{ELEMENTS}}) {
+               pidl "$_->{CASE}:";
+               indent;
+               if ($_->{TYPE} ne "EMPTY") {
+                       pidl "depth++;";
+                       my $env = UnionGenerateEnvElement($_);
+                       my $align = 0;
+                       ParseElement($_, $env, DEFERRED, \$align); 
+                       pidl "depth--;";
+               }
+               pidl "break;";
+               deindent;
+               pidl "";
+       }
+
+       deindent;
+       pidl "}";
+       pidl "";
+       pidl "return True;";
+       deindent;
+       pidl "}";
+
+}
+
+sub CreateFnDirection($$$$$)
+{
+       my ($fn,$ifn,$s,$all,$es) = @_;
+
+       my $args = "";
+       foreach (@$all) { $args .= ", " . DeclLong($_); }
+
+       my $env = { };
+       GenerateEnvElement($_, $env) foreach (@$es);
+
+       pidl "BOOL $ifn($s *v$args)";
+       pidl "{";
+       indent;
+       pidl "DEBUG(5,(\"$ifn\\n\"));";
+       pidl "";
+       # Call init for all arguments
+       foreach (@$es) {
+               InitLevel($_, $_->{LEVELS}[0], $_->{NAME}, $env);
+               pidl "";
+       }
+       pidl "return True;";
+       deindent;
+       pidl "}";
+       pidl "";
+       
+       pidl "BOOL $fn(const char *desc, $s *v, prs_struct *ps, int depth)";
+       pidl "{";
+       indent;
+       DeclareArrayVariables($es);
+       pidl "if (v == NULL)";
+       pidl "\treturn False;";
+       pidl "";
+       pidl "prs_debug(ps, depth, desc, \"$fn\");";
+       pidl "depth++;";
+
+       my $align = 8;
+       foreach (@$es) {
+               ParseElement($_, $env, PRIMITIVES, \$align); 
+               ParseElement($_, $env, DEFERRED, \$align); 
+               pidl "";
+       }
+
+       pidl "return True;";
+       deindent;
+       pidl "}";
+       pidl "";
 }
 
 sub ParseFunction($$)
@@ -203,6 +527,7 @@ sub ParseFunction($$)
 
        my @in = ();
        my @out = ();
+       my @all = @{$fn->{ELEMENTS}};
 
        foreach (@{$fn->{ELEMENTS}}) {
                push (@in, $_) if (grep(/in/, @{$_->{DIRECTION}}));
@@ -210,7 +535,7 @@ sub ParseFunction($$)
        }
 
        if (defined($fn->{RETURN_TYPE})) {
-               push (@out, { 
+               my $status = { 
                        NAME => "status", 
                        TYPE => $fn->{RETURN_TYPE},
                        LEVELS => [
@@ -219,11 +544,20 @@ sub ParseFunction($$)
                                        DATA_TYPE => $fn->{RETURN_TYPE}
                                }
                        ]
-               } );
+               };
+
+               push (@out, $status);
+               push (@all, $status);
        }
 
-       CreateStruct("$if->{NAME}_io_q_$fn->{NAME}", uc("$if->{NAME}_q_$fn->{NAME}"), \@in);
-       CreateStruct("$if->{NAME}_io_r_$fn->{NAME}", uc("$if->{NAME}_r_$fn->{NAME}"), \@out);
+       CreateFnDirection("$if->{NAME}_io_q_$fn->{NAME}", 
+                                "init_$if->{NAME}_q_$fn->{NAME}", 
+                                uc("$if->{NAME}_q_$fn->{NAME}"), 
+                                \@in, \@in);
+       CreateFnDirection("$if->{NAME}_io_r_$fn->{NAME}", 
+                                "init_$if->{NAME}_r_$fn->{NAME}",
+                                uc("$if->{NAME}_r_$fn->{NAME}"), 
+                                \@all, \@out);
 }
 
 sub ParseInterface($)
@@ -232,9 +566,9 @@ sub ParseInterface($)
 
        # Structures first 
        pidl "/* $if->{NAME} structures */";
-       foreach (@{$if->{TYPEDEFS}}) {
-               ParseStruct($if, $_->{DATA}, $_->{NAME}) if ($_->{TYPE} eq "STRUCT");
-               ParseUnion($if, $_->{DATA}, $_->{NAME}) if ($_->{TYPE} eq "UNION");
+       foreach (@{$if->{TYPES}}) {
+               ParseStruct($if, $_->{DATA}, $_->{NAME}) if ($_->{DATA}->{TYPE} eq "STRUCT");
+               ParseUnion($if, $_->{DATA}, $_->{NAME}) if ($_->{DATA}->{TYPE} eq "UNION");
        }
 
        pidl "/* $if->{NAME} functions */";