[5/5] widl: Remove var_t's ptr_level field and start write_pointers

Dan Hipschman dsh at linux.ucla.edu
Wed May 9 22:50:49 CDT 2007


This patch finally takes the ptr_level field out of the var_t struct.  This
field was always a bad idea, conceptually because pointer info belongs in
the type_t structure, and in practice because none of the ptr_level code
generalizes to typedef'd types.  It also made dealing with pointers a major
headache since there was always two ways to repesent pointers, and you always
had to think about both of them.

This also begins an implementation of write_pointers, which generates the
type format string for pointers in structures and arrays.  It's the first
error encountered when compiling oaidl.idl.  The reason I put both of these
in a single patch is that when I originally took out ptr_level, a lot of
stuff was still broken, and I didn't realize it until I started writing
write_pointers.  I had to go back and tweak the ptr_level patch, and now
it's a bit of a chore to separate them again, whereas this patch is already
tested and working.  It also includes new tests which pass on wine and XP.

---
 dlls/rpcrt4/tests/server.c   |   40 ++++
 dlls/rpcrt4/tests/server.idl |   18 ++
 tools/widl/client.c          |   12 +-
 tools/widl/header.c          |   81 ++++----
 tools/widl/header.h          |   22 ++-
 tools/widl/parser.y          |  126 +++++++----
 tools/widl/proxy.c           |   17 +-
 tools/widl/server.c          |    4 +-
 tools/widl/typegen.c         |  534 ++++++++++++++++++++++--------------------
 tools/widl/typegen.h         |    2 +-
 tools/widl/widltypes.h       |   12 +-
 tools/widl/write_msft.c      |   30 ++--
 12 files changed, 521 insertions(+), 377 deletions(-)

diff --git a/dlls/rpcrt4/tests/server.c b/dlls/rpcrt4/tests/server.c
index 51c570e..0086b97 100644
--- a/dlls/rpcrt4/tests/server.c
+++ b/dlls/rpcrt4/tests/server.c
@@ -114,6 +114,18 @@ s_sum_fixed_array(int a[5])
   return a[0] + a[1] + a[2] + a[3] + a[4];
 }
 
+int
+s_pints_sum(pints_t *pints)
+{
+  return *pints->pi + **pints->ppi + ***pints->pppi;
+}
+
+double
+s_ptypes_sum(ptypes_t *pt)
+{
+  return *pt->pc + *pt->ps + *pt->pl + *pt->pf + *pt->pd;
+}
+
 void
 s_stop(void)
 {
@@ -155,9 +167,14 @@ basic_tests(void)
   static char string[] = "I am a string";
   static int f[5] = {1, 3, 0, -2, -4};
   static vector_t a = {1, 3, 7};
+  pints_t pints;
+  ptypes_t ptypes;
+  int i1, i2, i3, *pi2, *pi3, **ppi3;
   double u, v;
   float s, t;
   long q, r;
+  short h;
+  char c;
   int x;
 
   ok(int_return() == INT_CODE, "RPC int_return\n");
@@ -191,6 +208,29 @@ basic_tests(void)
   ok(q == 9, "RPC square_half_long\n");
   ok(r == 1, "RPC square_half_long\n");
 
+  i1 = 19;
+  i2 = -3;
+  i3 = -29;
+  pi2 = &i2;
+  pi3 = &i3;
+  ppi3 = &pi3;
+  pints.pi = &i1;
+  pints.ppi = &pi2;
+  pints.pppi = &ppi3;
+  ok(pints_sum(&pints) == -13, "RPC pints_sum\n");
+
+  c = 10;
+  h = 3;
+  q = 14;
+  s = -5.0f;
+  u = 11.0;
+  ptypes.pc = &c;
+  ptypes.ps = &h;
+  ptypes.pl = &q;
+  ptypes.pf = &s;
+  ptypes.pd = &u;
+  ok(ptypes_sum(&ptypes) == 33.0, "RPC ptypes_sum\n");
+
   ok(sum_fixed_array(f) == -2, "RPC sum_fixed_array\n");
 }
 
diff --git a/dlls/rpcrt4/tests/server.idl b/dlls/rpcrt4/tests/server.idl
index c122870..4830e8c 100644
--- a/dlls/rpcrt4/tests/server.idl
+++ b/dlls/rpcrt4/tests/server.idl
@@ -31,6 +31,22 @@ typedef struct tag_vector
 ]
 interface IServer
 {
+  typedef struct
+  {
+    int *pi;
+    int **ppi;
+    int ***pppi;
+  } pints_t;
+
+  typedef struct
+  {
+    char *pc;
+    short *ps;
+    long *pl;
+    float *pf;
+    double *pd;
+  } ptypes_t;
+
   int int_return(void);
   int square(int x);
   int sum(int x, int y);
@@ -42,5 +58,7 @@ interface IServer
   float square_half_float(float x, [out] float *y);
   long square_half_long(long x, [out] long *y);
   int sum_fixed_array(int a[5]);
+  int pints_sum(pints_t *pints);
+  double ptypes_sum(ptypes_t *ptypes);
   void stop(void);
 }
diff --git a/tools/widl/client.c b/tools/widl/client.c
index 1652a3f..45747cf 100644
--- a/tools/widl/client.c
+++ b/tools/widl/client.c
@@ -116,7 +116,7 @@ static void write_function_stubs(type_t *iface, unsigned int *proc_offset, unsig
             }
         }
 
-        write_type(client, def->type, def);
+        write_type(client, def->type);
         fprintf(client, " ");
         write_prefix_name(client, prefix_client, def);
         fprintf(client, "(\n");
