widl: Allow types that reference themselves.

This commit is contained in:
Dan Hipschman 2007-05-24 17:50:02 -07:00 committed by Alexandre Julliard
parent 9c30da77ba
commit 8f7a5d63ec
6 changed files with 111 additions and 21 deletions

View File

@ -154,6 +154,14 @@ s_square_sun(sun_t *sun)
} }
} }
int
s_test_list_length(test_list_t *list)
{
return (list->t == TL_LIST
? 1 + s_test_list_length(list->u.tail)
: 0);
}
void void
s_stop(void) s_stop(void)
{ {
@ -292,6 +300,41 @@ union_tests(void)
ok(square_sun(&sun) == 121.0, "RPC square_sun\n"); ok(square_sun(&sun) == 121.0, "RPC square_sun\n");
} }
static test_list_t *
null_list(void)
{
test_list_t *n = HeapAlloc(GetProcessHeap(), 0, sizeof *n);
n->t = TL_NULL;
return n;
}
static test_list_t *
make_list(test_list_t *tail)
{
test_list_t *n = HeapAlloc(GetProcessHeap(), 0, sizeof *n);
n->t = TL_LIST;
n->u.tail = tail;
return n;
}
static void
free_list(test_list_t *list)
{
if (list->t == TL_LIST)
free_list(list->u.tail);
HeapFree(GetProcessHeap(), 0, list);
}
static void
pointer_tests(void)
{
test_list_t *list = make_list(make_list(make_list(null_list())));
ok(test_list_length(list) == 3, "RPC test_list_length\n");
free_list(list);
}
static void static void
client(const char *test) client(const char *test)
{ {
@ -307,6 +350,7 @@ client(const char *test)
basic_tests(); basic_tests();
union_tests(); union_tests();
pointer_tests();
ok(RPC_S_OK == RpcStringFree(&binding), "RpcStringFree\n"); ok(RPC_S_OK == RpcStringFree(&binding), "RpcStringFree\n");
ok(RPC_S_OK == RpcBindingFree(&IServer_IfHandle), "RpcBindingFree\n"); ok(RPC_S_OK == RpcBindingFree(&IServer_IfHandle), "RpcBindingFree\n");
@ -323,6 +367,7 @@ client(const char *test)
basic_tests(); basic_tests();
union_tests(); union_tests();
pointer_tests();
stop(); stop();
ok(RPC_S_OK == RpcStringFree(&binding), "RpcStringFree\n"); ok(RPC_S_OK == RpcStringFree(&binding), "RpcStringFree\n");

View File

@ -96,5 +96,17 @@ interface IServer
int sum_sp(sp_t *sp); int sum_sp(sp_t *sp);
double square_sun(sun_t *sun); double square_sun(sun_t *sun);
typedef struct test_list
{
int t;
[switch_is(t)] union
{
[case(TL_NULL)] int x; /* end of list */
[case(TL_LIST)] struct test_list *tail;
} u;
} test_list_t;
int test_list_length(test_list_t *ls);
void stop(void); void stop(void);
} }

View File

@ -23,3 +23,7 @@
#define SUN_F1 -2 #define SUN_F1 -2
#define SUN_F2 7 #define SUN_F2 7
#define SUN_PI 399 #define SUN_PI 399
/* test_list_t case values */
#define TL_NULL 0
#define TL_LIST 1

View File

@ -1206,6 +1206,7 @@ static type_t *make_type(unsigned char type, type_t *ref)
t->defined = FALSE; t->defined = FALSE;
t->written = FALSE; t->written = FALSE;
t->user_types_registered = FALSE; t->user_types_registered = FALSE;
t->tfswrite = FALSE;
t->typelib_idx = -1; t->typelib_idx = -1;
return t; return t;
} }

View File

