widl: Simplify correlation descriptor code

Dan Hipschman dsh at linux.ucla.edu
Mon Jun 11 20:51:41 CDT 2007


This simplifies the code to write correlation descriptors, needed for
unions and conformant / varying arrays.  It removes a field from the var_t
structure which I added a while ago to get unions working.  I've since
thought of a cleaner way to do things.  It allows factorization, and
fixes a bug.  New tests are added (passing in wine and on XP).

---
 dlls/rpcrt4/tests/server.c   |   24 ++++
 dlls/rpcrt4/tests/server.idl |    9 ++
 tools/widl/parser.y          |    1 -
 tools/widl/typegen.c         |  238 ++++++++++++++++++------------------------
 tools/widl/widltypes.h       |    1 -
 5 files changed, 135 insertions(+), 138 deletions(-)

diff --git a/dlls/rpcrt4/tests/server.c b/dlls/rpcrt4/tests/server.c
index 76d6f01..b65dc91 100644
--- a/dlls/rpcrt4/tests/server.c
+++ b/dlls/rpcrt4/tests/server.c
@@ -210,6 +210,21 @@ s_sum_cs(cs_t *cs)
   return s_sum_conf_array(cs->ca, cs->n);
 }
 
+int
+s_sum_cps(cps_t *cps)
+{
+  int sum = 0;
+  int i;
+
+  for (i = 0; i < *cps->pn; ++i)
+    sum += cps->ca1[i];
+
+  for (i = 0; i < 2 * cps->n; ++i)
+    sum += cps->ca2[i];
+
+  return sum;
+}
+
 void
 s_stop(void)
 {
@@ -393,7 +408,9 @@ array_tests(void)
   };
   static int c[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
   static vector_t vs[2] = {{1, -2, 3}, {4, -5, -6}};
+  cps_t cps;
   cs_t *cs;
+  int n;
 
   ok(sum_fixed_int_3d(m) == 4116, "RPC sum_fixed_int_3d\n");
 
@@ -417,6 +434,13 @@ array_tests(void)
   cs->ca[4] = -4;
   ok(sum_cs(cs) == 1, "RPC sum_cs\n");
   HeapFree(GetProcessHeap(), 0, cs);
+
+  n = 5;
+  cps.pn = &n;
+  cps.ca1 = &c[2];
+  cps.n = 3;
+  cps.ca2 = &c[3];
+  ok(sum_cps(&cps) == 53, "RPC sum_cps\n");
 }
 
 static void
diff --git a/dlls/rpcrt4/tests/server.idl b/dlls/rpcrt4/tests/server.idl
index 213a883..a7b3df7 100644
--- a/dlls/rpcrt4/tests/server.idl
+++ b/dlls/rpcrt4/tests/server.idl
@@ -119,7 +119,16 @@ interface IServer
     [size_is(n)] int ca[];
   } cs_t;
 
+  typedef struct
+  {
+    int *pn;
+    [size_is(*pn)] int *ca1;
+    [size_is(n * 2)] int *ca2;
+    int n;
+  } cps_t;
+
   int sum_cs(cs_t *cs);
+  int sum_cps(cps_t *cps);
 
   void stop(void);
 }
diff --git a/tools/widl/parser.y b/tools/widl/parser.y
index b5c1865..b582673 100644
--- a/tools/widl/parser.y
+++ b/tools/widl/parser.y
@@ -1387,7 +1387,6 @@ static var_t *make_var(char *name)
   v->args = NULL;
   v->attrs = NULL;
   v->eval = NULL;
-  v->corrdesc = 0;
   return v;
 }
 
diff --git a/tools/widl/typegen.c b/tools/widl/typegen.c
index 8f4c926..ab2f1a4 100644
--- a/tools/widl/typegen.c
+++ b/tools/widl/typegen.c
@@ -62,7 +62,7 @@ struct expr_eval_routine
 static size_t fields_memsize(const var_list_t *fields, unsigned int *align);
 static size_t write_struct_tfs(FILE *file, type_t *type, const char *name, unsigned int *tfsoff);
 static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *type,
-                                const char *name, int level, unsigned int *tfsoff);
+                                const char *name, int write_ptr, unsigned int *tfsoff);
 
 const char *string_of_type(unsigned char type)
 {
@@ -160,32 +160,6 @@ static int is_embedded_complex(const type_t *type)
     return is_struct(tc) || is_union(tc) || is_array(type);
 }
 