@@ -133,10 +133,10 @@ static void write_function_stubs(type_t *iface, unsigned int *proc_offset, unsig
         indent++;
 
         /* declare return value '_RetVal' */
-        if (!is_void(def->type, NULL))
+        if (!is_void(def->type))
         {
             print_client("");
-            write_type(client, def->type, def);
+            write_type(client, def->type);
             fprintf(client, " _RetVal;\n");
         }
 
@@ -226,7 +226,7 @@ static void write_function_stubs(type_t *iface, unsigned int *proc_offset, unsig
         write_remoting_arguments(client, indent, func, type_offset, PASS_OUT, PHASE_UNMARSHAL);
 
         /* unmarshal return value */
-        if (!is_void(def->type, NULL))
+        if (!is_void(def->type))
             print_phase_basetype(client, indent, PHASE_UNMARSHAL, PASS_RETURN, def, "_RetVal");
 
         /* update proc_offset */
@@ -235,7 +235,7 @@ static void write_function_stubs(type_t *iface, unsigned int *proc_offset, unsig
             LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
                 *proc_offset += get_size_procformatstring_var(var);
         }
-        if (!is_void(def->type, NULL))
+        if (!is_void(def->type))
             *proc_offset += get_size_procformatstring_var(def);
         else
             *proc_offset += 2; /* FC_END and FC_PAD */
@@ -257,7 +257,7 @@ static void write_function_stubs(type_t *iface, unsigned int *proc_offset, unsig
 
 
         /* emit return code */
-        if (!is_void(def->type, NULL))
+        if (!is_void(def->type))
         {
             fprintf(client, "\n");
             print_client("return _RetVal;\n");
diff --git a/tools/widl/header.c b/tools/widl/header.c
index 24ce8a0..4f5b6b5 100644
--- a/tools/widl/header.c
+++ b/tools/widl/header.c
@@ -46,6 +46,26 @@ static void indent(FILE *h, int delta)
   if (delta > 0) indentation += delta;
 }
 
+int is_ptrchain_attr(const var_t *var, enum attr_type t)
+{
+    if (is_attr(var->attrs, t))
+        return 1;
+    else
+    {
+        type_t *type = var->type;
+        for (;;)
+        {
+            if (is_attr(type->attrs, t))
+                return 1;
+            else if (type->kind == TKIND_ALIAS)
+                type = type->orig;
+            else if (is_ptr(type))
+                type = type->ref;
+            else return 0;
+        }
+    }
+}
+
 int is_attr(const attr_list_t *list, enum attr_type t)
 {
     const attr_t *attr;
@@ -70,9 +90,8 @@ unsigned long get_attrv(const attr_list_t *list, enum attr_type t)
     return 0;
 }
 
-int is_void(const type_t *t, const var_t *v)
+int is_void(const type_t *t)
 {
-  if (v && v->ptr_level) return 0;
   if (!t->type && !t->ref) return 1;
   return 0;
 }
@@ -105,15 +124,6 @@ void write_guid(FILE *f, const char *guid_prefix, const char *name, const UUID *
         uuid->Data4[6], uuid->Data4[7]);
 }
 
-static void write_pident(FILE *h, const var_t *v)
-{
-  int c;
-  for (c=0; c<v->ptr_level; c++) {
-    fprintf(h, "*");
-  }
-  if (v->name) fprintf(h, "%s", v->name);
-}
-
 void write_name(FILE *h, const var_t *v)
 {
   if (is_attr( v->attrs, ATTR_PROPGET ))
@@ -159,11 +169,9 @@ static void write_field(FILE *h, var_t *v)
   if (!v) return;
   if (v->type) {
     indent(h, 0);
-    write_type(h, v->type, NULL);
-    if (get_name(v)) {
-      fprintf(h, " ");
-      write_pident(h, v);
-    }
+    write_type(h, v->type);
+    if (get_name(v))
+      fprintf(h, " %s", v->name);
     else {
       /* not all C/C++ compilers support anonymous structs and unions */
       switch (v->type->type) {
@@ -220,10 +228,8 @@ static int needs_space_after(type_t *t)
   return t->kind == TKIND_ALIAS || ! is_ptr(t);
 }
 
-void write_type(FILE *h, type_t *t, const var_t *v)
+void write_type(FILE *h, type_t *t)
 {
-  int c;
-
   if (t->is_const) fprintf(h, "const ");
 
   if (t->kind == TKIND_ALIAS) fprintf(h, "%s", t->name);
@@ -278,18 +284,13 @@ void write_type(FILE *h, type_t *t, const var_t *v)
       case RPC_FC_UP:
       case RPC_FC_FP:
       case RPC_FC_OP:
-        if (t->ref) write_type(h, t->ref, NULL);
+        if (t->ref) write_type(h, t->ref);
         fprintf(h, "%s*", needs_space_after(t->ref) ? " " : "");
         break;
       default:
         fprintf(h, "%s", t->name);
     }
   }
-  if (v) {
-    for (c=0; c<v->ptr_level; c++) {
-      fprintf(h, "*");
-    }
-  }
 }
 
 
@@ -358,7 +359,7 @@ void write_user_types(void)
 void write_typedef(type_t *type)
 {
   fprintf(header, "typedef ");
-  write_type(header, type->orig, NULL);
+  write_type(header, type->orig);
   fprintf(header, "%s%s;\n", needs_space_after(type->orig) ? " " : "", type->name);
 }
 
@@ -396,13 +397,13 @@ void write_expr(FILE *h, const expr_t *e, int brackets)
     break;
   case EXPR_CAST:
     fprintf(h, "(");
-    write_type(h, e->u.tref, NULL);
+    write_type(h, e->u.tref);
     fprintf(h, ")");
     write_expr(h, e->ref, 1);
     break;
   case EXPR_SIZEOF:
     fprintf(h, "sizeof(");
-    write_type(h, e->u.tref, NULL);
+    write_type(h, e->u.tref);
     fprintf(h, ")");
     break;
   case EXPR_SHL:
@@ -451,11 +452,9 @@ void write_constdef(const var_t *v)
 void write_externdef(const var_t *v)
 {
   fprintf(header, "extern const ");
-  write_type(header, v->type, NULL);
-  if (get_name(v)) {
-    fprintf(header, " ");
-    write_pident(header, v);
-  }
+  write_type(header, v->type);
+  if (get_name(v))
+    fprintf(header, " %s", v->name);
   fprintf(header, ";\n\n");
 }
 
@@ -486,7 +485,7 @@ int has_out_arg_or_return(const func_t *func)
 {
     const var_t *var;
 
-    if (!is_void(func->def->type, NULL))
+    if (!is_void(func->def->type))
         return 1;
 
     if (!func->args)
@@ -579,7 +578,7 @@ void write_args(FILE *h, const var_list_t *args, const char *name, int method, i
         }
         else fprintf(h, ",");
     }
-    write_type(h, arg->type, arg);
+    write_type(h, arg->type);
     if (arg->args)
     {
       fprintf(h, " (STDMETHODCALLTYPE *");
@@ -612,7 +611,7 @@ static void write_cpp_method_def(const type_t *iface)
     if (!is_callas(def->attrs)) {
       indent(header, 0);
       fprintf(header, "virtual ");
-      write_type(header, def->type, def);
+      write_type(header, def->type);
       fprintf(header, " STDMETHODCALLTYPE ");
       write_name(header, def);
       fprintf(header, "(\n");
@@ -637,7 +636,7 @@ static void do_write_c_method_def(const type_t *iface, const char *name)
     const var_t *def = cur->def;
     if (!is_callas(def->attrs)) {
       indent(header, 0);
-      write_type(header, def->type, def);
+      write_type(header, def->type);
       fprintf(header, " (STDMETHODCALLTYPE *");
       write_name(header, def);
       fprintf(header, ")(\n");
@@ -670,7 +669,7 @@ static void write_method_proto(const type_t *iface)
 
     if (!is_local(def->attrs)) {
       /* proxy prototype */
-      write_type(header, def->type, def);
+      write_type(header, def->type);
       fprintf(header, " CALLBACK %s_", iface->name);
       write_name(header, def);
       fprintf(header, "_Proxy(\n");
@@ -693,14 +692,14 @@ static void write_method_proto(const type_t *iface)
       if (&m->entry != iface->funcs) {
         const var_t *mdef = m->def;
         /* proxy prototype - use local prototype */
-        write_type(header, mdef->type, mdef);
+        write_type(header, mdef->type);
         fprintf(header, " CALLBACK %s_", iface->name);
         write_name(header, mdef);
         fprintf(header, "_Proxy(\n");
         write_args(header, m->args, iface->name, 1, TRUE);
         fprintf(header, ");\n");
         /* stub prototype - use remotable prototype */
-        write_type(header, def->type, def);
+        write_type(header, def->type);
         fprintf(header, " __RPC_STUB %s_", iface->name);
         write_name(header, mdef);
         fprintf(header, "_Stub(\n");
@@ -719,7 +718,7 @@ static void write_function_proto(const type_t *iface, const func_t *fun, const c
   var_t *def = fun->def;
 
   /* FIXME: do we need to handle call_as? */
-  write_type(header, def->type, def);
+  write_type(header, def->type);
   fprintf(header, " ");
   write_prefix_name(header, prefix, def);
   fprintf(header, "(\n");
diff --git a/tools/widl/header.h b/tools/widl/header.h
index 4de1026..57ae6b4 100644
--- a/tools/widl/header.h
+++ b/tools/widl/header.h
@@ -21,16 +21,19 @@
 #ifndef __WIDL_HEADER_H
 #define __WIDL_HEADER_H
 
+#include "widltypes.h"
+
+extern int is_ptrchain_attr(const var_t *var, enum attr_type t);
 extern int is_attr(const attr_list_t *list, enum attr_type t);
 extern void *get_attrp(const attr_list_t *list, enum attr_type t);
 extern unsigned long get_attrv(const attr_list_t *list, enum attr_type t);
-extern int is_void(const type_t *t, const var_t *v);
+extern int is_void(const type_t *t);
 extern int is_conformant_array( const array_dims_t *array );
 extern int is_non_void(const expr_list_t *list);
 extern void write_name(FILE *h, const var_t *v);
 extern void write_prefix_name(FILE *h, const char *prefix, const var_t *v);
 extern const char* get_name(const var_t *v);
-extern void write_type(FILE *h, type_t *t, const var_t *v);
+extern void write_type(FILE *h, type_t *t);
 extern int is_object(const attr_list_t *list);
 extern int is_local(const attr_list_t *list);
 extern const var_t *is_callas(const attr_list_t *list);
@@ -52,16 +55,21 @@ extern int has_out_arg_or_return(const func_t *func);
 extern void write_guid(FILE *f, const char *guid_prefix, const char *name,
                        const UUID *uuid);
 
-static inline int is_string_type(const attr_list_t *attrs, int ptr_level, const array_dims_t *array)
+static inline int last_ptr(const type_t *type)
+{
+    return is_ptr(type) && !is_ptr(type->ref);
+}
+
+static inline int is_string_type(const attr_list_t *attrs, const type_t *type, const array_dims_t *array)
 {
     return (is_attr(attrs, ATTR_STRING) &&
-            ((ptr_level == 1 && !array) || (ptr_level == 0 && array)));
+            ((last_ptr(type) && !array) || (!is_ptr(type) && array)));
 }
 
-static inline int is_array_type(const attr_list_t *attrs, int ptr_level, const array_dims_t *array)
+static inline int is_array_type(const attr_list_t *attrs, const type_t *type, const array_dims_t *array)
 {
-    return ((ptr_level == 1 && !array && is_attr(attrs, ATTR_SIZEIS)) ||
-            (ptr_level == 0 && array));
+    return ((last_ptr(type) && !array && is_attr(attrs, ATTR_SIZEIS)) ||
+            (!is_ptr(type) && array));
 }
 
 #endif
diff --git a/tools/widl/parser.y b/tools/widl/parser.y
index b2f4691..a74aab1 100644
--- a/tools/widl/parser.y
+++ b/tools/widl/parser.y
@@ -79,11 +79,13 @@ static expr_t *make_expr3(enum expr_type type, expr_t *expr1, expr_t *expr2, exp
 static type_t *make_type(unsigned char type, type_t *ref);
 static expr_list_t *append_expr(expr_list_t *list, expr_t *expr);
 static array_dims_t *append_array(array_dims_t *list, expr_t *expr);
-static void set_type(var_t *v, type_t *type, array_dims_t *arr);
+static void set_type(var_t *v, type_t *type, int ptr_level, array_dims_t *arr);
 static ifref_list_t *append_ifref(ifref_list_t *list, ifref_t *iface);
 static ifref_t *make_ifref(type_t *iface);
 static var_list_t *append_var(var_list_t *list, var_t *var);
 static var_t *make_var(char *name);
+static pident_list_t *append_pident(pident_list_t *list, pident_t *p);
+static pident_t *make_pident(var_t *var);
 static func_list_t *append_func(func_list_t *list, func_t *func);
 static func_t *make_func(var_t *def, var_list_t *args);
 static type_t *make_class(char *name);
@@ -127,6 +129,8 @@ static void check_arg(var_t *arg);
 	type_t *type;
 	var_t *var;
 	var_list_t *var_list;
+	pident_t *pident;
+	pident_list_t *pident_list;
 	func_t *func;
 	func_list_t *func_list;
 	ifref_t *ifref;
@@ -234,8 +238,10 @@ static void check_arg(var_t *arg);
 %type <ifref> coclass_int
 %type <ifref_list> gbl_statements coclass_ints
 %type <var> arg field s_field case enum constdef externdef
-%type <var_list> m_args no_args args fields cases enums enum_list pident_list dispint_props
-%type <var> m_ident t_ident ident p_ident pident
+%type <var_list> m_args no_args args fields cases enums enum_list dispint_props
+%type <var> m_ident t_ident ident
+%type <pident> p_ident pident
+%type <pident_list> pident_list
 %type <func> funcdef
 %type <func_list> int_statements dispint_meths
 %type <type> coclass coclasshdr coclassdef
@@ -297,12 +303,12 @@ int_statements:					{ $$ = NULL; }
 statement: ';'					{}
 	| constdef ';'				{ if (!parse_only && do_header) { write_constdef($1); } }
 	| cppquote				{}
-	| enumdef ';'				{ if (!parse_only && do_header) { write_type(header, $1, NULL); fprintf(header, ";\n\n"); } }
+	| enumdef ';'				{ if (!parse_only && do_header) { write_type(header, $1); fprintf(header, ";\n\n"); } }
 	| externdef ';'				{ if (!parse_only && do_header) { write_externdef($1); } }
 	| import				{}
-	| structdef ';'				{ if (!parse_only && do_header) { write_type(header, $1, NULL); fprintf(header, ";\n\n"); } }
+	| structdef ';'				{ if (!parse_only && do_header) { write_type(header, $1); fprintf(header, ";\n\n"); } }
 	| typedef ';'				{}
-	| uniondef ';'				{ if (!parse_only && do_header) { write_type(header, $1, NULL); fprintf(header, ";\n\n"); } }
+	| uniondef ';'				{ if (!parse_only && do_header) { write_type(header, $1); fprintf(header, ";\n\n"); } }
 	;
 
 cppquote: tCPPQUOTE '(' aSTRING ')'		{ if (!parse_only && do_header) fprintf(header, "%s\n", $3); }
@@ -339,22 +345,24 @@ args:	  arg					{ check_arg($1); $$ = append_var( NULL, $1 ); }
 	;
 
 /* split into two rules to get bison to resolve a tVOID conflict */
-arg:	  attributes type pident array		{ $$ = $3;
-						  set_type($$, $2, $4);
+arg:	  attributes type pident array		{ $$ = $3->var;
+						  set_type($$, $2, $3->ptr_level, $4);
+						  free($3);
 						  $$->attrs = $1;
 						}
-	| type pident array			{ $$ = $2;
-						  set_type($$, $1, $3);
+	| type pident array			{ $$ = $2->var;
+						  set_type($$, $1, $2->ptr_level, $3);
+						  free($2);
 						}
-	| attributes type pident '(' m_args ')'	{ $$ = $3;
-						  $$->ptr_level--;
-						  set_type($$, $2, NULL);
+	| attributes type pident '(' m_args ')'	{ $$ = $3->var;
+						  set_type($$, $2, $3->ptr_level - 1, NULL);
+						  free($3);
 						  $$->attrs = $1;
 						  $$->args = $5;
 						}
-	| type pident '(' m_args ')'		{ $$ = $2;
-						  $$->ptr_level--;
-						  set_type($$, $1, NULL);
+	| type pident '(' m_args ')'		{ $$ = $2->var;
+						  set_type($$, $1, $2->ptr_level - 1, NULL);
+						  free($2);
 						  $$->args = $4;
 						}
 	;
@@ -482,7 +490,7 @@ case:	  tCASE expr ':' field			{ attr_t *a = make_attrp(ATTR_CASE, $2);
 	;
 
 constdef: tCONST type ident '=' expr_const	{ $$ = reg_const($3);
-						  set_type($$, $2, NULL);
+						  set_type($$, $2, 0, NULL);
 						  $$->eval = $5;
 						}
 	;
@@ -574,7 +582,7 @@ expr_const: expr				{ $$ = $1;
 	;
 
 externdef: tEXTERN tCONST type ident		{ $$ = $4;
-						  set_type($$, $3, NULL);
+						  set_type($$, $3, 0, NULL);
 						}
 	;
 
@@ -588,15 +596,21 @@ field:	  s_field ';'				{ $$ = $1; }
 	| ';'					{ $$ = NULL; }
 	;
 
-s_field:  m_attributes type pident array	{ $$ = $3; set_type($$, $2, $4); $$->attrs = $1; }
+s_field:  m_attributes type pident array	{ $$ = $3->var;
+						  set_type($$, $2, $3->ptr_level, $4);
+						  free($3);
+						  $$->attrs = $1;
+						}
 	;
 
 funcdef:
 	  m_attributes type callconv pident
-	  '(' m_args ')'			{ set_type($4, $2, NULL);
-						  $4->attrs = $1;
-						  $$ = make_func($4, $6);
-						  if (is_attr($4->attrs, ATTR_IN)) {
+	  '(' m_args ')'			{ var_t *v = $4->var;
+						  set_type(v, $2, $4->ptr_level, NULL);
+						  free($4);
+						  v->attrs = $1;
+						  $$ = make_func(v, $6);
+						  if (is_attr(v->attrs, ATTR_IN)) {
 						    yyerror("inapplicable attribute [in] for function '%s'",$$->def->name);
 						  }
 						}
@@ -792,14 +806,14 @@ p_ident:  '*' pident %prec PPTR			{ $$ = $2; $$->ptr_level++; }
 	| tCONST p_ident			{ $$ = $2; /* FIXME */ }
 	;
 
-pident:	  ident
+pident:	  ident					{ $$ = make_pident($1); }
 	| p_ident
 	| '(' pident ')'			{ $$ = $2; }
 	;
 
 pident_list:
-	pident                                  { $$ = append_var( NULL, $1 ); }
-	| pident_list ',' pident                { $$ = append_var( $1, $3 ); }
+	pident                                  { $$ = append_pident( NULL, $1 ); }
+	| pident_list ',' pident                { $$ = append_pident( $1, $3 ); }
 	;
 
 pointer_type:
@@ -1185,6 +1199,7 @@ static type_t *make_type(unsigned char type, type_t *ref)
   t->funcs = NULL;
   t->fields = NULL;
   t->ifaces = NULL;
+  t->typestring_offset = 0;
   t->ignore = parse_only;
   t->is_const = FALSE;
   t->sign = 0;
@@ -1195,10 +1210,13 @@ static type_t *make_type(unsigned char type, type_t *ref)
   return t;
 }
 
-static void set_type(var_t *v, type_t *type, array_dims_t *arr)
+static void set_type(var_t *v, type_t *type, int ptr_level, array_dims_t *arr)
 {
   v->type = type;
   v->array = arr;
+
+  for ( ; 0 < ptr_level; --ptr_level)
+    v->type = make_type(RPC_FC_RP, v->type);
 }
 
 static ifref_list_t *append_ifref(ifref_list_t *list, ifref_t *iface)
@@ -1237,7 +1255,6 @@ static var_t *make_var(char *name)
 {
   var_t *v = xmalloc(sizeof(var_t));
   v->name = name;
-  v->ptr_level = 0;
   v->type = NULL;
   v->args = NULL;
   v->attrs = NULL;
@@ -1246,6 +1263,25 @@ static var_t *make_var(char *name)
   return v;
 }
 
+static pident_list_t *append_pident(pident_list_t *list, pident_t *p)
+{
+  if (!p) return list;
+  if (!list) {
+    list = xmalloc(sizeof(*list));
+    list_init(list);
+  }
+  list_add_tail(list, &p->entry);
+  return list;
+}
+
+static pident_t *make_pident(var_t *var)
+{
+  pident_t *p = xmalloc(sizeof(*p));
+  p->var = var;
+  p->ptr_level = 0;
+  return p;
+}
+
 static func_list_t *append_func(func_list_t *list, func_t *func)
 {
     if (!func) return list;
@@ -1326,10 +1362,10 @@ static type_t *reg_type(type_t *type, const char *name, int t)
   return type;
 }
 
-static type_t *reg_typedefs(type_t *type, var_list_t *names, attr_list_t *attrs)
+static type_t *reg_typedefs(type_t *type, pident_list_t *pidents, attr_list_t *attrs)
 {
   type_t *ptr = type;
-  const var_t *name;
+  const pident_t *pident;
   int ptrc = 0;
   int is_str = is_attr(attrs, ATTR_STRING);
   unsigned char ptr_type = get_attrv(attrs, ATTR_POINTERTYPE);
@@ -1345,9 +1381,9 @@ static type_t *reg_typedefs(type_t *type, var_list_t *names, attr_list_t *attrs)
     c = t->type;
     if (c != RPC_FC_CHAR && c != RPC_FC_BYTE && c != RPC_FC_WCHAR)
     {
-      name = LIST_ENTRY( list_head( names ), const var_t, entry );
+      pident = LIST_ENTRY( list_head( pidents ), const pident_t, entry );
       yyerror("'%s': [string] attribute is only valid on 'char', 'byte', or 'wchar_t' pointers and arrays",
-              name->name);
+              pident->var->name);
     }
   }
 
@@ -1363,11 +1399,13 @@ static type_t *reg_typedefs(type_t *type, var_list_t *names, attr_list_t *attrs)
     type->name = gen_name();
   }
 
-  LIST_FOR_EACH_ENTRY( name, names, const var_t, entry )
+  LIST_FOR_EACH_ENTRY( pident, pidents, const pident_t, entry )
   {
+    var_t *name = pident->var;
+
     if (name->name) {
       type_t *cur = ptr;
-      int cptr = name->ptr_level;
+      int cptr = pident->ptr_level;
       if (cptr > ptrc) {
         while (cptr > ptrc) {
           cur = ptr = make_type(RPC_FC_RP, cur);
@@ -1467,20 +1505,20 @@ static int get_struct_type(var_list_t *fields)
   {
     type_t *t = field->type;
 
-    if (field->ptr_level > 0)
+    if (is_ptr(field->type))
     {
         has_pointer = 1;
         continue;
     }
 
-    if (is_string_type(field->attrs, 0, field->array))
+    if (is_string_type(field->attrs, field->type, field->array))
     {
         has_conformance = 1;
         has_variance = 1;
         continue;
     }
 
-    if (is_array_type(field->attrs, 0, field->array))
+    if (is_array_type(field->attrs, field->type, field->array))
     {
         if (field->array && is_conformant_array(field->array))
         {
@@ -1700,21 +1738,23 @@ static char *gen_name(void)
   return name;
 }
 
-static void process_typedefs(var_list_t *names)
+static void process_typedefs(pident_list_t *pidents)
 {
-  var_t *name, *next;
+  pident_t *pident, *next;
 
-  if (!names) return;
-  LIST_FOR_EACH_ENTRY_SAFE( name, next, names, var_t, entry )
+  if (!pidents) return;
+  LIST_FOR_EACH_ENTRY_SAFE( pident, next, pidents, pident_t, entry )
   {
-    type_t *type = find_type(name->name, 0);
+    var_t *var = pident->var;
+    type_t *type = find_type(var->name, 0);
 
     if (! parse_only && do_header)
       write_typedef(type);
     if (in_typelib && type->attrs)
       add_typelib_entry(type);
 
-    free(name);
+    free(pident);
+    free(var);
   }
 }
 
diff --git a/tools/widl/proxy.c b/tools/widl/proxy.c
index 6e0817a..2eb9de1 100644
--- a/tools/widl/proxy.c
+++ b/tools/widl/proxy.c
@@ -138,7 +138,7 @@ static void clear_output_vars( const var_list_t *args )
 
 int is_var_ptr(const var_t *v)
 {
-  return v->ptr_level || is_ptr(v->type);
+  return is_ptr(v->type);
 }
 
 int cant_be_null(const var_t *v)
@@ -247,12 +247,17 @@ static void proxy_free_variables( var_list_t *args, unsigned int type_offset )
   if (!args) return;
   LIST_FOR_EACH_ENTRY( arg, args, const var_t, entry )
   {
+    size_t start_offset;
+    size_t size_type = get_size_typeformatstring_var(arg, &start_offset);
+    start_offset += type_offset;
+
     if (is_attr(arg->attrs, ATTR_OUT))
     {
       free_variable( arg, type_offset );
       fprintf(proxy, "\n");
     }
-    type_offset += get_size_typeformatstring_var(arg);
+
+    type_offset += size_type;
   }
 }
 
@@ -260,11 +265,11 @@ static void gen_proxy(type_t *iface, const func_t *cur, int idx,
                       unsigned int proc_offset, unsigned int *type_offset)
 {
   var_t *def = cur->def;
-  int has_ret = !is_void(def->type, def);
+  int has_ret = !is_void(def->type);
   unsigned int offset;
 
   indent = 0;
-  write_type(proxy, def->type, def);
+  write_type(proxy, def->type);
   print_proxy( " STDMETHODCALLTYPE %s_", iface->name);
   write_name(proxy, def);
   print_proxy( "_Proxy(\n");
@@ -275,7 +280,7 @@ static void gen_proxy(type_t *iface, const func_t *cur, int idx,
   /* local variables */
   if (has_ret) {
     print_proxy( "" );
-    write_type(proxy, def->type, def);
+    write_type(proxy, def->type);
     print_proxy( " _RetVal;\n");
   }
   print_proxy( "RPC_MESSAGE _RpcMessage;\n" );
@@ -355,7 +360,7 @@ static void gen_stub(type_t *iface, const func_t *cur, const char *cas,
 {
   var_t *def = cur->def;
   const var_t *arg;
-  int has_ret = !is_void(def->type, def);
+  int has_ret = !is_void(def->type);
   unsigned int offset;
 
   indent = 0;
diff --git a/tools/widl/server.c b/tools/widl/server.c
index a51a69c..be366ea 100644
--- a/tools/widl/server.c
+++ b/tools/widl/server.c
@@ -192,7 +192,7 @@ static void write_function_stubs(type_t *iface, unsigned int *proc_offset, unsig
         assign_stub_out_args(server, indent, func);
 
         /* Call the real server function */
-        if (!is_void(def->type, NULL))
+        if (!is_void(def->type))
             print_server("_RetVal = ");
         else
             print_server("");
@@ -246,7 +246,7 @@ static void write_function_stubs(type_t *iface, unsigned int *proc_offset, unsig
         write_remoting_arguments(server, indent, func, type_offset, PASS_OUT, PHASE_MARSHAL);
 
         /* marshall the return value */
-        if (!is_void(def->type, NULL))
+        if (!is_void(def->type))
             print_phase_basetype(server, indent, PHASE_MARSHAL, PASS_RETURN, def, "_RetVal");
 
         indent--;
diff --git a/tools/widl/typegen.c b/tools/widl/typegen.c
index d3d2c1c..e8385ec 100644
--- a/tools/widl/typegen.c
+++ b/tools/widl/typegen.c
@@ -59,7 +59,7 @@ struct expr_eval_routine
     const expr_t *expr;
 };
 
-static size_t type_memsize(const type_t *t, int ptr_level, const array_dims_t *array, unsigned int *align);
+static size_t type_memsize(const type_t *t, const array_dims_t *array, unsigned int *align);
 static size_t fields_memsize(const var_list_t *fields, unsigned int *align);
 
 const char *string_of_type(unsigned char type)
@@ -235,7 +235,6 @@ static size_t write_procformatstring_var(FILE *file, int indent,
     const var_t *var, int is_return, unsigned int *type_offset)
 {
     size_t size;
-    int ptr_level = var->ptr_level;
     const type_t *type = var->type;
 
     int is_in = is_attr(var->attrs, ATTR_IN);
@@ -243,7 +242,7 @@ static size_t write_procformatstring_var(FILE *file, int indent,
 
     if (!is_in && !is_out) is_in = TRUE;
 
-    if (ptr_level == 0 && !var->array && is_base_type(type->type))
+    if (!var->array && is_base_type(type->type))
     {
         if (is_return)
             print_file(file, indent, "0x53,    /* FC_RETURN_PARAM_BASETYPE */\n");
@@ -281,7 +280,7 @@ static size_t write_procformatstring_var(FILE *file, int indent,
         print_file(file, indent, "NdrFcShort(0x%x),\n", *type_offset);
         size = 4; /* includes param type prefix */
     }
-    *type_offset += get_size_typeformatstring_var(var);
+    *type_offset += get_size_typeformatstring_var(var, NULL);
     return size;
 }
 
@@ -319,7 +318,7 @@ void write_procformatstring(FILE *file, const ifref_list_t *ifaces, int for_obje
 
                 /* emit return value data */
                 var = func->def;
-                if (is_void(var->type, NULL))
+                if (is_void(var->type))
                 {
                     print_file(file, indent, "0x5b,    /* FC_END */\n");
                     print_file(file, indent, "0x5c,    /* FC_PAD */\n");
@@ -347,6 +346,7 @@ static int write_base_type(FILE *file, const type_t *type, unsigned int *typestr
         *typestring_offset += 1;
         return 1;
     }
+
     return 0;
 }
 
@@ -439,7 +439,7 @@ static size_t write_conf_or_var_desc(FILE *file, const func_t *func, const type_
             if (structure->fields) LIST_FOR_EACH_ENTRY( var, structure->fields, const var_t, entry )
             {
                 unsigned int align = 0;
-                offset -= type_memsize(var->type, var->ptr_level, var->array, &align);
+                offset -= type_memsize(var->type, var->array, &align);
                 /* FIXME: take alignment into account */
                 if (!strcmp(var->name, subexpr->u.sval))
                 {
@@ -593,7 +593,7 @@ static size_t fields_memsize(const var_list_t *fields, unsigned int *align)
 
     if (!fields) return 0;
     LIST_FOR_EACH_ENTRY( v, fields, const var_t, entry )
-        size += type_memsize(v->type, v->ptr_level, v->array, align);
+        size += type_memsize(v->type, v->array, align);
 
     return size;
 }
@@ -614,11 +614,11 @@ static size_t get_array_size( const array_dims_t *array )
     return size;
 }
 
-static size_t type_memsize(const type_t *t, int ptr_level, const array_dims_t *array, unsigned int *align)
+static size_t type_memsize(const type_t *t, const array_dims_t *array, unsigned int *align)
 {
     size_t size = 0;
 
-    if (ptr_level)
+    if (is_ptr(t))
     {
         size = sizeof(void *);
         if (size > *align) *align = size;
@@ -671,8 +671,29 @@ static size_t type_memsize(const type_t *t, int ptr_level, const array_dims_t *a
     return size;
 }
 
+static size_t write_nonsimple_pointer(FILE *file, const type_t *type, size_t offset)
+{
+    short absoff = type->ref->typestring_offset;
+    short reloff = absoff - (offset + 2);
+    print_file(file, 2, "0x%02x, 0x10,\t/* %s */\n",
+               type->type, string_of_type(type->type));
+    print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%hd) */\n",
+               reloff, reloff, absoff);
+    return 4;
+}
+
+static size_t write_simple_pointer(FILE *file, const type_t *type)
+{
+    print_file(file, 2, "0x%02x, 0x8,\t/* %s [simple_pointer] */\n",
+               type->type, string_of_type(type->type));
+    print_file(file, 2, "0x%02x,\t/* %s */\n", type->ref->type,
+               string_of_type(type->ref->type));
+    print_file(file, 2, "0x5c,\t/* FC_PAD */\n");
+    return 4;
+}
+
 static int write_pointers(FILE *file, const attr_list_t *attrs,
-                          const type_t *type, int ptr_level,
+                          type_t *type,
                           const array_dims_t *array, int level,
                           unsigned int *typestring_offset)
 {
@@ -681,15 +702,43 @@ static int write_pointers(FILE *file, const attr_list_t *attrs,
 
     /* don't generate a pointer for first-level arrays since we want to
     * descend into them to write their pointers, not stop here */
-    if ((level == 0 || ptr_level == 0) && is_array_type(attrs, ptr_level, array))
+    if ((level == 0 || !is_ptr(type)) && is_array_type(attrs, type, array))
     {
-        return write_pointers(file, NULL, type, 0, NULL, level + 1, typestring_offset);
+        return write_pointers(file, NULL, type, NULL, level + 1, typestring_offset);
     }
 
-    if (ptr_level != 0)
+    if (is_ptr(type))
     {
-        /* FIXME: only general algorithm implemented, not the actual writing */
-        error("write_pointers: Writing type format string for pointer is unimplemented\n");
+        if (!is_ptr(type->ref) && 1 < level)
+        {
+            print_file(file, 0, "/* %d */\n", *typestring_offset);
+            if (type->ref->typestring_offset)
+            {
+                type->typestring_offset = *typestring_offset;
+                *typestring_offset += write_nonsimple_pointer(file, type, *typestring_offset);
+            }
+            else if (is_base_type(type->ref->type))
+            {
+                type->typestring_offset = *typestring_offset;
+                *typestring_offset += write_simple_pointer(file, type);
+            }
+            else
+                error("write_pointers: pointer doesn't point to anything recognizable (0x%02x)\n",
+                      type->ref->type);
+        }
+        else
+        {
+            pointers_written = write_pointers(file, attrs, type->ref, array,
+                                              level + 1, typestring_offset);
+
+            if (1 < level)
+            {
+                print_file(file, 0, "/* %d */\n", *typestring_offset);
+                type->typestring_offset = *typestring_offset;
+                *typestring_offset += write_nonsimple_pointer(file, type, *typestring_offset);
+            }
+        }
+
         return 1;
     }
 
@@ -705,7 +754,7 @@ static int write_pointers(FILE *file, const attr_list_t *attrs,
             if (!type->fields) break;
             LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry )
                 pointers_written += write_pointers(file, v->attrs, v->type,
-                                                   v->ptr_level, v->array,
+                                                   v->array,
                                                    level + 1,
                                                    typestring_offset);
 
@@ -720,34 +769,45 @@ static int write_pointers(FILE *file, const attr_list_t *attrs,
 }
 
 static size_t write_pointer_description(FILE *file, const attr_list_t *attrs,
-                                        const type_t *type, int ptr_level,
+                                        const type_t *type, size_t mem_offset,
                                         const array_dims_t *array, int level,
-                                        size_t typestring_offset)
+                                        size_t *typestring_offset)
 {
-    size_t size = 0;
     const var_t *v;
+    unsigned int align = 0;
 
     /* don't generate a pointer for first-level arrays since we want to
      * descend into them to write their pointers, not stop here */
-    if ((level == 0 || ptr_level == 0) && is_array_type(attrs, ptr_level, array))
+    if ((level == 0 || !is_ptr(type)) && is_array_type(attrs, type, array))
     {
-        return write_pointer_description(file, NULL, type, 0, NULL,
-                                         level + 1, typestring_offset);
+        write_pointer_description(file, NULL, type, mem_offset, NULL,
+                                  level + 1, typestring_offset);
     }
-
-    if (ptr_level != 0)
+    else if (is_ptr(type))
     {
-        /* FIXME: only general algorithm implemented, not the actual writing */
-        error("write_pointer_description: Writing pointer description is unimplemented\n");
-        return 0;
-    }
-
-    /* FIXME: search through all refs for pointers too */
+        print_file(file, 2, "0x46,\t/* FC_NO_REPEAT */\n");
+        print_file(file, 2, "0x5c,\t/* FC_PAD */\n");
+        print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", mem_offset, mem_offset);
+        print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", mem_offset, mem_offset);
 
-    switch (type->type)
+        if (type->ref->typestring_offset)
+        {
+            *typestring_offset
+                += 6 + write_nonsimple_pointer(file, type, 6 + *typestring_offset);
+        }
+        else if (is_base_type(type->ref->type))
+        {
+            *typestring_offset += 6 + write_simple_pointer(file, type);
+        }
+        else
+            error("write_pointer_description: unimplemented\n");
+    }
+    else
     {
-        /* note: don't descend into complex structures or unions since these
-         * will always be generated as a separate type */
+        switch (type->type)
+        {
+            /* note: don't descend into complex structures or unions since these
+             * will always be generated as a separate type */
         case RPC_FC_STRUCT:
         case RPC_FC_CVSTRUCT:
         case RPC_FC_CPSTRUCT:
@@ -755,19 +815,21 @@ static size_t write_pointer_description(FILE *file, const attr_list_t *attrs,
         case RPC_FC_PSTRUCT:
             if (!type->fields) break;
             LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry )
-                size += write_pointer_description(file, v->attrs, v->type,
-                                                  v->ptr_level, v->array,
-                                                  level + 1,
-                                                  typestring_offset);
-
+                {
+                    mem_offset
+                        += write_pointer_description(file, v->attrs, v->type,
+                                                     mem_offset, v->array,
+                                                     level + 1,
+                                                     typestring_offset);
+                }
             break;
 
         default:
-            /* nothing to do */
             break;
+        }
     }
 
-    return size;
+    return type_memsize(type, array, &align);
 }
 
 static size_t write_string_tfs(FILE *file, const attr_list_t *attrs,
@@ -805,7 +867,7 @@ static size_t write_string_tfs(FILE *file, const attr_list_t *attrs,
 
     print_file(file, 2,"0x%x, 0x%x,    /* %s%s */\n",
                pointer_type, flags,
-               string_of_type(pointer_type),
+               pointer_type == RPC_FC_FP ? "FC_FP" : (pointer_type == RPC_FC_UP ? "FC_UP" : "FC_RP"),
                (flags & RPC_FC_P_SIMPLEPOINTER) ? " [simple_pointer]" : "");
     *typestring_offset += 2;
 
@@ -862,7 +924,7 @@ static size_t write_string_tfs(FILE *file, const attr_list_t *attrs,
 }
 
 static size_t write_array_tfs(FILE *file, const attr_list_t *attrs,
-                              const type_t *type, const array_dims_t *array,
+                              type_t *type, const array_dims_t *array,
                               const char *name, unsigned int *typestring_offset)
 {
     const expr_list_t *length_is = get_attrp(attrs, ATTR_LENGTHIS);
@@ -876,7 +938,7 @@ static size_t write_array_tfs(FILE *file, const attr_list_t *attrs,
 
     print_file(file, 2, "0x%x, 0x00,    /* %s */\n",
                pointer_type,
-               string_of_type(pointer_type));
+               pointer_type == RPC_FC_FP ? "FC_FP" : (pointer_type == RPC_FC_UP ? "FC_UP" : "FC_RP"));
     print_file(file, 2, "NdrFcShort(0x2),\n");
     *typestring_offset += 4;
 
@@ -888,10 +950,9 @@ static size_t write_array_tfs(FILE *file, const attr_list_t *attrs,
     else
     {
         const expr_t *dim = array ? LIST_ENTRY( list_head( array ), expr_t, entry ) : NULL;
-        size_t pointer_start_offset = *typestring_offset;
         int has_pointer = 0;
 
-        if (write_pointers(file, attrs, type, 0, array, 0, typestring_offset) > 0)
+        if (write_pointers(file, attrs, type, array, 0, typestring_offset) > 0)
             has_pointer = 1;
 
         start_offset = *typestring_offset;
@@ -900,7 +961,7 @@ static size_t write_array_tfs(FILE *file, const attr_list_t *attrs,
         {
             /* fixed array */
             unsigned int align = 0;
-            size_t size = type_memsize(type, 0, array, &align);
+            size_t size = type_memsize(type, array, &align);
             if (size < USHRT_MAX)
             {
                 WRITE_FCTYPE(file, FC_SMFARRAY, *typestring_offset);
@@ -925,8 +986,7 @@ static size_t write_array_tfs(FILE *file, const attr_list_t *attrs,
                 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
                 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
                 *typestring_offset += 2;
-                *typestring_offset = write_pointer_description(file, attrs,
-                    type, 0, array, 0, pointer_start_offset);
+                write_pointer_description(file, attrs, type, 0, array, 0, typestring_offset);
                 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
                 *typestring_offset += 1;
             }
@@ -945,7 +1005,7 @@ static size_t write_array_tfs(FILE *file, const attr_list_t *attrs,
         {
             /* varying array */
             unsigned int align = 0;
-            size_t element_size = type_memsize(type, 0, NULL, &align);
+            size_t element_size = type_memsize(type, NULL, &align);
             size_t elements = dim->cval;
             size_t total_size = element_size * elements;
 
@@ -984,8 +1044,7 @@ static size_t write_array_tfs(FILE *file, const attr_list_t *attrs,
                 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
                 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
                 *typestring_offset += 2;
-                *typestring_offset += write_pointer_description(file, attrs,
-                    type, 0, array, 0, pointer_start_offset);
+                write_pointer_description(file, attrs, type, 0, array, 0, typestring_offset);
                 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
                 *typestring_offset += 1;
             }
@@ -1004,7 +1063,7 @@ static size_t write_array_tfs(FILE *file, const attr_list_t *attrs,
         {
             /* conformant array */
             unsigned int align = 0;
-            size_t element_size = type_memsize(type, 0, NULL, &align);
+            size_t element_size = type_memsize(type, NULL, &align);
 
             WRITE_FCTYPE(file, FC_CARRAY, *typestring_offset);
             /* alignment */
@@ -1022,8 +1081,7 @@ static size_t write_array_tfs(FILE *file, const attr_list_t *attrs,
                 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
                 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
                 *typestring_offset += 2;
-                *typestring_offset += write_pointer_description(file, attrs,
-                    type, 0, array, 0, pointer_start_offset);
+                write_pointer_description(file, attrs, type, 0, array, 0, typestring_offset);
                 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
                 *typestring_offset += 1;
             }
@@ -1042,7 +1100,7 @@ static size_t write_array_tfs(FILE *file, const attr_list_t *attrs,
         {
             /* conformant varying array */
             unsigned int align = 0;
-            size_t element_size = type_memsize(type, 0, NULL, &align);
+            size_t element_size = type_memsize(type, NULL, &align);
 
             WRITE_FCTYPE(file, FC_CVARRAY, *typestring_offset);
             /* alignment */
@@ -1063,8 +1121,7 @@ static size_t write_array_tfs(FILE *file, const attr_list_t *attrs,
                 print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
                 print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
                 *typestring_offset += 2;
-                *typestring_offset += write_pointer_description(file, attrs,
-                    type, 0, array, 0, pointer_start_offset);
+                write_pointer_description(file, attrs, type, 0, array, 0, typestring_offset);
                 print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
                 *typestring_offset += 1;
             }
@@ -1086,7 +1143,7 @@ static const var_t *find_array_or_string_in_struct(const type_t *type)
 {
     const var_t *last_field = LIST_ENTRY( list_tail(type->fields), const var_t, entry );
 
-    if (is_array_type(last_field->attrs, last_field->ptr_level, last_field->array))
+    if (is_array_type(last_field->attrs, last_field->type, last_field->array))
         return last_field;
 
     assert((last_field->type->type == RPC_FC_CSTRUCT) ||
@@ -1107,6 +1164,12 @@ static void write_struct_members(FILE *file, const type_t *type, unsigned int *t
         if (field->array)
             write_array_tfs( file, field->attrs, field->type, field->array,
                              field->name, typestring_offset );
+        else if (is_ptr( field->type ))
+        {
+            /* pointers are handled in detail earlier, here just treat them like longs */
+            print_file( file, 2, "0x8,\t/* FC_LONG */\n" );
+            *typestring_offset += 1;
+        }
         else if (!write_base_type( file, field->type, typestring_offset ))
             error("Unsupported member type 0x%x\n", rtype);
     }
@@ -1121,32 +1184,28 @@ static void write_struct_members(FILE *file, const type_t *type, unsigned int *t
     *typestring_offset += 1;
 }
 
-static size_t write_struct_tfs(FILE *file, const type_t *type,
+static size_t write_struct_tfs(FILE *file, type_t *type,
                                const char *name, unsigned int *typestring_offset)
 {
     unsigned int total_size;
     const var_t *array;
     size_t start_offset;
     size_t array_offset;
-    size_t pointer_offset;
+    int has_pointers;
     unsigned int align = 0;
 
     switch (type->type)
     {
     case RPC_FC_STRUCT:
     case RPC_FC_PSTRUCT:
-        total_size = type_memsize(type, 0, NULL, &align);
+        total_size = type_memsize(type, NULL, &align);
 
         if (total_size > USHRT_MAX)
             error("structure size for parameter %s exceeds %d bytes by %d bytes\n",
                   name, USHRT_MAX, total_size - USHRT_MAX);
 
         if (type->type == RPC_FC_PSTRUCT)
-        {
-            pointer_offset = *typestring_offset;
-            write_pointers(file, NULL, type, 0, NULL, 0, typestring_offset);
-        }
-        else pointer_offset = 0; /* silence warning */
+            write_pointers(file, NULL, type, NULL, 0, typestring_offset);
 
         start_offset = *typestring_offset;
         if (type->type == RPC_FC_STRUCT)
@@ -1164,8 +1223,7 @@ static size_t write_struct_tfs(FILE *file, const type_t *type,
             print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
             print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
             *typestring_offset += 2;
-            *typestring_offset += write_pointer_description(file, NULL,
-                type, 0, NULL, 0, pointer_offset);
+            write_pointer_description(file, NULL, type, 0, NULL, 0, typestring_offset);
             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
             *typestring_offset += 1;
         }
@@ -1175,7 +1233,7 @@ static size_t write_struct_tfs(FILE *file, const type_t *type,
         return start_offset;
     case RPC_FC_CSTRUCT:
     case RPC_FC_CPSTRUCT:
-        total_size = type_memsize(type, 0, NULL, &align);
+        total_size = type_memsize(type, NULL, &align);
 
         if (total_size > USHRT_MAX)
             error("structure size for parameter %s exceeds %d bytes by %d bytes\n",
@@ -1189,11 +1247,7 @@ static size_t write_struct_tfs(FILE *file, const type_t *type,
         current_structure = NULL;
 
         if (type->type == RPC_FC_CPSTRUCT)
-        {
-            pointer_offset = *typestring_offset;
-            write_pointers(file, NULL, type, 0, NULL, 0, typestring_offset);
-        }
-        else pointer_offset = 0; /* silence warning */
+            write_pointers(file, NULL, type, NULL, 0, typestring_offset);
 
         start_offset = *typestring_offset;
         if (type->type == RPC_FC_CSTRUCT)
@@ -1216,8 +1270,7 @@ static size_t write_struct_tfs(FILE *file, const type_t *type,
             print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
             print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
             *typestring_offset += 2;
-            *typestring_offset += write_pointer_description(file, NULL,
-                type, 0, NULL, 0, pointer_offset);
+            write_pointer_description(file, NULL, type, 0, NULL, 0, typestring_offset);
             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
             *typestring_offset += 1;
         }
@@ -1227,7 +1280,7 @@ static size_t write_struct_tfs(FILE *file, const type_t *type,
 
         return start_offset;
     case RPC_FC_CVSTRUCT:
-        total_size = type_memsize(type, 0, NULL, &align);
+        total_size = type_memsize(type, NULL, &align);
 
         if (total_size > USHRT_MAX)
             error("structure size for parameter %s exceeds %d bytes by %d bytes\n",
@@ -1245,9 +1298,7 @@ static size_t write_struct_tfs(FILE *file, const type_t *type,
                                            typestring_offset);
         current_structure = NULL;
 
-        pointer_offset = *typestring_offset;
-        if (!write_pointers(file, NULL, type, 0, NULL, 0, typestring_offset))
-            pointer_offset = 0;
+        has_pointers = write_pointers(file, NULL, type, NULL, 0, typestring_offset);
 
         start_offset = *typestring_offset;
         WRITE_FCTYPE(file, FC_CVSTRUCT, *typestring_offset);
@@ -1262,13 +1313,12 @@ static size_t write_struct_tfs(FILE *file, const type_t *type,
                    array_offset);
         *typestring_offset += 2;
 
-        if (pointer_offset != 0)
+        if (has_pointers)
         {
             print_file(file, 2, "0x%x, /* FC_PP */\n", RPC_FC_PP);
             print_file(file, 2, "0x%x, /* FC_PAD */\n", RPC_FC_PAD);
             *typestring_offset += 2;
-            *typestring_offset += write_pointer_description(file, NULL,
-                type, 0, NULL, 0, pointer_offset);
+            write_pointer_description(file, NULL, type, 0, NULL, 0, typestring_offset);
             print_file(file, 2, "0x%x, /* FC_END */\n", RPC_FC_END);
             *typestring_offset += 1;
         }
@@ -1283,10 +1333,12 @@ static size_t write_struct_tfs(FILE *file, const type_t *type,
     }
 }
 
-static void write_pointer_only_tfs(FILE *file, const attr_list_t *attrs, int pointer_type,
-                                   unsigned char flags, size_t offset,
-                                   unsigned int *typeformat_offset)
+static size_t write_pointer_only_tfs(FILE *file, const attr_list_t *attrs, int pointer_type,
+                                     unsigned char flags, size_t offset,
+                                     unsigned int *typeformat_offset)
 {
+    size_t start_offset = *typeformat_offset;
+    short reloff = offset - (*typeformat_offset + 2);
     int in_attr, out_attr;
     in_attr = is_attr(attrs, ATTR_IN);
     out_attr = is_attr(attrs, ATTR_OUT);
@@ -1298,7 +1350,7 @@ static void write_pointer_only_tfs(FILE *file, const attr_list_t *attrs, int poi
     print_file(file, 2, "0x%x, 0x%x,\t\t/* %s",
                pointer_type,
                flags,
-               string_of_type(pointer_type));
+               pointer_type == RPC_FC_FP ? "FC_FP" : (pointer_type == RPC_FC_UP ? "FC_UP" : "FC_RP"));
     if (file)
     {
         if (flags & 0x04)
@@ -1308,8 +1360,10 @@ static void write_pointer_only_tfs(FILE *file, const attr_list_t *attrs, int poi
         fprintf(file, " */\n");
     }
 
-    print_file(file, 2, "NdrFcShort(0x%x),    /* %d */\n", offset, offset);
+    print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", reloff, offset);
     *typeformat_offset += 4;
+
+    return start_offset;
 }
 
 static size_t write_union_tfs(FILE *file, const attr_list_t *attrs,
@@ -1320,7 +1374,7 @@ static size_t write_union_tfs(FILE *file, const attr_list_t *attrs,
     return *typeformat_offset;
 }
 
-static size_t write_ip_tfs(FILE *file, const func_t *func, const var_t *var,
+static size_t write_ip_tfs(FILE *file, const func_t *func, const type_t *type, const var_t *var,
                            unsigned int *typeformat_offset)
 {
     size_t i;
@@ -1344,7 +1398,7 @@ static size_t write_ip_tfs(FILE *file, const func_t *func, const var_t *var,
     }
     else
     {
-        const type_t *base = is_ptr(var->type) ? var->type->ref : var->type;
+        const type_t *base = is_ptr(type) ? type->ref : type;
         const UUID *uuid = get_attrp(base->attrs, ATTR_UUID);
 
         if (! uuid)
@@ -1380,129 +1434,96 @@ static int get_ptr_attr(const type_t *t, int def_type)
 }
 
 static size_t write_typeformatstring_var(FILE *file, int indent, const func_t *func,
-                                         const var_t *var, unsigned int *typeformat_offset)
+                                         type_t *type, const var_t *var,
+                                         unsigned int *typeformat_offset)
 {
-    const type_t *type = var->type;
-    int var_ptrs = var->ptr_level, type_ptrs = 0;
-    int is_str = is_attr(var->attrs, ATTR_STRING);
-
-    chat("write_typeformatstring_var: %s\n", var->name);
+    int pointer_type;
+    size_t offset;
 
-    while (TRUE)
+    if (type == var->type)      /* top-level pointers */
     {
-        is_str = is_str || is_attr(type->attrs, ATTR_STRING);
-        if (type->kind == TKIND_ALIAS)
-            type = type->orig;
-        else if (is_ptr(type))
-        {
-            ++type_ptrs;
-            type = type->ref;
-        }
-        else
-        {
-            type = var->type;
-            break;
-        }
-    }
+        int pointer_attr = get_attrv(var->attrs, ATTR_POINTERTYPE);
+        if (pointer_attr != 0 && !is_ptr(type))
+            error("'%s': pointer attribute applied to non-pointer type\n", var->name);
 
-    while (TRUE)
-    {
-        int ptr_level = var_ptrs + type_ptrs;
-        int pointer_type = 0;
+        if (pointer_attr == 0)
+            pointer_attr = get_ptr_attr(type, RPC_FC_RP);
 
-        chat("write_typeformatstring: type->type = 0x%x, type->name = %s, ptr_level = %d\n", type->type, type->name, ptr_level);
+        pointer_type = pointer_attr;
+    }
+    else
+        pointer_type = get_ptr_attr(type, RPC_FC_UP);
 
-        /* var attrs only effect the rightmost pointer  */
-        if ((0 < var->ptr_level && var_ptrs == var->ptr_level)
-            || (var->ptr_level == 0 && type == var->type))
-        {
-            int pointer_attr = get_attrv(var->attrs, ATTR_POINTERTYPE);
-            if (pointer_attr)
-            {
-                if (! ptr_level)
-                    error("'%s': pointer attribute applied to non-pointer type\n", var->name);
-                pointer_type = pointer_attr;
-            }
-            else
-                pointer_type = RPC_FC_RP;
-        }
-        else                            /* pointers below other pointers default to unique */
-            pointer_type = var_ptrs ? RPC_FC_UP : get_ptr_attr(type, RPC_FC_UP);
+    if (((last_ptr(type) && var->array == NULL)
+         || (!is_ptr(type) && var->array != NULL))
+        && is_ptrchain_attr(var, ATTR_STRING))
+    {
+        return write_string_tfs(file, var->attrs, type, var->array, var->name, typeformat_offset);
+    }
 
-        if (is_str && ptr_level + (var->array != NULL) == 1)
-            return write_string_tfs(file, var->attrs, type, var->array, var->name, typeformat_offset);
+    if (is_array_type(var->attrs, type, var->array))
+        return write_array_tfs(file, var->attrs, type, var->array, var->name, typeformat_offset);
 
-        if (is_array_type(var->attrs, ptr_level, var->array))
-            return write_array_tfs(file, var->attrs, type, var->array, var->name, typeformat_offset);
+    if (!is_ptr(type))
+    {
+        /* basic types don't need a type format string */
+        if (is_base_type(type->type))
+            return 0;
 
-        if (ptr_level == 0)
+        switch (type->type)
         {
-            /* basic types don't need a type format string */
-            if (is_base_type(type->type))
-                return 0;
-
-            switch (type->type)
-            {
-            case RPC_FC_STRUCT:
-            case RPC_FC_PSTRUCT:
-            case RPC_FC_CSTRUCT:
-            case RPC_FC_CPSTRUCT:
-            case RPC_FC_CVSTRUCT:
-            case RPC_FC_BOGUS_STRUCT:
-                return write_struct_tfs(file, type, var->name, typeformat_offset);
-            case RPC_FC_ENCAPSULATED_UNION:
-            case RPC_FC_NON_ENCAPSULATED_UNION:
-                return write_union_tfs(file, var->attrs, type, var->name, typeformat_offset);
-            case RPC_FC_IGNORE:
-            case RPC_FC_BIND_PRIMITIVE:
-                /* nothing to do */
-                return 0;
-            default:
-                error("write_typeformatstring_var: Unsupported type 0x%x for variable %s\n", type->type, var->name);
-            }
+        case RPC_FC_STRUCT:
+        case RPC_FC_PSTRUCT:
+        case RPC_FC_CSTRUCT:
+        case RPC_FC_CPSTRUCT:
+        case RPC_FC_CVSTRUCT:
+        case RPC_FC_BOGUS_STRUCT:
+            return write_struct_tfs(file, type, var->name, typeformat_offset);
+        case RPC_FC_ENCAPSULATED_UNION:
+        case RPC_FC_NON_ENCAPSULATED_UNION:
+            return write_union_tfs(file, var->attrs, type, var->name, typeformat_offset);
+        case RPC_FC_IGNORE:
+        case RPC_FC_BIND_PRIMITIVE:
+            /* nothing to do */
+            return 0;
+        default:
+            error("write_typeformatstring_var: Unsupported type 0x%x for variable %s\n", type->type, var->name);
         }
-        else if (ptr_level == 1)
-        {
-            size_t start_offset = *typeformat_offset;
-            int in_attr = is_attr(var->attrs, ATTR_IN);
-            int out_attr = is_attr(var->attrs, ATTR_OUT);
-            const type_t *base = is_ptr(type) ? type->ref : type;
-
-            if (base->type == RPC_FC_IP)
-            {
-                return write_ip_tfs(file, func, var, typeformat_offset);
-            }
+    }
+    else if (last_ptr(type))
+    {
+        size_t start_offset = *typeformat_offset;
+        int in_attr = is_attr(var->attrs, ATTR_IN);
+        int out_attr = is_attr(var->attrs, ATTR_OUT);
+        const type_t *base = type->ref;
 
-            /* special case for pointers to base types */
-            if (is_base_type(base->type))
-            {
-                print_file(file, indent, "0x%x, 0x%x,    /* %s %s[simple_pointer] */\n",
-                           pointer_type, (!in_attr && out_attr) ? 0x0C : 0x08,
-                           string_of_type(pointer_type),
-                           (!in_attr && out_attr) ? "[allocated_on_stack] " : "");
-                print_file(file, indent, "0x%02x,    /* %s */\n", base->type, string_of_type(base->type));
-                print_file(file, indent, "0x5c,          /* FC_PAD */\n");
-                *typeformat_offset += 4;
-                return start_offset;
-            }
+        if (base->type == RPC_FC_IP)
+        {
+            return write_ip_tfs(file, func, type, var, typeformat_offset);
         }
 
-        assert(ptr_level > 0);
-
-        if (file)
-            fprintf(file, "/* %2u */\n", *typeformat_offset);
-        write_pointer_only_tfs(file, var->attrs, pointer_type,
-                               1 < ptr_level ? 0x10 : 0,
-                               2, typeformat_offset);
-
-        if (var_ptrs)
-            --var_ptrs;
-        else
+        /* special case for pointers to base types */
+        if (is_base_type(base->type))
         {
-            --type_ptrs;
-            type = type->ref;
+            print_file(file, indent, "0x%x, 0x%x,    /* %s %s[simple_pointer] */\n",
+                       pointer_type, (!in_attr && out_attr) ? 0x0C : 0x08,
+                       string_of_type(pointer_type),
+                       (!in_attr && out_attr) ? "[allocated_on_stack] " : "");
+            print_file(file, indent, "0x%02x,    /* %s */\n", base->type, string_of_type(base->type));
+            print_file(file, indent, "0x5c,          /* FC_PAD */\n");
+            *typeformat_offset += 4;
+            return start_offset;
         }
     }
+
+    assert(is_ptr(type));
+
+    offset = write_typeformatstring_var(file, indent, func, type->ref, var, typeformat_offset);
+    if (file)
+        fprintf(file, "/* %2u */\n", *typeformat_offset);
+    return write_pointer_only_tfs(file, var->attrs, pointer_type,
+                           !last_ptr(type) ? 0x10 : 0,
+                           offset, typeformat_offset);
 }
 
 
@@ -1536,7 +1557,7 @@ void write_typeformatstring(FILE *file, const ifref_list_t *ifaces, int for_obje
                 current_func = func;
                 if (func->args)
                     LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
-                        write_typeformatstring_var(file, indent, func, var,
+                        write_typeformatstring_var(file, indent, func, var->type, var,
                                                    &typeformat_offset);
             }
         }
@@ -1551,13 +1572,13 @@ void write_typeformatstring(FILE *file, const ifref_list_t *ifaces, int for_obje
 }
 
 static unsigned int get_required_buffer_size_type(
-    const type_t *type, int ptr_level, const array_dims_t *array,
+    const type_t *type, const array_dims_t *array,
     const char *name, unsigned int *alignment)
 {
     size_t size = 0;
 
     *alignment = 0;
-    if (ptr_level == 0)
+    if (!is_ptr(type))
     {
         switch (type->type)
         {
@@ -1595,6 +1616,7 @@ static unsigned int get_required_buffer_size_type(
             return 0;
 
         case RPC_FC_STRUCT:
+        case RPC_FC_PSTRUCT:
         {
             const var_t *field;
             if (!type->fields) return 0;
@@ -1602,7 +1624,7 @@ static unsigned int get_required_buffer_size_type(
             {
                 unsigned int alignment;
                 size += get_required_buffer_size_type(
-                    field->type, field->ptr_level, field->array, field->name,
+                    field->type, field->array, field->name,
                     &alignment);
             }
             break;
@@ -1610,7 +1632,7 @@ static unsigned int get_required_buffer_size_type(
 
         case RPC_FC_RP:
             if (is_base_type( type->ref->type ) || type->ref->type == RPC_FC_STRUCT)
-                size = get_required_buffer_size_type( type->ref, 0, NULL, name, alignment );
+                size = get_required_buffer_size_type( type->ref, NULL, name, alignment );
             break;
 
         default:
@@ -1636,7 +1658,7 @@ static unsigned int get_required_buffer_size(const var_t *var, unsigned int *ali
 
     if (pass == PASS_OUT)
     {
-        if (out_attr && var->ptr_level > 0)
+        if (out_attr && is_ptr(var->type))
         {
             type_t *type = var->type;
 
@@ -1650,7 +1672,7 @@ static unsigned int get_required_buffer_size(const var_t *var, unsigned int *ali
                 {
                     unsigned int align;
                     size += get_required_buffer_size_type(
-                        field->type, field->ptr_level, field->array, field->name,
+                        field->type, field->array, field->name,
                         &align);
                 }
                 return size;
@@ -1662,7 +1684,7 @@ static unsigned int get_required_buffer_size(const var_t *var, unsigned int *ali
     {
         if ((!out_attr || in_attr) && !has_size && !is_attr(var->attrs, ATTR_STRING) && !var->array)
         {
-            if (var->ptr_level > 0)
+            if (is_ptr(var->type))
             {
                 type_t *type = var->type;
 
@@ -1680,7 +1702,7 @@ static unsigned int get_required_buffer_size(const var_t *var, unsigned int *ali
                     {
                         unsigned int align;
                         size += get_required_buffer_size_type(
-                            field->type, field->ptr_level, field->array, field->name,
+                            field->type, field->array, field->name,
                             &align);
                     }
                     return size;
@@ -1688,7 +1710,7 @@ static unsigned int get_required_buffer_size(const var_t *var, unsigned int *ali
             }
         }
 
-        return get_required_buffer_size_type(var->type, var->ptr_level, var->array, var->name, alignment);
+        return get_required_buffer_size_type(var->type, var->array, var->name, alignment);
     }
 }
 
@@ -1706,7 +1728,7 @@ static unsigned int get_function_buffer_size( const func_t *func, enum pass pass
         }
     }
 
-    if (pass == PASS_OUT && !is_void(func->def->type, NULL))
+    if (pass == PASS_OUT && !is_void(func->def->type))
     {
         total_size += get_required_buffer_size(func->def, &alignment, PASS_RETURN);
         total_size += alignment;
@@ -1755,7 +1777,7 @@ void print_phase_basetype(FILE *file, int indent, enum remoting_phase phase,
                           enum pass pass, const var_t *var,
                           const char *varname)
 {
-    const type_t *type = var->type;
+    type_t *type = var->type;
     unsigned int size;
     unsigned int alignment = 0;
     unsigned char rtype;
@@ -1764,7 +1786,7 @@ void print_phase_basetype(FILE *file, int indent, enum remoting_phase phase,
     if (phase != PHASE_MARSHAL && phase != PHASE_UNMARSHAL)
         return;
 
-    rtype = type->type;
+    rtype = is_ptr(type) ? type->ref->type : type->type;
 
     switch (rtype)
     {
@@ -1813,8 +1835,8 @@ void print_phase_basetype(FILE *file, int indent, enum remoting_phase phase,
     if (phase == PHASE_MARSHAL)
     {
         print_file(file, indent, "*(");
-        write_type(file, var->type, NULL);
-        if (var->ptr_level)
+        write_type(file, is_ptr(type) ? type->ref : type);
+        if (is_ptr(type))
             fprintf(file, " *)_StubMsg.Buffer = *");
         else
             fprintf(file, " *)_StubMsg.Buffer = ");
@@ -1828,16 +1850,16 @@ void print_phase_basetype(FILE *file, int indent, enum remoting_phase phase,
         else
             print_file(file, indent, "*");
         fprintf(file, varname);
-        if (pass == PASS_IN && var->ptr_level)
+        if (pass == PASS_IN && is_ptr(type))
             fprintf(file, " = (");
         else
             fprintf(file, " = *(");
-        write_type(file, var->type, NULL);
+        write_type(file, is_ptr(type) ? type->ref : type);
         fprintf(file, " *)_StubMsg.Buffer;\n");
     }
 
     print_file(file, indent, "_StubMsg.Buffer += sizeof(");
-    write_type(file, var->type, NULL);
+    write_type(file, var->type);
     fprintf(file, ");\n");
 }
 
@@ -1870,6 +1892,9 @@ void write_remoting_arguments(FILE *file, int indent, const func_t *func,
     {
         const type_t *type = var->type;
         unsigned char rtype;
+        size_t start_offset;
+        size_t size_type = get_size_typeformatstring_var(var, &start_offset);
+        start_offset += *type_offset;
 
         length_is = get_attrp(var->attrs, ATTR_LENGTHIS);
         size_is = get_attrp(var->attrs, ATTR_SIZEIS);
@@ -1901,12 +1926,12 @@ void write_remoting_arguments(FILE *file, int indent, const func_t *func,
 
         if (is_user_derived( var ))
         {
-            print_phase_function(file, indent, "UserMarshal", phase, var->name, *type_offset);
+            print_phase_function(file, indent, "UserMarshal", phase, var->name, start_offset);
         }
-        else if (is_string_type(var->attrs, var->ptr_level, var->array))
+        else if (is_string_type(var->attrs, var->type, var->array))
         {
             if (var->array && !is_conformant_array(var->array))
-                print_phase_function(file, indent, "NonConformantString", phase, var->name, *type_offset);
+                print_phase_function(file, indent, "NonConformantString", phase, var->name, start_offset);
             else
             {
                 if (size_is && is_size_needed_for_phase(phase))
@@ -1918,13 +1943,13 @@ void write_remoting_arguments(FILE *file, int indent, const func_t *func,
                 }
 
                 if ((phase == PHASE_FREE) || (pointer_type == RPC_FC_UP))
-                    print_phase_function(file, indent, "Pointer", phase, var->name, *type_offset);
+                    print_phase_function(file, indent, "Pointer", phase, var->name, start_offset);
                 else
                     print_phase_function(file, indent, "ConformantString", phase, var->name,
-                                         *type_offset + (has_size ? 4 : 2));
+                                         start_offset + (has_size ? 4 : 2));
             }
         }
-        else if (is_array_type(var->attrs, var->ptr_level, var->array))
+        else if (is_array_type(var->attrs, var->type, var->array))
         {
             const char *array_type;
 
@@ -1986,31 +2011,32 @@ void write_remoting_arguments(FILE *file, int indent, const func_t *func,
             else if (phase != PHASE_FREE)
             {
                 if (pointer_type == RPC_FC_UP)
-                    print_phase_function(file, indent, "Pointer", phase, var->name, *type_offset);
+                    print_phase_function(file, indent, "Pointer", phase, var->name, start_offset);
                 else
-                    print_phase_function(file, indent, array_type, phase, var->name, *type_offset + 4);
+                    print_phase_function(file, indent, array_type, phase, var->name, start_offset);
             }
         }
-        else if (var->ptr_level == 0 && is_base_type(rtype))
+        else if (!is_ptr(var->type) && is_base_type(rtype))
         {
             print_phase_basetype(file, indent, phase, pass, var, var->name);
         }
-        else if (var->ptr_level == 0)
+        else if (!is_ptr(var->type))
         {
             switch (rtype)
             {
             case RPC_FC_STRUCT:
-                print_phase_function(file, indent, "SimpleStruct", phase, var->name, *type_offset);
+            case RPC_FC_PSTRUCT:
+                print_phase_function(file, indent, "SimpleStruct", phase, var->name, start_offset);
                 break;
             case RPC_FC_CSTRUCT:
             case RPC_FC_CPSTRUCT:
-                print_phase_function(file, indent, "ConformantStruct", phase, var->name, *type_offset);
+                print_phase_function(file, indent, "ConformantStruct", phase, var->name, start_offset);
                 break;
             case RPC_FC_CVSTRUCT:
-                print_phase_function(file, indent, "ConformantVaryingStruct", phase, var->name, *type_offset);
+                print_phase_function(file, indent, "ConformantVaryingStruct", phase, var->name, start_offset);
                 break;
             case RPC_FC_BOGUS_STRUCT:
-                print_phase_function(file, indent, "ComplexStruct", phase, var->name, *type_offset);
+                print_phase_function(file, indent, "ComplexStruct", phase, var->name, start_offset);
                 break;
             case RPC_FC_RP:
                 if (is_base_type( var->type->ref->type ))
@@ -2020,43 +2046,42 @@ void write_remoting_arguments(FILE *file, int indent, const func_t *func,
                 else if (var->type->ref->type == RPC_FC_STRUCT)
                 {
                     if (phase != PHASE_BUFFERSIZE && phase != PHASE_FREE)
-                        print_phase_function(file, indent, "SimpleStruct", phase, var->name, *type_offset + 4);
+                        print_phase_function(file, indent, "SimpleStruct", phase, var->name, start_offset + 4);
                 }
                 else
                 {
                     const var_t *iid;
                     if ((iid = get_attrp( var->attrs, ATTR_IIDIS )))
                         print_file( file, indent, "_StubMsg.MaxCount = (unsigned long)%s;\n", iid->name );
-                    print_phase_function(file, indent, "Pointer", phase, var->name, *type_offset);
+                    print_phase_function(file, indent, "Pointer", phase, var->name, start_offset);
                 }
                 break;
             default:
-                error("write_remoting_arguments: Unsupported type: %s (0x%02x, ptr_level: %d)\n",
-                    var->name, rtype, var->ptr_level);
+                error("write_remoting_arguments: Unsupported type: %s (0x%02x)\n", var->name, rtype);
             }
         }
         else
         {
-            if ((var->ptr_level == 1) && (pointer_type == RPC_FC_RP) && is_base_type(rtype))
+            if (last_ptr(var->type) && (pointer_type == RPC_FC_RP) && is_base_type(rtype))
             {
                 print_phase_basetype(file, indent, phase, pass, var, var->name);
             }
-            else if ((var->ptr_level == 1) && (pointer_type == RPC_FC_RP) && (rtype == RPC_FC_STRUCT))
+            else if (last_ptr(var->type) && (pointer_type == RPC_FC_RP) && (rtype == RPC_FC_STRUCT))
             {
                 if (phase != PHASE_BUFFERSIZE && phase != PHASE_FREE)
-                    print_phase_function(file, indent, "SimpleStruct", phase, var->name, *type_offset + 4);
+                    print_phase_function(file, indent, "SimpleStruct", phase, var->name, start_offset + 4);
             }
             else
             {
                 const var_t *iid;
                 if ((iid = get_attrp( var->attrs, ATTR_IIDIS )))
                     print_file( file, indent, "_StubMsg.MaxCount = (unsigned long)%s;\n", iid->name );
-                print_phase_function(file, indent, "Pointer", phase, var->name, *type_offset);
+                print_phase_function(file, indent, "Pointer", phase, var->name, start_offset);
             }
         }
         fprintf(file, "\n");
     next:
-        *type_offset += get_size_typeformatstring_var(var);
+        *type_offset += size_type;
     }
 }
 
@@ -2079,7 +2104,7 @@ size_t get_size_procformatstring_func(const func_t *func)
             size += get_size_procformatstring_var(var);
 
     /* return value size */
-    if (is_void(func->def->type, NULL))
+    if (is_void(func->def->type))
         size += 2; /* FC_END and FC_PAD */
     else
         size += get_size_procformatstring_var(func->def);
@@ -2087,11 +2112,15 @@ size_t get_size_procformatstring_func(const func_t *func)
     return size;
 }
 
-size_t get_size_typeformatstring_var(const var_t *var)
+size_t get_size_typeformatstring_var(const var_t *var, size_t *pstart_offset)
 {
-    unsigned int type_offset = 0;
-    write_typeformatstring_var(NULL, 0, NULL, var, &type_offset);
-    return type_offset;
+    unsigned int type_offset = 2; /* 0 is used as an invalid offset */
+    size_t start_offset = write_typeformatstring_var(NULL, 0, NULL, var->type,
+                                                     var, &type_offset);
+    if (pstart_offset)
+        *pstart_offset = start_offset - 2;
+
+    return type_offset - 2;
 }
 
 size_t get_size_procformatstring(const ifref_list_t *ifaces, int for_objects)
@@ -2133,7 +2162,7 @@ size_t get_size_typeformatstring(const ifref_list_t *ifaces, int for_objects)
                 /* argument list size */
                 if (func->args)
                     LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
-                        size += get_size_typeformatstring_var(var);
+                        size += get_size_typeformatstring_var(var, NULL);
             }
         }
     }
@@ -2185,13 +2214,13 @@ static void write_struct_expr(FILE *h, const expr_t *e, int brackets,
             break;
         case EXPR_CAST:
             fprintf(h, "(");
-            write_type(h, e->u.tref, NULL);
+            write_type(h, e->u.tref);
             fprintf(h, ")");
             write_struct_expr(h, e->ref, 1, fields, structvar);
             break;
         case EXPR_SIZEOF:
             fprintf(h, "sizeof(");
-            write_type(h, e->u.tref, NULL);
+            write_type(h, e->u.tref);
             fprintf(h, ")");
             break;
         case EXPR_SHL:
@@ -2239,10 +2268,10 @@ void declare_stub_args( FILE *file, int indent, const func_t *func )
     const var_t *var;
 
     /* declare return value '_RetVal' */
-    if (!is_void(def->type, NULL))
+    if (!is_void(def->type))
     {
         print_file(file, indent, "");
-        write_type(file, def->type, def);
+        write_type(file, def->type);
         fprintf(file, " _RetVal;\n");
     }
 
@@ -2262,16 +2291,13 @@ void declare_stub_args( FILE *file, int indent, const func_t *func )
 
         if (!in_attr && !has_size && !is_string)
         {
-            int indirection;
             print_file(file, indent, "");
-            write_type(file, var->type, NULL);
-            for (indirection = 0; indirection < var->ptr_level - 1; indirection++)
-                fprintf(file, "*");
+            write_type(file, var->type->ref);
             fprintf(file, " _W%u;\n", i++);
         }
 
         print_file(file, indent, "");
-        write_type(file, var->type, var);
+        write_type(file, var->type);
         fprintf(file, " ");
         if (var->array) {
             fprintf(file, "( *");
@@ -2324,13 +2350,13 @@ void assign_stub_out_args( FILE *file, int indent, const func_t *func )
                     write_expr( file, expr, 1 );
                     fprintf(file, " * ");
                 }
-                size = type_memsize(type, 0, NULL, &align);
+                size = type_memsize(type, NULL, &align);
                 fprintf(file, "%u);\n", size);
             }
             else if (!is_string)
             {
                 fprintf(file, " = &_W%u;\n", i);
-                if (var->ptr_level > 1)
+                if (is_ptr(var->type) && !last_ptr(var->type))
                     print_file(file, indent, "_W%u = 0;\n", i);
                 i++;
             }
diff --git a/tools/widl/typegen.h b/tools/widl/typegen.h
index eda259b..9c9e5c0 100644
--- a/tools/widl/typegen.h
+++ b/tools/widl/typegen.h
@@ -42,7 +42,7 @@ void print_phase_basetype(FILE *file, int indent, enum remoting_phase phase, enu
 void write_remoting_arguments(FILE *file, int indent, const func_t *func, unsigned int *type_offset, enum pass pass, enum remoting_phase phase);
 size_t get_size_procformatstring_var(const var_t *var);
 size_t get_size_procformatstring_func(const func_t *func);
-size_t get_size_typeformatstring_var(const var_t *var);
+size_t get_size_typeformatstring_var(const var_t *var, size_t *start_offset);
 size_t get_size_procformatstring(const ifref_list_t *ifaces, int for_objects);
 size_t get_size_typeformatstring(const ifref_list_t *ifaces, int for_objects);
 void assign_stub_out_args( FILE *file, int indent, const func_t *func );
diff --git a/tools/widl/widltypes.h b/tools/widl/widltypes.h
index 15c5c1a..18a976a 100644
--- a/tools/widl/widltypes.h
+++ b/tools/widl/widltypes.h
@@ -39,6 +39,7 @@ typedef struct _expr_t expr_t;
 typedef struct _type_t type_t;
 typedef struct _typeref_t typeref_t;
 typedef struct _var_t var_t;
+typedef struct _pident_t pident_t;
 typedef struct _func_t func_t;
 typedef struct _ifref_t ifref_t;
 typedef struct _typelib_entry_t typelib_entry_t;
@@ -51,6 +52,7 @@ typedef struct list str_list_t;
 typedef struct list func_list_t;
 typedef struct list expr_list_t;
 typedef struct list var_list_t;
+typedef struct list pident_list_t;
 typedef struct list ifref_list_t;
 typedef struct list array_dims_t;
 
@@ -205,6 +207,7 @@ struct _type_t {
   var_list_t *fields;             /* interfaces, structures and enumerations */
   ifref_list_t *ifaces;           /* coclasses */
   type_t *orig;                   /* dup'd types */
+  unsigned int typestring_offset;
   int ignore, is_const, sign;
   int defined, written, user_types_registered;
   int typelib_idx;
@@ -212,7 +215,6 @@ struct _type_t {
 
 struct _var_t {
   char *name;
-  int ptr_level;
   array_dims_t *array;
   type_t *type;
   var_list_t *args;  /* for function pointers */
@@ -223,6 +225,14 @@ struct _var_t {
   struct list entry;
 };
 
+struct _pident_t {
+  var_t *var;
+  int ptr_level;
+
+  /* parser-internal */
+  struct list entry;
+};
+
 struct _func_t {
   var_t *def;
   var_list_t *args;
diff --git a/tools/widl/write_msft.c b/tools/widl/write_msft.c
index 439d7be..02422e7 100644
--- a/tools/widl/write_msft.c
+++ b/tools/widl/write_msft.c
@@ -1049,7 +1049,8 @@ static void dump_type(type_t *t)
 
 static int encode_var(
 	msft_typelib_t *typelib,   /* [I] The type library in which to encode the TYPEDESC. */
-	var_t *var,                /* [I] The type description to encode. */
+	type_t *type,              /* [I] The type description to encode. */
+	var_t *var,                /* [I] The var to encode. */
 	int *encoded_type,         /* [O] The encoded type description. */
 	int *width,                /* [O] The width of the type, or NULL. */
 	int *alignment,            /* [O] The alignment of the type, or NULL. */
@@ -1061,20 +1062,18 @@ static int encode_var(
     int child_size;
     int vt;
     int scratch;
-    type_t *type;
 
     if (!width) width = &scratch;
     if (!alignment) alignment = &scratch;
     if (!decoded_size) decoded_size = &scratch;
     *decoded_size = 0;
 
-    chat("encode_var: var %p var->type %p var->type->name %s var->ptr_level %d var->type->ref %p\n",
-         var, var->type, var->type->name ? var->type->name : "NULL", var->ptr_level, var->type->ref);
-    if(var->ptr_level) {
-        int skip_ptr;
-        var->ptr_level--;
-	skip_ptr = encode_var(typelib, var, &target_type, NULL, NULL, &child_size);
-        var->ptr_level++;
+    chat("encode_var: var %p type %p type->name %s type->ref %p\n",
+         var, type, type->name ? type->name : "NULL", type->ref);
+
+    vt = get_type_vt(type);
+    if (vt == VT_PTR) {
+        int skip_ptr = encode_var(typelib, type->ref, var, &target_type, NULL, NULL, &child_size);
 
         if(skip_ptr == 2) {
             chat("encode_var: skipping ptr\n");
@@ -1124,7 +1123,7 @@ static int encode_var(
         chat("array with %d dimensions\n", num_dims);
         array_save = var->array;
         var->array = NULL;
-	encode_var(typelib, var, &target_type, width, alignment, NULL);
+	encode_var(typelib, type, var, &target_type, width, alignment, NULL);
         var->array = array_save;
 	arrayoffset = ctl2_alloc_segment(typelib, MSFT_SEG_ARRAYDESC, (2 + 2 * num_dims) * sizeof(long), 0);
 	arraydata = (void *)&typelib->typelib_segment_data[MSFT_SEG_ARRAYDESC][arrayoffset];
@@ -1153,10 +1152,8 @@ static int encode_var(
 	*decoded_size = 20 /*sizeof(ARRAYDESC)*/ + (num_dims - 1) * 8 /*sizeof(SAFEARRAYBOUND)*/;
         return 0;
     }
-    dump_type(var->type);
+    dump_type(type);
 
-    vt = get_type_vt(var->type);
-    type = var->type;
     encode_type(typelib, vt, type, encoded_type, width, alignment, decoded_size);
     if(type->type == RPC_FC_IP) return 2;
     return 0;
@@ -1177,6 +1174,7 @@ static void write_value(msft_typelib_t* typelib, int *out, int vt, void *value)
     case VT_INT:
     case VT_UINT:
     case VT_HRESULT:
+    case VT_PTR:
       {
         unsigned long *lv = value;
         if((*lv & 0x3ffffff) == *lv) {
@@ -1389,7 +1387,7 @@ static HRESULT add_func_desc(msft_typeinfo_t* typeinfo, const func_t *func, int
 
     /* fill out the basic type information */
     typedata[0] = typedata_size | (index << 16);
-    encode_var(typeinfo->typelib, func->def, &typedata[1], NULL, NULL, &decoded_size);
+    encode_var(typeinfo->typelib, func->def->type, func->def, &typedata[1], NULL, NULL, &decoded_size);
     typedata[2] = funcflags;
     typedata[3] = ((52 /*sizeof(FUNCDESC)*/ + decoded_size) << 16) | typeinfo->typeinfo->cbSizeVft;
     typedata[4] = (next_idx << 16) | (callconv << 8) | (invokekind << 3) | funckind;
@@ -1427,7 +1425,7 @@ static HRESULT add_func_desc(msft_typeinfo_t* typeinfo, const func_t *func, int
 
         if(defaultdata) *defaultdata = -1;
 
-	encode_var(typeinfo->typelib, arg, paramdata, NULL, NULL, &decoded_size);
+	encode_var(typeinfo->typelib, arg->type, arg, paramdata, NULL, NULL, &decoded_size);
         if (arg->attrs) LIST_FOR_EACH_ENTRY( attr, arg->attrs, const attr_t, entry ) {
             switch(attr->type) {
             case ATTR_DEFAULTVALUE_EXPR:
@@ -1629,7 +1627,7 @@ static HRESULT add_var_desc(msft_typeinfo_t *typeinfo, UINT index, var_t* var)
     typeinfo->var_offsets[var_num] = offset;
 
     /* figure out type widths and whatnot */
-    encode_var(typeinfo->typelib, var, &typedata[1], &var_datawidth,
+    encode_var(typeinfo->typelib, var->type, var, &typedata[1], &var_datawidth,
                &var_alignment, &var_type_size);
 
     /* pad out starting position to data width */



More information about the wine-patches mailing list