Sync to wine-0.9.60:
[reactos.git] / reactos / tools / widl / typegen.c
index ae23f94..32e557f 100644 (file)
@@ -58,6 +58,9 @@ static size_t write_struct_tfs(FILE *file, type_t *type, const char *name, unsig
 static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *type,
                                 const char *name, int write_ptr, unsigned int *tfsoff);
 static const var_t *find_array_or_string_in_struct(const type_t *type);
+static size_t write_string_tfs(FILE *file, const attr_list_t *attrs,
+                               type_t *type,
+                               const char *name, unsigned int *typestring_offset);
 
 const char *string_of_type(unsigned char type)
 {
@@ -165,7 +168,7 @@ static int type_has_pointers(const type_t *type)
     else if (is_struct(type->type))
     {
         const var_t *field;
-        if (type->fields) LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
+        if (type->fields_or_args) LIST_FOR_EACH_ENTRY( field, type->fields_or_args, const var_t, entry )
         {
             if (type_has_pointers(field->type))
                 return TRUE;
@@ -177,11 +180,11 @@ static int type_has_pointers(const type_t *type)
         const var_t *field;
         if (type->type == RPC_FC_ENCAPSULATED_UNION)
         {
-            const var_t *uv = LIST_ENTRY(list_tail(type->fields), const var_t, entry);
-            fields = uv->type->fields;
+            const var_t *uv = LIST_ENTRY(list_tail(type->fields_or_args), const var_t, entry);
+            fields = uv->type->fields_or_args;
         }
         else
-            fields = type->fields;
+            fields = type->fields_or_args;
         if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
         {
             if (field->type && type_has_pointers(field->type))
@@ -205,7 +208,7 @@ static int type_has_full_pointer(const type_t *type)
     else if (is_struct(type->type))
     {
         const var_t *field;
-        if (type->fields) LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
+        if (type->fields_or_args) LIST_FOR_EACH_ENTRY( field, type->fields_or_args, const var_t, entry )
         {
             if (type_has_full_pointer(field->type))
                 return TRUE;
@@ -217,11 +220,11 @@ static int type_has_full_pointer(const type_t *type)
         const var_t *field;
         if (type->type == RPC_FC_ENCAPSULATED_UNION)
         {
-            const var_t *uv = LIST_ENTRY(list_tail(type->fields), const var_t, entry);
-            fields = uv->type->fields;
+            const var_t *uv = LIST_ENTRY(list_tail(type->fields_or_args), const var_t, entry);
+            fields = uv->type->fields_or_args;
         }
         else
-            fields = type->fields;
+            fields = type->fields_or_args;
         if (fields) LIST_FOR_EACH_ENTRY( field, fields, const var_t, entry )
         {
             if (field->type && type_has_full_pointer(field->type))
@@ -415,8 +418,8 @@ void write_parameters_init(FILE *file, int indent, const func_t *func)
 {
     const var_t *var;
 
-    if (!is_void(func->def->type))
-        write_var_init(file, indent, func->def->type, "_RetVal");
+    if (!is_void(get_func_return_type(func)))
+        write_var_init(file, indent, get_func_return_type(func), "_RetVal");
 
     if (!func->args)
         return;
@@ -490,14 +493,16 @@ int decl_indirect(const type_t *t)
             && !is_array(t));
 }
 
-static size_t write_procformatstring_var(FILE *file, int indent,
-                                         const var_t *var, int is_return)
+static size_t write_procformatstring_type(FILE *file, int indent,
+                                          const char *name,
+                                          const type_t *type,
+                                          const attr_list_t *attrs,
+                                          int is_return)
 {
     size_t size;
-    const type_t *type = var->type;
 
-    int is_in = is_attr(var->attrs, ATTR_IN);
-    int is_out = is_attr(var->attrs, ATTR_OUT);
+    int is_in = is_attr(attrs, ATTR_IN);
+    int is_out = is_attr(attrs, ATTR_OUT);
 
     if (!is_in && !is_out) is_in = TRUE;
 
@@ -520,7 +525,7 @@ static size_t write_procformatstring_var(FILE *file, int indent,
         }
         else
         {
-            error("Unknown/unsupported type: %s (0x%02x)\n", var->name, type->type);
+            error("Unknown/unsupported type: %s (0x%02x)\n", name, type->type);
             size = 0;
         }
     }
@@ -570,18 +575,17 @@ void write_procformatstring(FILE *file, const ifref_list_t *ifaces, type_pred_t
                 if (func->args)
                 {
                     LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
-                        write_procformatstring_var(file, indent, var, FALSE);
+                        write_procformatstring_type(file, indent, var->name, var->type, var->attrs, FALSE);
                 }
 
                 /* emit return value data */
-                var = func->def;
-                if (is_void(var->type))
+                if (is_void(get_func_return_type(func)))
                 {
                     print_file(file, indent, "0x5b,    /* FC_END */\n");
                     print_file(file, indent, "0x5c,    /* FC_PAD */\n");
                 }
                 else
-                    write_procformatstring_var(file, indent, var, TRUE);
+                    write_procformatstring_type(file, indent, "return value", get_func_return_type(func), NULL, TRUE);
             }
         }
     }
@@ -706,7 +710,7 @@ static size_t write_conf_or_var_desc(FILE *file, const type_t *structure,
         size_t offset = 0;
         const var_t *var;
 
-        if (structure->fields) LIST_FOR_EACH_ENTRY( var, structure->fields, const var_t, entry )
+        if (structure->fields_or_args) LIST_FOR_EACH_ENTRY( var, structure->fields_or_args, const var_t, entry )
         {
             unsigned int align = 0;
             /* FIXME: take alignment into account */
@@ -921,11 +925,11 @@ size_t type_memsize(const type_t *t, unsigned int *align)
     case RPC_FC_CSTRUCT:
     case RPC_FC_PSTRUCT:
     case RPC_FC_BOGUS_STRUCT:
-        size = fields_memsize(t->fields, align);
+        size = fields_memsize(t->fields_or_args, align);
         break;
     case RPC_FC_ENCAPSULATED_UNION:
     case RPC_FC_NON_ENCAPSULATED_UNION:
-        size = union_memsize(t->fields, align);
+        size = union_memsize(t->fields_or_args, align);
         break;
     case RPC_FC_SMFARRAY:
     case RPC_FC_LGFARRAY:
@@ -945,7 +949,7 @@ size_t type_memsize(const type_t *t, unsigned int *align)
 int is_full_pointer_function(const func_t *func)
 {
     const var_t *var;
-    if (type_has_full_pointer(func->def->type))
+    if (type_has_full_pointer(get_func_return_type(func)))
         return TRUE;
     if (!func->args)
         return FALSE;
@@ -981,27 +985,13 @@ static unsigned int write_nonsimple_pointer(FILE *file, const type_t *type, size
     return 4;
 }
 
-static unsigned char conf_string_type_of_char_type(unsigned char t)
-{
-    switch (t)
-    {
-    case RPC_FC_BYTE:
-    case RPC_FC_CHAR:
-        return RPC_FC_C_CSTRING;
-    case RPC_FC_WCHAR:
-        return RPC_FC_C_WSTRING;
-    }
-
-    error("string_type_of_char_type: unrecognized type %d\n", t);
-    return 0;
-}
-
 static unsigned int write_simple_pointer(FILE *file, const type_t *type)
 {
-    unsigned char fc
-        = is_string_type(type->attrs, type)
-        ? conf_string_type_of_char_type(type->ref->type)
-        : type->ref->type;
+    unsigned char fc = type->ref->type;
+    /* for historical reasons, write_simple_pointer also handled string types,
+     * but no longer does. catch bad uses of the function with this check */
+    if (is_string_type(type->attrs, type))
+        error("write_simple_pointer: can't handle type %s which is a string type\n", type->name);
     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", fc, string_of_type(fc));
@@ -1157,7 +1147,7 @@ static void write_end(FILE *file, unsigned int *tfsoff)
 static void write_descriptors(FILE *file, type_t *type, unsigned int *tfsoff)
 {
     unsigned int offset = 0;
-    var_list_t *fs = type->fields;
+    var_list_t *fs = type->fields_or_args;
     var_t *f;
 
     if (fs) LIST_FOR_EACH_ENTRY(f, fs, var_t, entry)
@@ -1202,7 +1192,12 @@ static int write_no_repeat_pointer_descriptions(
         *typestring_offset += 6;
 
         if (is_ptr(type))
-            write_pointer_tfs(file, type, typestring_offset);
+        {
+            if (is_string_type(type->attrs, type))
+                write_string_tfs(file, NULL, type, NULL, typestring_offset);
+            else
+                write_pointer_tfs(file, type, typestring_offset);
+        }
         else
         {
             unsigned absoff = type->typestring_offset;
@@ -1226,7 +1221,7 @@ static int write_no_repeat_pointer_descriptions(
     if (is_non_complex_struct(type))
     {
         const var_t *v;
-        LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry )
+        LIST_FOR_EACH_ENTRY( v, type->fields_or_args, const var_t, entry )
             written += write_no_repeat_pointer_descriptions(
                 file, v->type,
                 offset_in_memory, offset_in_buffer, typestring_offset);
@@ -1268,7 +1263,9 @@ static int write_pointer_description_offsets(
         }
         *typestring_offset += 4;
 
-        if (processed(type->ref) || is_base_type(type->ref->type))
+        if (is_string_type(attrs, type))
+            write_string_tfs(file, NULL, type, NULL, typestring_offset);
+        else if (processed(type->ref) || is_base_type(type->ref->type))
             write_pointer_tfs(file, type, typestring_offset);
         else
             error("write_pointer_description_offsets: type format string unknown\n");
@@ -1286,7 +1283,7 @@ static int write_pointer_description_offsets(
     {
         /* otherwise search for interesting fields to parse */
         const var_t *v;
-        LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry )
+        LIST_FOR_EACH_ENTRY( v, type->fields_or_args, const var_t, entry )
         {
             written += write_pointer_description_offsets(
                 file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
@@ -1349,7 +1346,7 @@ static int write_fixed_array_pointer_descriptions(
     else if (is_struct(type->type))
     {
         const var_t *v;
-        LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry )
+        LIST_FOR_EACH_ENTRY( v, type->fields_or_args, const var_t, entry )
         {
             pointer_count += write_fixed_array_pointer_descriptions(
                 file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
@@ -1460,7 +1457,7 @@ static int write_varying_array_pointer_descriptions(
     else if (is_struct(type->type))
     {
         const var_t *v;
-        LIST_FOR_EACH_ENTRY( v, type->fields, const var_t, entry )
+        LIST_FOR_EACH_ENTRY( v, type->fields_or_args, const var_t, entry )
         {
             pointer_count += write_varying_array_pointer_descriptions(
                 file, v->attrs, v->type, offset_in_memory, offset_in_buffer,
@@ -1535,18 +1532,18 @@ int is_declptr(const type_t *t)
 
 static size_t write_string_tfs(FILE *file, const attr_list_t *attrs,
                                type_t *type,
-                               const char *name, unsigned int *typestring_offset,
-                               int toplevel)
+                               const char *name, unsigned int *typestring_offset)
 {
     size_t start_offset;
     unsigned char rtype;
 
-    if (toplevel && is_declptr(type))
+    if (is_declptr(type))
     {
         unsigned char flag = is_conformant_array(type) ? 0 : RPC_FC_P_SIMPLEPOINTER;
         int pointer_type = is_ptr(type) ? type->type : get_attrv(attrs, ATTR_POINTERTYPE);
         if (!pointer_type)
             pointer_type = RPC_FC_RP;
+        print_start_tfs_comment(file, type, *typestring_offset);
         print_file(file, 2,"0x%x, 0x%x,\t/* %s%s */\n",
                    pointer_type, flag, string_of_type(pointer_type),
                    flag ? " [simple_pointer]" : "");
@@ -1733,7 +1730,7 @@ static size_t write_array_tfs(FILE *file, const attr_list_t *attrs, type_t *type
 
 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 );
+    const var_t *last_field = LIST_ENTRY( list_tail(type->fields_or_args), const var_t, entry );
     const type_t *ft = last_field->type;
 
     if (ft->declarray && is_conformant_array(ft))
@@ -1753,7 +1750,7 @@ static void write_struct_members(FILE *file, const type_t *type,
     int salign = -1;
     int padding;
 
-    if (type->fields) LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
+    if (type->fields_or_args) LIST_FOR_EACH_ENTRY( field, type->fields_or_args, const var_t, entry )
     {
         type_t *ft = field->type;
         if (!ft->declarray || !is_conformant_array(ft))
@@ -1819,7 +1816,7 @@ static size_t write_struct_tfs(FILE *file, type_t *type,
         error("structure size for %s exceeds %d bytes by %d bytes\n",
               name, USHRT_MAX, total_size - USHRT_MAX);
 
-    if (type->fields) LIST_FOR_EACH_ENTRY(f, type->fields, var_t, entry)
+    if (type->fields_or_args) LIST_FOR_EACH_ENTRY(f, type->fields_or_args, var_t, entry)
         has_pointers |= write_embedded_types(file, f->attrs, f->type, f->name,
                                              FALSE, tfsoff);
     if (!has_pointers) has_pointers = type_has_pointers(type);
@@ -1828,7 +1825,7 @@ static size_t write_struct_tfs(FILE *file, type_t *type,
     if (array && !processed(array->type))
         array_offset
             = is_attr(array->attrs, ATTR_STRING)
-            ? write_string_tfs(file, array->attrs, array->type, array->name, tfsoff, FALSE)
+            ? write_string_tfs(file, array->attrs, array->type, array->name, tfsoff)
             : write_array_tfs(file, array->attrs, array->type, array->name, tfsoff);
 
     corroff = *tfsoff;
@@ -1883,7 +1880,7 @@ static size_t write_struct_tfs(FILE *file, type_t *type,
 
     if (type->type == RPC_FC_BOGUS_STRUCT)
     {
-        const var_list_t *fs = type->fields;
+        const var_list_t *fs = type->fields_or_args;
         const var_t *f;
 
         type->ptrdesc = *tfsoff;
@@ -1891,7 +1888,12 @@ static size_t write_struct_tfs(FILE *file, type_t *type,
         {
             type_t *ft = f->type;
             if (is_ptr(ft))
-                write_pointer_tfs(file, ft, tfsoff);
+            {
+                if (is_string_type(f->attrs, ft))
+                    write_string_tfs(file, f->attrs, ft, f->name, tfsoff);
+                else
+                    write_pointer_tfs(file, ft, tfsoff);
+            }
             else if (!ft->declarray && is_conformant_array(ft))
             {
                 unsigned int absoff = ft->typestring_offset;
@@ -1988,11 +1990,11 @@ static size_t write_union_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
 
     if (type->type == RPC_FC_ENCAPSULATED_UNION)
     {
-        const var_t *uv = LIST_ENTRY(list_tail(type->fields), const var_t, entry);
-        fields = uv->type->fields;
+        const var_t *uv = LIST_ENTRY(list_tail(type->fields_or_args), const var_t, entry);
+        fields = uv->type->fields_or_args;
     }
     else
-        fields = type->fields;
+        fields = type->fields_or_args;
 
     if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
     {
@@ -2008,7 +2010,7 @@ static size_t write_union_tfs(FILE *file, type_t *type, unsigned int *tfsoff)
     print_start_tfs_comment(file, type, start_offset);
     if (type->type == RPC_FC_ENCAPSULATED_UNION)
     {
-        const var_t *sv = LIST_ENTRY(list_head(type->fields), const var_t, entry);
+        const var_t *sv = LIST_ENTRY(list_head(type->fields_or_args), const var_t, entry);
         const type_t *st = sv->type;
 
         switch (st->type)
@@ -2181,8 +2183,8 @@ static size_t write_typeformatstring_var(FILE *file, int indent, const func_t *f
         return type->typestring_offset;
     }
 
-    if ((last_ptr(type) || last_array(type)) && is_ptrchain_attr(var, ATTR_STRING))
-        return write_string_tfs(file, var->attrs, type, var->name, typeformat_offset, TRUE);
+    if (is_string_type(var->attrs, type))
+        return write_string_tfs(file, var->attrs, type, var->name, typeformat_offset);
 
     if (is_array(type))
     {
@@ -2286,6 +2288,10 @@ static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *ty
     {
         write_user_tfs(file, type, tfsoff);
     }
+    else if (is_string_type(attrs, type))
+    {
+        write_string_tfs(file, attrs, type, name, tfsoff);
+    }
     else if (is_ptr(type))
     {
         type_t *ref = type->ref;
@@ -2307,10 +2313,6 @@ static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *ty
             retmask |= 1;
         }
     }
-    else if (last_array(type) && is_attr(attrs, ATTR_STRING))
-    {
-        write_string_tfs(file, attrs, type, name, tfsoff, FALSE);
-    }
     else if (type->declarray && is_conformant_array(type))
         ;    /* conformant arrays and strings are handled specially */
     else if (is_array(type))
@@ -2355,12 +2357,16 @@ static size_t process_tfs(FILE *file, const ifref_list_t *ifaces, type_pred_t pr
             {
                 if (is_local(func->def->attrs)) continue;
 
-                if (!is_void(func->def->type))
-                    update_tfsoff(func->def->type,
+                if (!is_void(get_func_return_type(func)))
+                {
+                    var_t v = *func->def;
+                    v.type = get_func_return_type(func);
+                    update_tfsoff(get_func_return_type(func),
                                   write_typeformatstring_var(
-                                      file, 2, NULL, func->def->type,
-                                      func->def, &typeformat_offset),
+                                      file, 2, NULL, get_func_return_type(func),
+                                      &v, &typeformat_offset),
                                   file);
+                }
 
                 current_func = func;
                 if (func->args)
@@ -2452,8 +2458,8 @@ static unsigned int get_required_buffer_size_type(
         {
             size_t size = 0;
             const var_t *field;
-            if (!type->fields) return 0;
-            LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
+            if (!type->fields_or_args) return 0;
+            LIST_FOR_EACH_ENTRY( field, type->fields_or_args, const var_t, entry )
             {
                 unsigned int alignment;
                 size += get_required_buffer_size_type(field->type, field->name,
@@ -2507,8 +2513,8 @@ static unsigned int get_required_buffer_size(const var_t *var, unsigned int *ali
                 const var_t *field;
                 unsigned int size = 36;
 
-                if (!type->fields) return size;
-                LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
+                if (!type->fields_or_args) return size;
+                LIST_FOR_EACH_ENTRY( field, type->fields_or_args, const var_t, entry )
                 {
                     unsigned int align;
                     size += get_required_buffer_size_type(
@@ -2537,8 +2543,8 @@ static unsigned int get_required_buffer_size(const var_t *var, unsigned int *ali
                     unsigned int size = 36;
                     const var_t *field;
 
-                    if (!type->fields) return size;
-                    LIST_FOR_EACH_ENTRY( field, type->fields, const var_t, entry )
+                    if (!type->fields_or_args) return size;
+                    LIST_FOR_EACH_ENTRY( field, type->fields_or_args, const var_t, entry )
                     {
                         unsigned int align;
                         size += get_required_buffer_size_type(
@@ -2567,9 +2573,11 @@ static unsigned int get_function_buffer_size( const func_t *func, enum pass pass
         }
     }
 
-    if (pass == PASS_OUT && !is_void(func->def->type))
+    if (pass == PASS_OUT && !is_void(get_func_return_type(func)))
     {
-        total_size += get_required_buffer_size(func->def, &alignment, PASS_RETURN);
+        var_t v = *func->def;
+        v.type = get_func_return_type(func);
+        total_size += get_required_buffer_size(&v, &alignment, PASS_RETURN);
         total_size += alignment;
     }
     return total_size;
@@ -2778,9 +2786,13 @@ static void write_remoting_arg(FILE *file, int indent, const func_t *func,
         {
             if (pass == PASS_IN)
             {
+                /* if the context_handle attribute appears in the chain of types
+                 * without pointers being followed, then the context handle must
+                 * be direct, otherwise it is a pointer */
+                int is_ch_ptr = is_aliaschain_attr(type, ATTR_CONTEXTHANDLE) ? FALSE : TRUE;
                 print_file(file, indent, "NdrClientContextMarshall(\n");
                 print_file(file, indent + 1, "&_StubMsg,\n");
-                print_file(file, indent + 1, "(NDR_CCONTEXT)%s%s,\n", is_ptr(type) ? "*" : "", var->name);
+                print_file(file, indent + 1, "(NDR_CCONTEXT)%s%s,\n", is_ch_ptr ? "*" : "", var->name);
                 print_file(file, indent + 1, "%s);\n", in_attr && out_attr ? "1" : "0");
             }
             else
@@ -3008,6 +3020,7 @@ void write_remoting_arguments(FILE *file, int indent, const func_t *func,
     {
         var_t var;
         var = *func->def;
+        var.type = get_func_return_type(func);
         var.name = xstrdup( "_RetVal" );
         write_remoting_arg( file, indent, func, pass, phase, &var );
         free( var.name );
@@ -3023,9 +3036,9 @@ void write_remoting_arguments(FILE *file, int indent, const func_t *func,
 }
 
 
-size_t get_size_procformatstring_var(const var_t *var)
+size_t get_size_procformatstring_type(const char *name, const type_t *type, const attr_list_t *attrs)
 {
-    return write_procformatstring_var(NULL, 0, var, FALSE);
+    return write_procformatstring_type(NULL, 0, name, type, attrs, FALSE);
 }
 
 
@@ -3037,13 +3050,13 @@ size_t get_size_procformatstring_func(const func_t *func)
     /* argument list size */
     if (func->args)
         LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
-            size += get_size_procformatstring_var(var);
+            size += get_size_procformatstring_type(var->name, var->type, var->attrs);
 
     /* return value size */
-    if (is_void(func->def->type))
+    if (is_void(get_func_return_type(func)))
         size += 2; /* FC_END and FC_PAD */
     else
-        size += get_size_procformatstring_var(func->def);
+        size += get_size_procformatstring_type("return value", get_func_return_type(func), NULL);
 
     return size;
 }
@@ -3175,14 +3188,13 @@ void declare_stub_args( FILE *file, int indent, const func_t *func )
 {
     int in_attr, out_attr;
     int i = 0;
-    const var_t *def = func->def;
     const var_t *var;
 
     /* declare return value '_RetVal' */
-    if (!is_void(def->type))
+    if (!is_void(get_func_return_type(func)))
     {
         print_file(file, indent, "");
-        write_type_decl_left(file, def->type);
+        write_type_decl_left(file, get_func_return_type(func));
         fprintf(file, " _RetVal;\n");
     }
 
@@ -3299,7 +3311,7 @@ int write_expr_eval_routines(FILE *file, const char *iface)
     LIST_FOR_EACH_ENTRY(eval, &expr_eval_routines, struct expr_eval_routine, entry)
     {
         const char *name = eval->structure->name;
-        const var_list_t *fields = eval->structure->fields;
+        const var_list_t *fields = eval->structure->fields_or_args;
         result = 1;
 
         print_file(file, 0, "static void __RPC_USER %s_%sExprEval_%04u(PMIDL_STUB_MESSAGE pStubMsg)\n",