-static long field_offset(const type_t *strct, const char *name, var_t **pfield)
-{
-    long offset = 0;
-    var_list_t *fields = strct->fields;
-    var_t *f;
-
-    if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
-    {
-        unsigned int align = 0;
-
-        if (f->name != NULL && strcmp(name, f->name) == 0)
-        {
-            if (pfield) *pfield = f;
-            return offset;
-        }
-        else
-        {
-            /* FIXME: handle possible padding */
-            offset += type_memsize(f->type, &align);
-        }
-    }
-
-    if (pfield) *pfield = NULL;
-    return -1;
-}
-
 static int compare_expr(const expr_t *a, const expr_t *b)
 {
     int ret;
@@ -442,7 +416,8 @@ static int write_base_type(FILE *file, const type_t *type, unsigned int *typestr
 }
 
 /* write conformance / variance descriptor */
-static size_t write_conf_or_var_desc(FILE *file, const func_t *func, const type_t *structure, const expr_t *expr)
+static size_t write_conf_or_var_desc(FILE *file, const func_t *func, const type_t *structure,
+                                     unsigned int baseoff, const expr_t *expr)
 {
     unsigned char operator_type = 0;
     const char *operator_string = "no operators";
@@ -526,18 +501,19 @@ 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, &align);
                 /* FIXME: take alignment into account */
                 if (!strcmp(var->name, subexpr->u.sval))
                 {
                     correlation_variable = var->type;
                     break;
                 }
+                offset += type_memsize(var->type, &align);
             }
             if (!correlation_variable)
                 error("write_conf_or_var_desc: couldn't find variable %s in structure\n",
                       subexpr->u.sval);
 
+            offset -= baseoff;
             correlation_type = RPC_FC_NORMAL_CONFORMANCE;
         }
         else