@ -132,6 +132,23 @@ static int is_union(unsigned char type)
} }
} }
static void update_tfsoff(type_t *type, unsigned int offset, FILE *file)
{
type->typestring_offset = offset;
if (file) type->tfswrite = FALSE;
}
static void guard_rec(type_t *type)
{
/* types that contain references to themselves (like a linked list),
need to be shielded from infinite recursion when writing embedded
types */
if (type->typestring_offset)
type->tfswrite = FALSE;
else
type->typestring_offset = 1;
}
static int is_embedded_complex(const type_t *type) static int is_embedded_complex(const type_t *type)
{ {
return is_struct(type->type) || is_union(type->type); return is_struct(type->type) || is_union(type->type);
@ -789,7 +806,7 @@ static size_t write_pointer_tfs(FILE *file, type_t *type, unsigned int *typestri
unsigned int offset = *typestring_offset; unsigned int offset = *typestring_offset;
print_file(file, 0, "/* %d */\n", offset); print_file(file, 0, "/* %d */\n", offset);
type->typestring_offset = offset; update_tfsoff(type, offset, file);
if (type->ref->typestring_offset) if (type->ref->typestring_offset)
*typestring_offset += write_nonsimple_pointer(file, type, offset); *typestring_offset += write_nonsimple_pointer(file, type, offset);
@ -799,9 +816,9 @@ static size_t write_pointer_tfs(FILE *file, type_t *type, unsigned int *typestri
return offset; return offset;
} }
static int has_known_tfs(const type_t *type) static int processed(const type_t *type)
{ {
return type->typestring_offset || is_base_type(type->type); return type->typestring_offset && !type->tfswrite;
} }
static size_t write_pointer_description(FILE *file, const attr_list_t *attrs, static size_t write_pointer_description(FILE *file, const attr_list_t *attrs,
@ -827,7 +844,7 @@ static size_t write_pointer_description(FILE *file, const attr_list_t *attrs,
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);
*typestring_offset += 6; *typestring_offset += 6;
if (has_known_tfs(type->ref)) if (processed(type->ref) || is_base_type(type->ref->type))
write_pointer_tfs(file, type, typestring_offset); write_pointer_tfs(file, type, typestring_offset);
else else
error("write_pointer_description: type format string unknown\n"); error("write_pointer_description: type format string unknown\n");
@ -1224,6 +1241,8 @@ static size_t write_struct_tfs(FILE *file, type_t *type,
int has_pointers; int has_pointers;
unsigned int align = 0; unsigned int align = 0;
guard_rec(type);
switch (type->type) switch (type->type)
{ {
case RPC_FC_STRUCT: case RPC_FC_STRUCT:
@ -1238,7 +1257,7 @@ static size_t write_struct_tfs(FILE *file, type_t *type,
write_embedded_types(file, NULL, type, name, NULL, 0, typestring_offset); write_embedded_types(file, NULL, type, name, NULL, 0, typestring_offset);
start_offset = *typestring_offset; start_offset = *typestring_offset;
type->typestring_offset = start_offset; update_tfsoff(type, start_offset, file);
if (type->type == RPC_FC_STRUCT) if (type->type == RPC_FC_STRUCT)
WRITE_FCTYPE(file, FC_STRUCT, *typestring_offset); WRITE_FCTYPE(file, FC_STRUCT, *typestring_offset);
else else
@ -1281,7 +1300,7 @@ static size_t write_struct_tfs(FILE *file, type_t *type,
write_embedded_types(file, NULL, type, name, NULL, 0, typestring_offset); write_embedded_types(file, NULL, type, name, NULL, 0, typestring_offset);
start_offset = *typestring_offset; start_offset = *typestring_offset;
type->typestring_offset = start_offset; update_tfsoff(type, start_offset, file);
if (type->type == RPC_FC_CSTRUCT) if (type->type == RPC_FC_CSTRUCT)
WRITE_FCTYPE(file, FC_CSTRUCT, *typestring_offset); WRITE_FCTYPE(file, FC_CSTRUCT, *typestring_offset);
else else
@ -1334,7 +1353,7 @@ static size_t write_struct_tfs(FILE *file, type_t *type,
typestring_offset); typestring_offset);
start_offset = *typestring_offset; start_offset = *typestring_offset;
type->typestring_offset = start_offset; update_tfsoff(type, start_offset, file);
WRITE_FCTYPE(file, FC_CVSTRUCT, *typestring_offset); WRITE_FCTYPE(file, FC_CVSTRUCT, *typestring_offset);
/* alignment */ /* alignment */
print_file(file, 2, "0x%02x,\n", align - 1); print_file(file, 2, "0x%02x,\n", align - 1);
@ -1371,6 +1390,7 @@ static size_t write_struct_tfs(FILE *file, type_t *type,
write_embedded_types(file, NULL, type, name, NULL, 0, typestring_offset); write_embedded_types(file, NULL, type, name, NULL, 0, typestring_offset);
start_offset = *typestring_offset; start_offset = *typestring_offset;
update_tfsoff(type, start_offset, file);
print_file(file, 0, "/* %d */\n", start_offset); print_file(file, 0, "/* %d */\n", start_offset);
print_file(file, 2, "0x%x,\t/* %s */\n", type->type, string_of_type(type->type)); print_file(file, 2, "0x%x,\t/* %s */\n", type->type, string_of_type(type->type));
print_file(file, 2, "0x%x,\t/* %d */\n", align - 1, align - 1); print_file(file, 2, "0x%x,\t/* %d */\n", align - 1, align - 1);
@ -1457,6 +1477,8 @@ static size_t write_union_tfs(FILE *file, type_t *type, const char *name,
short nodeftype = 0xffff; short nodeftype = 0xffff;
var_t *f; var_t *f;
guard_rec(type);
/* use a level of 1 so pointers always get written */ /* use a level of 1 so pointers always get written */
write_embedded_types(file, NULL, type, name, NULL, 1, tfsoff); write_embedded_types(file, NULL, type, name, NULL, 1, tfsoff);
@ -1468,7 +1490,7 @@ static size_t write_union_tfs(FILE *file, type_t *type, const char *name,
} }
start_offset = *tfsoff; start_offset = *tfsoff;
type->typestring_offset = start_offset; update_tfsoff(type, start_offset, file);
print_file(file, 0, "/* %d */\n", start_offset); print_file(file, 0, "/* %d */\n", start_offset);
print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", size, size); print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", size, size);
print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", nbranch, nbranch); print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", nbranch, nbranch);
@ -1669,11 +1691,11 @@ static size_t write_typeformatstring_var(FILE *file, int indent, const func_t *f
offset, typeformat_offset); offset, typeformat_offset);
} }
static void clear_tfsoff(type_t *type) static void set_tfswrite(type_t *type, int val)
{ {
for (;;) while (type->tfswrite != val)
{ {
type->typestring_offset = 0; type->tfswrite = val;
if (type->kind == TKIND_ALIAS) if (type->kind == TKIND_ALIAS)
type = type->orig; type = type->orig;
@ -1685,7 +1707,7 @@ static void clear_tfsoff(type_t *type)
{ {
var_t *v; var_t *v;
LIST_FOR_EACH_ENTRY( v, type->fields, var_t, entry ) LIST_FOR_EACH_ENTRY( v, type->fields, var_t, entry )
clear_tfsoff(v->type); set_tfswrite(v->type, val);
} }
return; return;
@ -1707,7 +1729,8 @@ static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *ty
unsigned int align = 0; unsigned int align = 0;
type_t *ft = f->type; type_t *ft = f->type;
if (ft->type == RPC_FC_NON_ENCAPSULATED_UNION) if (!ft) continue;
else if (ft->type == RPC_FC_NON_ENCAPSULATED_UNION)
{ {
expr_t *swexp = get_attrp(f->attrs, ATTR_SWITCHIS); expr_t *swexp = get_attrp(f->attrs, ATTR_SWITCHIS);
const char *swname; const char *swname;
@ -1722,7 +1745,7 @@ static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *ty
error("%s: only identifiers are supported for switch_is at this time\n", error("%s: only identifiers are supported for switch_is at this time\n",
f->name); f->name);
if (ft->typestring_offset == 0) if (!processed(ft))
write_union_tfs(file, ft, f->name, tfsoff); write_union_tfs(file, ft, f->name, tfsoff);
swname = swexp->u.sval; swname = swexp->u.sval;
@ -1760,7 +1783,7 @@ static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *ty
{ {
type_t *ref = type->ref; type_t *ref = type->ref;
if (!has_known_tfs(ref)) if (!processed(ref) && !is_base_type(ref->type))
{ {
if (is_ptr(ref)) if (is_ptr(ref))
{ {
@ -1791,7 +1814,7 @@ static int write_embedded_types(FILE *file, const attr_list_t *attrs, type_t *ty
return retmask; return retmask;
} }
static void clear_all_tfsoffs(const ifref_list_t *ifaces) static void set_all_tfswrite(const ifref_list_t *ifaces, int val)
{ {
const ifref_t * iface; const ifref_t * iface;
const func_t *func; const func_t *func;
@ -1803,7 +1826,7 @@ static void clear_all_tfsoffs(const ifref_list_t *ifaces)
LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry ) LIST_FOR_EACH_ENTRY( func, iface->iface->funcs, const func_t, entry )
if (func->args) if (func->args)
LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry ) LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
clear_tfsoff(var->type); set_tfswrite(var->type, val);
} }
static size_t process_tfs(FILE *file, const ifref_list_t *ifaces, int for_objects) static size_t process_tfs(FILE *file, const ifref_list_t *ifaces, int for_objects)
@ -1827,9 +1850,12 @@ static size_t process_tfs(FILE *file, const ifref_list_t *ifaces, int for_object
current_func = func; current_func = func;
if (func->args) if (func->args)
LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry ) LIST_FOR_EACH_ENTRY( var, func->args, const var_t, entry )
var->type->typestring_offset update_tfsoff(
= write_typeformatstring_var(file, 2, func, var->type, var->type,
var, &typeformat_offset); write_typeformatstring_var(
file, 2, func, var->type, var,
&typeformat_offset),
file);
} }
} }
} }
@ -1850,7 +1876,7 @@ void write_typeformatstring(FILE *file, const ifref_list_t *ifaces, int for_obje
indent++; indent++;
print_file(file, indent, "NdrFcShort(0x0),\n"); print_file(file, indent, "NdrFcShort(0x0),\n");
clear_all_tfsoffs(ifaces); set_all_tfswrite(ifaces, TRUE);
process_tfs(file, ifaces, for_objects); process_tfs(file, ifaces, for_objects);
print_file(file, indent, "0x0\n"); print_file(file, indent, "0x0\n");
@ -2417,6 +2443,7 @@ 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) size_t get_size_typeformatstring(const ifref_list_t *ifaces, int for_objects)
{ {
set_all_tfswrite(ifaces, FALSE);
return process_tfs(NULL, ifaces, for_objects); return process_tfs(NULL, ifaces, for_objects);
} }

View File

@ -214,6 +214,7 @@ struct _type_t {
unsigned int defined : 1; unsigned int defined : 1;
unsigned int written : 1; unsigned int written : 1;
unsigned int user_types_registered : 1; unsigned int user_types_registered : 1;
unsigned int tfswrite : 1; /* if the type needs to be written to the TFS */
int sign : 2; int sign : 2;
}; };