widl: Lay framework for unions with simple unions working.

This commit is contained in:
Dan Hipschman 2007-05-18 16:53:27 -07:00 committed by Alexandre Julliard
parent 18724eaeb8
commit c5aaadc4c8
6 changed files with 331 additions and 9 deletions

View File

@ -21,6 +21,7 @@
#include <windows.h>
#include "wine/test.h"
#include "server.h"
#include "server_defines.h"
#include <stdio.h>
@ -138,6 +139,19 @@ s_sum_sp(sp_t *sp)
return sp->x + sp->s->x;
}
double
s_square_sun(sun_t *sun)
{
switch (sun->s)
{
case SUN_I: return sun->u.i * sun->u.i;
case SUN_F1:
case SUN_F2: return sun->u.f * sun->u.f;
default:
return 0.0;
}
}
void
s_stop(void)
{
@ -252,6 +266,24 @@ basic_tests(void)
ok(sum_sp(&sp) == 29, "RPC sum_sp\n");
}
static void
union_tests(void)
{
sun_t sun;
sun.s = SUN_I;
sun.u.i = 9;
ok(square_sun(&sun) == 81.0, "RPC square_sun\n");
sun.s = SUN_F1;
sun.u.f = 5.0;
ok(square_sun(&sun) == 25.0, "RPC square_sun\n");
sun.s = SUN_I;
sun.u.i = -2.0;
ok(square_sun(&sun) == 4.0, "RPC square_sun\n");
}
static void
client(const char *test)
{
@ -266,6 +298,7 @@ client(const char *test)
ok(RPC_S_OK == RpcBindingFromStringBinding(binding, &IServer_IfHandle), "RpcBindingFromStringBinding\n");
basic_tests();
union_tests();
ok(RPC_S_OK == RpcStringFree(&binding), "RpcStringFree\n");
ok(RPC_S_OK == RpcBindingFree(&IServer_IfHandle), "RpcBindingFree\n");
@ -281,6 +314,7 @@ client(const char *test)
ok(RPC_S_OK == RpcBindingFromStringBinding(binding, &IServer_IfHandle), "RpcBindingFromStringBinding\n");
basic_tests();
union_tests();
stop();
ok(RPC_S_OK == RpcStringFree(&binding), "RpcStringFree\n");

View File

@ -18,6 +18,8 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "server_defines.h"
typedef struct tag_vector
{
int x;
@ -53,6 +55,17 @@ interface IServer
vector_t **pv;
} pvectors_t;
typedef struct
{
[switch_is(s)] union
{
[case(SUN_I)] int i;
[case(SUN_F1, SUN_F2)] float f;
} u;
int s;
} sun_t;
int int_return(void);
int square(int x);
int sum(int x, int y);
@ -81,5 +94,6 @@ interface IServer
} sp_t;
int sum_sp(sp_t *sp);
double square_sun(sun_t *sun);
void stop(void);
}

View File

@ -0,0 +1,24 @@
/*
* Constants shared between server.c and server.idl
*
* Copyright (C) Google 2007 (Dan Hipschman)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
/* sun_t case values */
#define SUN_I 10
#define SUN_F1 -2
#define SUN_F2 7

View File

@ -1260,6 +1260,7 @@ static var_t *make_var(char *name)
v->attrs = NULL;
v->array = NULL;
v->eval = NULL;
v->corrdesc = 0;
return v;
}

View File