@@ -819,7 +795,7 @@ static int processed(const type_t *type)
 }
 
 static void write_member_type(FILE *file, type_t *type, const var_t *field,
-                              unsigned int *tfsoff)
+                              unsigned int *corroff, unsigned int *tfsoff)
 {
     if (is_ptr(type))
     {
@@ -828,10 +804,19 @@ static void write_member_type(FILE *file, type_t *type, const var_t *field,
     }
     else if (is_embedded_complex(type))
     {
-        size_t absoff = (field && field->corrdesc
-                         ? field->corrdesc
-                         : type->typestring_offset);
-        short reloff = absoff - (*tfsoff + 2);
+        size_t absoff;
+        short reloff;
+
+        if (is_union(type->type) && is_attr(field->attrs, ATTR_SWITCHIS))
+        {
+            absoff = *corroff;
+            *corroff += 8;
+        }
+        else
+        {
+            absoff = type->typestring_offset;
+        }
+        reloff = absoff - (*tfsoff + 2);
 
         print_file(file, 2, "0x4c,\t/* FC_EMBEDDED_COMPLEX */\n");
         /* FIXME: actually compute necessary padding */
@@ -855,6 +840,35 @@ static void write_end(FILE *file, unsigned int *tfsoff)
     *tfsoff += 1;
 }
 
+static void write_descriptors(FILE *file, type_t *type, unsigned int *tfsoff)
+{
+    unsigned int offset = 0;
+    var_list_t *fs = type->fields;
+    var_t *f;
+
+    if (fs) LIST_FOR_EACH_ENTRY(f, fs, var_t, entry)
+    {
+        unsigned int align = 0;
+        type_t *ft = f->type;
+        if (is_union(ft->type) && is_attr(f->attrs, ATTR_SWITCHIS))
+        {
+            unsigned int absoff = ft->typestring_offset;
+            short reloff = absoff - (*tfsoff + 6);
+            print_file(file, 0, "/* %d */\n", *tfsoff);
+            print_file(file, 2, "0x%x,\t/* %s */\n", ft->type, string_of_type(ft->type));
+            print_file(file, 2, "0x%x,\t/* FIXME: always FC_LONG */\n", RPC_FC_LONG);
+            write_conf_or_var_desc(file, current_func, current_structure, offset,
+                                   get_attrp(f->attrs, ATTR_SWITCHIS));
+            print_file(file, 2, "NdrFcShort(%hd),\t/* Offset= %hd (%u) */\n",
+                       reloff, reloff, absoff);
+            *tfsoff += 8;
+        }
+
+        /* FIXME: take alignment into account */
+        offset += type_memsize(ft, &align);
+    }
+}
+
 static size_t write_pointer_description(FILE *file, type_t *type, size_t mem_offset,
                                         int level, unsigned int *typestring_offset)
 {
@@ -959,6 +973,8 @@ static size_t write_string_tfs(FILE *file, const attr_list_t *attrs,
     }
     else if (type->size_is)
     {
+        unsigned int align = 0;
+
         if (rtype == RPC_FC_CHAR)
             WRITE_FCTYPE(file, FC_C_CSTRING, *typestring_offset);
         else
@@ -966,7 +982,12 @@ static size_t write_string_tfs(FILE *file, const attr_list_t *attrs,
         print_file(file, 2, "0x%x, /* FC_STRING_SIZED */\n", RPC_FC_STRING_SIZED);
         *typestring_offset += 2;
 
-        *typestring_offset += write_conf_or_var_desc(file, current_func, NULL, type->size_is);
+        *typestring_offset += write_conf_or_var_desc(
+            file, current_func, current_structure,
+            (type->declarray && current_structure
+             ? type_memsize(current_structure, &align)
+             : 0),
+            type->size_is);
 
         return start_offset;
     }
@@ -997,7 +1018,7 @@ static size_t write_array_tfs(FILE *file, const attr_list_t *attrs, type_t *type
         pointer_type = RPC_FC_RP;
 
     has_pointer = FALSE;
-    if (write_embedded_types(file, attrs, type, name, 0, typestring_offset))
+    if (write_embedded_types(file, attrs, type->ref, name, FALSE, typestring_offset))
         has_pointer = TRUE;
 
     size = type_memsize(type, &align);
@@ -1011,9 +1032,14 @@ static size_t write_array_tfs(FILE *file, const attr_list_t *attrs, type_t *type
     print_file(file, 2, "0x%x,\t/* %d */\n", align - 1, align - 1);
     *typestring_offset += 2;
 
+    align = 0;
     if (type->type != RPC_FC_BOGUS_ARRAY)
     {
         unsigned char tc = type->type;
+        unsigned int baseoff
+            = type->declarray && current_structure
+            ? type_memsize(current_structure, &align)
+            : 0;
 
         if (tc == RPC_FC_LGFARRAY || tc == RPC_FC_LGVARRAY)
         {
@@ -1028,8 +1054,8 @@ static size_t write_array_tfs(FILE *file, const attr_list_t *attrs, type_t *type
 
         if (is_conformant_array(type))
             *typestring_offset
-                += write_conf_or_var_desc(file, current_func,
-                                          current_structure, size_is);
+                += write_conf_or_var_desc(file, current_func, current_structure,
+                                          baseoff, size_is);
 
         if (type->type == RPC_FC_SMVARRAY || type->type == RPC_FC_LGVARRAY)
         {
@@ -1053,8 +1079,8 @@ static size_t write_array_tfs(FILE *file, const attr_list_t *attrs, type_t *type
 
         if (length_is)
             *typestring_offset
-                += write_conf_or_var_desc(file, current_func,
-                                          current_structure, length_is);
+                += write_conf_or_var_desc(file, current_func, current_structure,
+                                          baseoff, length_is);
 
         if (has_pointer)
         {
@@ -1066,7 +1092,7 @@ static size_t write_array_tfs(FILE *file, const attr_list_t *attrs, type_t *type
             *typestring_offset += 1;
         }
 
-        write_member_type(file, type->ref, NULL, typestring_offset);
+        write_member_type(file, type->ref, NULL, NULL, typestring_offset);
         write_end(file, typestring_offset);
     }
     else
@@ -1089,7 +1115,8 @@ static const var_t *find_array_or_string_in_struct(const type_t *type)
         return NULL;
 }
 
-static void write_struct_members(FILE *file, const type_t *type, unsigned int *typestring_offset)
+static void write_struct_members(FILE *file, const type_t *type,
+                                 unsigned int *corroff, unsigned int *typestring_offset)
 {
     const var_t *field;
 
@@ -1097,7 +1124,7 @@ static void write_struct_members(FILE *file, const type_t *type, unsigned int *t
     {
         type_t *ft = field->type;
         if (!ft->declarray || !is_conformant_array(ft))
-            write_member_type(file, ft, field, typestring_offset);
+            write_member_type(file, ft, field, corroff, typestring_offset);
     }
 
     write_end(file, typestring_offset);
@@ -1106,32 +1133,37 @@ static void write_struct_members(FILE *file, const type_t *type, unsigned int *t
 static size_t write_struct_tfs(FILE *file, type_t *type,
                                const char *name, unsigned int *tfsoff)
 {
+    const type_t *save_current_structure = current_structure;
     unsigned int total_size;
     const var_t *array;
     size_t start_offset;
     size_t array_offset;
     int has_pointers;
     unsigned int align = 0;
+    unsigned int corroff;
+    var_t *f;
 
     guard_rec(type);
+    current_structure = type;
 
     total_size = type_memsize(type, &align);
     if (total_size > USHRT_MAX)
         error("structure size for %s exceeds %d bytes by %d bytes\n",
               name, USHRT_MAX, total_size - USHRT_MAX);
 
-    has_pointers = write_embedded_types(file, NULL, type, name, 0, tfsoff);
+    if (type->fields) LIST_FOR_EACH_ENTRY(f, type->fields, var_t, entry)
+        has_pointers |= write_embedded_types(file, f->attrs, f->type, f->name,
+                                             FALSE, tfsoff);
 
     array = find_array_or_string_in_struct(type);
     if (array && !processed(array->type))
-    {
-        current_structure = type;
         array_offset
             = is_attr(array->attrs, ATTR_STRING)
             ? write_string_tfs(file, array->attrs, array->type, array->name, tfsoff)
             : write_array_tfs(file, array->attrs, array->type, array->name, tfsoff);
-        current_structure = NULL;
-    }
+
+    corroff = *tfsoff;
+    write_descriptors(file, type, tfsoff);
 
     start_offset = *tfsoff;
     update_tfsoff(type, start_offset, file);
@@ -1171,10 +1203,9 @@ static size_t write_struct_tfs(FILE *file, type_t *type,
         *tfsoff += 1;
     }
 
-    current_structure = type;
-    write_struct_members(file, type, tfsoff);
-    current_structure = NULL;
+    write_struct_members(file, type, &corroff, tfsoff);
 
+    current_structure = save_current_structure;
     return start_offset;
 }
 
@@ -1230,8 +1261,7 @@ static void write_branch_type(FILE *file, const type_t *t, unsigned int *tfsoff)
     *tfsoff += 2;
 }
 
-static size_t write_union_tfs(FILE *file, type_t *type, const char *name,
-                              unsigned int *tfsoff)
+static size_t write_union_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
 {
     unsigned int align = 0;
     unsigned int start_offset;
@@ -1244,14 +1274,13 @@ static size_t write_union_tfs(FILE *file, type_t *type, const char *name,
 
     guard_rec(type);
 
-    /* use a level of 1 so pointers always get written */
-    write_embedded_types(file, NULL, type, name, 1, tfsoff);
-
     if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
     {
         expr_list_t *cases = get_attrp(f->attrs, ATTR_CASE);
         if (cases)
             nbranch += list_count(cases);
+        if (f->type)
+            write_embedded_types(file, f->attrs, f->type, f->name, TRUE, tfsoff);
     }
 
     start_offset = *tfsoff;
@@ -1321,7 +1350,7 @@ static size_t write_ip_tfs(FILE *file, const func_t *func, const type_t *type, c
         expr.is_const = FALSE;
         print_file(file, 2, "0x2f,  /* FC_IP */\n");
         print_file(file, 2, "0x5c,  /* FC_PAD */\n");
-        *typeformat_offset += write_conf_or_var_desc(file, func, NULL, &expr) + 2;
+        *typeformat_offset += write_conf_or_var_desc(file, func, NULL, 0, &expr) + 2;
     }
     else
     {
@@ -1404,7 +1433,7 @@ static size_t write_typeformatstring_var(FILE *file, int indent, const func_t *f
             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, type, var->name, typeformat_offset);
+            return write_union_tfs(file, type, typeformat_offset);
         case RPC_FC_IGNORE:
         case RPC_FC_BIND_PRIMITIVE:
             /* nothing to do */
@@ -1475,92 +1504,19 @@ static void set_tfswrite(type_t *type, int val)
 }
 
 static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *type,
-                                const char *name, int level, unsigned int *tfsoff)
+                                const char *name, int write_ptr, unsigned int *tfsoff)
 {
-    var_list_t *fields = type->fields;
     int retmask = 0;
-    size_t offset = 0;
-    var_t *f;
-
-    if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
-    {
-        unsigned int align = 0;
-        type_t *ft = f->type;
-
-        if (!ft) continue;
-        else if (ft->type == RPC_FC_NON_ENCAPSULATED_UNION)
-        {
-            expr_t *swexp = get_attrp(f->attrs, ATTR_SWITCHIS);
-            const char *swname;
-            var_t *swvar;
-            size_t corroff;
-            unsigned char corrdesc, op = 0;
-            short creloff, ureloff;
-
-            if (swexp == NULL)
-                error("union %s needs a switch_is attribute\n", f->name);
-            if (swexp->type != EXPR_IDENTIFIER)
-                error("%s: only identifiers are supported for switch_is at this time\n",
-                      f->name);
-
-            if (!processed(ft))
-                write_union_tfs(file, ft, f->name, tfsoff);
-
-            swname = swexp->u.sval;
-            corroff = field_offset(type, swname, &swvar);
-            corrdesc = swvar->type->type;
-            creloff = corroff - offset;
-
-            f->corrdesc = *tfsoff;
-            ureloff = ft->typestring_offset - (f->corrdesc + 6);
-            print_file(file, 0, "/* %d */\n", f->corrdesc);
-            print_file(file, 2, "0x%x,\t/* %s */\n", ft->type, string_of_type(ft->type));
-            print_file(file, 2, "0x8,\t/* FIXME: support other switch types */\n");
-            print_file(file, 2, "0x%x,\t/* Corr desc: %s */\n",
-                       corrdesc, string_of_type(corrdesc & 0xf));
-            print_file(file, 2, "0x%x,\n", op);
-            print_file(file, 2, "NdrFcShort(0x%hx),\t/* %hd */\n", creloff, creloff);
-            print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n",
-                       ureloff, ureloff, ft->typestring_offset);
-            *tfsoff += 8;
-        }
-        else
-            retmask |= write_embedded_types(file, attrs, ft, f->name,
-                                            level + 1, tfsoff);
 
-        /* FIXME: this doesn't take alignment/padding into account */
-        offset += type_memsize(ft, &align);
-    }
-    /* don't generate a pointer for first-level arrays since we want to
-       descend into them to write their pointers, not stop here */
-    else if (level == 0 && is_array(type))
-    {
-        return write_embedded_types(file, NULL, type->ref, name, level + 1, tfsoff);
-    }
-    else if (is_ptr(type))
+    if (is_ptr(type))
     {
         type_t *ref = type->ref;
 
         if (!processed(ref) && !is_base_type(ref->type))
-        {
-            if (is_ptr(ref))
-            {
-                retmask |= write_embedded_types(file, attrs, ref, name,
-                                                level + 1, tfsoff);
-            }
-            else if (is_struct(ref->type))
-            {
-                write_struct_tfs(file, ref, name, tfsoff);
-            }
-            else
-            {
-                error("write_embedded_types: type format string unknown for %s (0x%x)\n",
-                      name, ref->type);
-            }
-        }
+            retmask |= write_embedded_types(file, NULL, ref, name, TRUE, tfsoff);
 
-        /* top-level pointers are handled inline */
-        if (1 < level)
+        /* top-level pointers are handled inline for structures */
+        if (write_ptr)
             write_pointer_tfs(file, type, tfsoff);
 
         retmask |= 1;
@@ -1571,6 +1527,16 @@ static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *ty
     {
         write_array_tfs(file, attrs, type, name, tfsoff);
     }
+    else if (is_struct(type->type))
+    {
+        if (!processed(type))
+            write_struct_tfs(file, type, name, tfsoff);
+    }
+    else if (is_union(type->type))
+    {
+        if (!processed(type))
+            write_union_tfs(file, type, tfsoff);
+    }
     else if (!is_base_type(type->type))
         error("write_embedded_types: unknown embedded type for %s (0x%x)\n",
               name, type->type);
diff --git a/tools/widl/widltypes.h b/tools/widl/widltypes.h
index 0c8acad..0fe453b 100644
--- a/tools/widl/widltypes.h
+++ b/tools/widl/widltypes.h
@@ -227,7 +227,6 @@ struct _var_t {
   var_list_t *args;  /* for function pointers */
   attr_list_t *attrs;
   expr_t *eval;
-  size_t corrdesc;  /* offset to correlation descriptor (e.g., for unions) */
 
   /* parser-internal */
   struct list entry;



More information about the wine-patches mailing list