@ -61,8 +61,9 @@ struct expr_eval_routine
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);
static size_t write_struct_tfs(FILE *file, type_t *type, const char *name,
unsigned int *typestring_offset);
static size_t write_struct_tfs(FILE *file, type_t *type, const char *name, unsigned int *tfsoff);
static void write_embedded_types(FILE *file, const type_t *type, size_t *tfsoff);
const char *string_of_type(unsigned char type)
{
switch (type)
@ -87,6 +88,14 @@ const char *string_of_type(unsigned char type)
case RPC_FC_UP: return "FC_UP";
case RPC_FC_OP: return "FC_OP";
case RPC_FC_FP: return "FC_FP";
case RPC_FC_ENCAPSULATED_UNION: return "FC_ENCAPSULATED_UNION";
case RPC_FC_NON_ENCAPSULATED_UNION: return "FC_NON_ENCAPSULATED_UNION";
case RPC_FC_STRUCT: return "FC_STRUCT";
case RPC_FC_PSTRUCT: return "FC_PSTRUCT";
case RPC_FC_CSTRUCT: return "FC_CSTRUCT";
case RPC_FC_CPSTRUCT: return "FC_CPSTRUCT";
case RPC_FC_CVSTRUCT: return "FC_CVSTRUCT";
case RPC_FC_BOGUS_STRUCT: return "FC_BOGUS_STRUCT";
default:
error("string_of_type: unknown type 0x%02x\n", type);
return NULL;
@ -109,6 +118,49 @@ static int is_struct(unsigned char type)
}
}
static int is_union(unsigned char type)
{
switch (type)
{
case RPC_FC_ENCAPSULATED_UNION:
case RPC_FC_NON_ENCAPSULATED_UNION:
return 1;
default:
return 0;
}
}
static int is_embedded_complex(const type_t *type)
{
return is_struct(type->type) || is_union(type->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, f->array, &align);
}
}
if (pfield) *pfield = NULL;
return -1;
}
static int compare_expr(const expr_t *a, const expr_t *b)
{
int ret;
@ -612,6 +664,26 @@ static size_t fields_memsize(const var_list_t *fields, unsigned int *align)
return size;
}
static size_t union_memsize(const var_list_t *fields, unsigned int *pmaxa)
{
size_t size, maxs = 0;
unsigned int align = *pmaxa;
const var_t *v;
if (fields) LIST_FOR_EACH_ENTRY( v, fields, const var_t, entry )
{
/* we could have an empty default field with NULL type */
if (v->type)
{
size = type_memsize(v->type, v->array, &align);
if (maxs < size) maxs = size;
if (*pmaxa < align) *pmaxa = align;
}
}
return maxs;
}
static size_t get_array_size( const array_dims_t *array )
{
size_t size = 1;
@ -672,9 +744,11 @@ static size_t type_memsize(const type_t *t, const array_dims_t *array, unsigned
case RPC_FC_CSTRUCT:
case RPC_FC_PSTRUCT:
case RPC_FC_BOGUS_STRUCT:
size = fields_memsize(t->fields, align);
break;
case RPC_FC_ENCAPSULATED_UNION:
case RPC_FC_NON_ENCAPSULATED_UNION:
size = fields_memsize(t->fields, align);
size = union_memsize(t->fields, align);
break;
default:
error("type_memsize: Unknown type %d\n", t->type);
@ -1167,6 +1241,20 @@ static void write_struct_members(FILE *file, const type_t *type, unsigned int *t
print_file( file, 2, "0x8,\t/* FC_LONG */\n" );
*typestring_offset += 1;
}
else if (is_embedded_complex(field->type))
{
size_t absoff = (field->corrdesc
? field->corrdesc
: field->type->typestring_offset);
short reloff = absoff - (*typestring_offset + 2);
print_file(file, 2, "0x4c,\t/* FC_EMBEDDED_COMPLEX */\n");
/* FIXME: actually compute necessary padding */
print_file(file, 2, "0x0,\t/* FIXME: padding */\n");
print_file(file, 2, "NdrFcShort(0x%hx),\t/* Offset= %hd (%lu) */\n",
reloff, reloff, absoff);
*typestring_offset += 4;
}
else if (!write_base_type( file, field->type, typestring_offset ))
error("Unsupported member type 0x%x\n", rtype);
}
@ -1327,6 +1415,32 @@ static size_t write_struct_tfs(FILE *file, type_t *type,
*typestring_offset += 1;
return start_offset;
case RPC_FC_BOGUS_STRUCT:
total_size = type_memsize(type, NULL, &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);
write_embedded_types(file, type, typestring_offset);
start_offset = *typestring_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/* %d */\n", align - 1, align - 1);
print_file(file, 2, "NdrFcShort(0x%x),\t/* %d */\n", total_size, total_size);
/* do conformant array stuff */
print_file(file, 2, "NdrFcShort(0x0),\t/* FIXME: conformant array stuff */\n");
/* do pointer stuff here */
print_file(file, 2, "NdrFcShort(0x0),\t/* FIXME: pointer stuff */\n");
*typestring_offset += 8;
write_struct_members(file, type, typestring_offset);
return start_offset;
default:
error("write_struct_tfs: Unimplemented for type 0x%x\n", type->type);
return *typestring_offset;
@ -1366,12 +1480,91 @@ static size_t write_pointer_only_tfs(FILE *file, const attr_list_t *attrs, int p
return start_offset;
}
static size_t write_union_tfs(FILE *file, const attr_list_t *attrs,
const type_t *type, const char *name,
unsigned int *typeformat_offset)
static void write_branch_type(FILE *file, const type_t *t, size_t *tfsoff)
{
error("write_union_tfs: Unimplemented\n");
return *typeformat_offset;
if (is_base_type(t->type))
{
print_file(file, 2, "NdrFcShort(0x80%02x),\t/* Simple arm type: %s */\n",
t->type, string_of_type(t->type));
}
else if (t->typestring_offset)
{
short reloff = t->typestring_offset - (*tfsoff + 2);
print_file(file, 2, "NdrFcShort(0x%x),\t/* Offset= %d (%d) */\n",
reloff, reloff, t->typestring_offset);
}
else
error("write_branch_type: type unimplemented (0x%x)\n", t->type);
*tfsoff += 2;
}
static size_t write_union_tfs(FILE *file, type_t *type, size_t *tfsoff)
{
size_t align = 0;
size_t start_offset;
size_t size = type_memsize(type, NULL, &align);
var_list_t *fields = type->fields;
size_t nbranch = 0;
type_t *deftype = NULL;
short nodeftype = 0xffff;
var_t *f;
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);
}
start_offset = *tfsoff;
type->typestring_offset = 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", nbranch, nbranch);
*tfsoff += 4;
if (fields) LIST_FOR_EACH_ENTRY(f, fields, var_t, entry)
{
type_t *ft = f->type;
expr_list_t *cases = get_attrp(f->attrs, ATTR_CASE);
int deflt = is_attr(f->attrs, ATTR_DEFAULT);
expr_t *c;
if (cases == NULL && !deflt)
error("union field %s with neither case nor default attribute\n", f->name);
if (cases) LIST_FOR_EACH_ENTRY(c, cases, expr_t, entry)
{
/* MIDL doesn't check for duplicate cases, even though that seems
like a reasonable thing to do, it just dumps them to the TFS
like we're going to do here. */
print_file(file, 2, "NdrFcLong(0x%x),\t/* %d */\n", c->cval, c->cval);
*tfsoff += 4;
write_branch_type(file, ft, tfsoff);
}
/* MIDL allows multiple default branches, even though that seems
illogical, it just chooses the last one, which is what we will
do. */
if (deflt)
{
deftype = ft;
nodeftype = 0;
}
}
if (deftype)
{
write_branch_type(file, deftype, tfsoff);
}
else
{
print_file(file, 2, "NdrFcShort(0x%x),\n", nodeftype);
*tfsoff += 2;
}
return start_offset;
}
static size_t write_ip_tfs(FILE *file, const func_t *func, const type_t *type, const var_t *var,
@ -1481,7 +1674,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, var->attrs, 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 */
@ -1550,6 +1743,61 @@ static void clear_tfsoff(type_t *type)
}
}
static void write_embedded_types(FILE *file, const type_t *type, size_t *tfsoff)
{
var_list_t *fields = type->fields;
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;
size_t corroff;
if (ft->type == RPC_FC_NON_ENCAPSULATED_UNION)
{
expr_t *swexp = get_attrp(f->attrs, ATTR_SWITCHIS);
const char *swname;
var_t *swvar;
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 (ft->typestring_offset == 0)
write_union_tfs(file, ft, 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 if (!is_base_type(ft->type))
error("write_embedded_types: unknown type (0x%x)\n", ft->type);
/* FIXME: this doesn't take alignment/padding into account */
offset += type_memsize(ft, NULL, &align);
}
}
static void clear_all_tfsoffs(const ifref_list_t *ifaces)
{
const ifref_t * iface;

View File

@ -220,6 +220,7 @@ 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;