summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog27
-rw-r--r--TODO3
-rw-r--r--gidl.dtd20
-rw-r--r--metadata-format.txt53
-rw-r--r--src/generate.c174
-rw-r--r--src/gidlmodule.c1
-rw-r--r--src/gidlnode.c125
-rw-r--r--src/gidlnode.h19
-rw-r--r--src/gidlparser.c145
-rw-r--r--src/ginfo.c104
-rw-r--r--src/girepository.h16
-rw-r--r--src/gmetadata.c3
-rw-r--r--src/gmetadata.h31
-rwxr-xr-xtests/roundtrips.sh2
-rw-r--r--tests/union.test14
15 files changed, 683 insertions, 54 deletions
diff --git a/ChangeLog b/ChangeLog
index 48188f4a..900468c7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,30 @@
+2005-05-15 Matthias Clasen <mclasen@redhat.com>
+
+ * tests/roundtrips.sh (SIMPLE_TESTS): Add union.test.
+
+ * tests/union.test: Add a union test.
+
+ * src/generate.c: Handle unions.
+
+ * src/girepository.h:
+ * src/ginfo.c: Add GIUnionInfo and functions to access it.
+
+ * src/gidlnode.c: Handle GIdlNodeUnion nodes.
+
+ * src/gidlparser.c (start_union): Parse <union> elements.
+
+ * src/gidlnode.h: Add a GIdlNodeUnion.
+
+ * gidl.dtd: Add a <union> element.
+
+ * src/gmetadata.c (g_metadata_check_sanity): Check
+ union_blob_size.
+
+ * src/gmetadata.h: Add union_blob_size to Header,
+ add a UnionBlob.
+
+ * metadata-format.txt: Add a UnionBlob.
+
2005-05-13 Matthias Clasen <mclasen@redhat.com>
* tests/*: Update testcases.
diff --git a/TODO b/TODO
index 325db9da..34375afa 100644
--- a/TODO
+++ b/TODO
@@ -9,7 +9,6 @@ XML format
Binary format
-------------
- Add hashes to lookup interfaces and functions in interfaces
-- Do we need (at least limited) handling of unions ? E.g. GdkEvent
- Write a validator
- Handle parent being 0
@@ -25,6 +24,8 @@ Repository
- Add thorough error checking
- Use hashes
- Maybe allow populating repositories at runtime
+- Think about a system-wide repository mapping namespace ids to
+ libraries/metadata files
General
-------
diff --git a/gidl.dtd b/gidl.dtd
index f19b037f..d134fc12 100644
--- a/gidl.dtd
+++ b/gidl.dtd
@@ -2,7 +2,7 @@
<!ATTLIST api version CDATA #REQUIRED >
-<!ELEMENT namespace (function|callback|object|interface|enum|flags|boxed|struct|constant|errordomain)* >
+<!ELEMENT namespace (function|callback|object|interface|enum|flags|boxed|struct|constant|errordomain|union)* >
<!ATTLIST namespace name CDATA #REQUIRED >
<!ELEMENT function (return-type,parameters?) >
@@ -15,7 +15,6 @@
null-ok (0|1) #IMPLIED
transfer (full|shallow|none) #IMPLIED >
-
<!ELEMENT parameter EMPTY >
<!ATTLIST parameter type CDATA #REQUIRED
name CDATA #REQUIRED
@@ -82,9 +81,10 @@
is-class-closure (0|1) #IMPLIED >
<!ELEMENT field EMPTY >
-<!ATTLIST field name CDATA #REQUIRED
- type CDATA #REQUIRED
- bits CDATA #IMPLIED >
+<!ATTLIST field name CDATA #REQUIRED
+ type CDATA #REQUIRED
+ bits CDATA #IMPLIED
+ branch CDATA #IMPLIED>
<!ELEMENT enum (member+) >
<!ATTLIST enum name CDATA #REQUIRED
@@ -114,6 +114,16 @@
<!ATTLIST struct name CDATA #REQUIRED
deprecated (0|1) #IMPLIED >
+<!ELEMENT union (discriminator?,(constructor|field|method)*) >
+<!ATTLIST union name CDATA #REQUIRED
+ type-name CDATA #IMPLIED
+ get-type CDATA #IMPLIED
+ deprecated (0|1) #IMPLIED >
+
+<!ELEMENT discriminator EMPTY >
+<!ATTLIST discriminator offset CDATA #REQUIRED
+ type CDATA #REQUIRED >
+
<!ELEMENT constant EMPTY >
<!ATTLIST constant name CDATA #REQUIRED
type CDATA #REQUIRED
diff --git a/metadata-format.txt b/metadata-format.txt
index c6234468..4d4ac3c6 100644
--- a/metadata-format.txt
+++ b/metadata-format.txt
@@ -1,7 +1,10 @@
GObject binary metadata for introspection
-----------------------------------------
-Version 0.4
+Version 0.5
+
+Changes since 0.4:
+- add a UnionBlob
Changes since 0.3:
- drop short_name for ValueBlob.
@@ -63,7 +66,7 @@ directory ::= list of entries
entry ::= blob type, name, namespace, offset
-blob ::= function|callback|struct|boxed|enum|flags|object|interface|constant|errordomain
+blob ::= function|callback|struct|boxed|enum|flags|object|interface|constant|errordomain|union
annotations ::= list of annotations, sorted by offset
@@ -112,6 +115,7 @@ struct Header
guint16 struct_blob_size; /* 20 */
guint16 object_blob_size; /* 32 */
guint16 interface_blob_size; /* 28 */
+ guint16 union_blob_size; /* 28 */
}
magic: The string "GOBJ\nMETADATA\r\n\032". This was inspired by XPCOM,
@@ -989,5 +993,50 @@ name: The name of the annotation, a string.
value: The value of the annotation (also a string)
+UnionBlob (28 + x bytes)
+
+struct UnionBlob
+{
+ guint16 blob_type; /* 11 */
+ guint deprecated : 1;
+ guint unregistered : 1;
+ guint discriminated : 1;
+ guint reserved :13;
+ guint32 name;
+
+ GTypeBlob gtype;
+
+ guint16 n_fields;
+ guint16 n_functions;
+
+ gint32 discriminator_offset;
+ SimpleTypeBlob discriminator_type;
+
+ FieldBlob fields[];
+ FunctionBlob functions[];
+ ConstantBlob discriminator_values[]
+}
+
+unregistered:
+ If this is set, the type is not registered with GType.
+
+discriminated:
+ Is set if the union is discriminated
+
+gtype: For types which are registered with GType, contains the
+ information about the GType. Otherwise unused.
+
+n_fields: Length of the arrays
+
+discriminator_offset:
+ Offset from the beginning of the blob where the
+ discriminator of a discriminated union is located
+
+discriminator_type:
+ Type of the discriminator
+discriminator_values:
+ On discriminator value per field
+fields: Array of FieldBlobs describing the alternative
+ branches of the union
diff --git a/src/generate.c b/src/generate.c
index 0f87a973..c3cb30c9 100644
--- a/src/generate.c
+++ b/src/generate.c
@@ -147,8 +147,15 @@ write_type_info (const gchar *namespace,
}
static void
+write_constant_value (const gchar *namespace,
+ GITypeInfo *info,
+ GArgument *argument,
+ FILE *file);
+
+static void
write_field_info (const gchar *namespace,
GIFieldInfo *info,
+ GIConstantInfo *branch,
FILE *file)
{
const gchar *name;
@@ -156,6 +163,7 @@ write_field_info (const gchar *namespace,
gint size;
gint offset;
GITypeInfo *type;
+ GArgument value;
name = g_base_info_get_name ((GIBaseInfo *)info);
flags = g_field_info_get_flags (info);
@@ -177,7 +185,18 @@ write_field_info (const gchar *namespace,
write_type_info (namespace, type, file);
g_base_info_unref ((GIBaseInfo *)type);
- g_fprintf (file, "\" />\n");
+ g_fprintf (file, "\"");
+
+ if (branch)
+ {
+ g_fprintf (file, " branch=\"");
+ type = g_constant_info_get_type (branch);
+ g_constant_info_get_value (branch, &value);
+ write_constant_value (namespace, type, &value, file);
+ g_fprintf (file, "\"");
+ }
+
+ g_fprintf (file," />\n");
}
static void
@@ -383,7 +402,7 @@ write_struct_info (const gchar *namespace,
for (i = 0; i < g_struct_info_get_n_fields (info); i++)
{
GIFieldInfo *field = g_struct_info_get_field (info, i);
- write_field_info (namespace, field, file);
+ write_field_info (namespace, field, NULL, file);
g_base_info_unref ((GIBaseInfo *)field);
}
@@ -423,77 +442,86 @@ write_value_info (const gchar *namespace,
}
static void
-write_constant_info (const gchar *namespace,
- GIConstantInfo *info,
- FILE *file,
- gint indent)
+write_constant_value (const gchar *namespace,
+ GITypeInfo *type,
+ GArgument *value,
+ FILE *file)
{
- GITypeInfo *type;
- const gchar *name;
- gboolean deprecated;
- GArgument value;
-
- name = g_base_info_get_name ((GIBaseInfo *)info);
- deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
-
- g_fprintf (file, "%*s<constant name=\"%s\" type=\"", indent, "", name);
-
- type = g_constant_info_get_type (info);
- write_type_info (namespace, type, file);
- g_fprintf (file, "\" value=\"");
-
- g_constant_info_get_value (info, &value);
switch (g_type_info_get_tag (type))
{
case GI_TYPE_TAG_BOOLEAN:
- g_fprintf (file, "%d", value.v_boolean);
+ g_fprintf (file, "%d", value->v_boolean);
break;
case GI_TYPE_TAG_INT8:
- g_fprintf (file, "%d", value.v_int8);
+ g_fprintf (file, "%d", value->v_int8);
break;
case GI_TYPE_TAG_UINT8:
- g_fprintf (file, "%d", value.v_uint8);
+ g_fprintf (file, "%d", value->v_uint8);
break;
case GI_TYPE_TAG_INT16:
- g_fprintf (file, "%" G_GINT16_FORMAT, value.v_int16);
+ g_fprintf (file, "%" G_GINT16_FORMAT, value->v_int16);
break;
case GI_TYPE_TAG_UINT16:
- g_fprintf (file, "%" G_GUINT16_FORMAT, value.v_uint16);
+ g_fprintf (file, "%" G_GUINT16_FORMAT, value->v_uint16);
break;
case GI_TYPE_TAG_INT32:
- g_fprintf (file, "%" G_GINT32_FORMAT, value.v_int32);
+ g_fprintf (file, "%" G_GINT32_FORMAT, value->v_int32);
break;
case GI_TYPE_TAG_UINT32:
- g_fprintf (file, "%" G_GUINT32_FORMAT, value.v_uint32);
+ g_fprintf (file, "%" G_GUINT32_FORMAT, value->v_uint32);
break;
case GI_TYPE_TAG_INT64:
- g_fprintf (file, "%" G_GINT64_FORMAT, value.v_int64);
+ g_fprintf (file, "%" G_GINT64_FORMAT, value->v_int64);
break;
case GI_TYPE_TAG_UINT64:
- g_fprintf (file, "%" G_GUINT64_FORMAT, value.v_uint64);
+ g_fprintf (file, "%" G_GUINT64_FORMAT, value->v_uint64);
break;
case GI_TYPE_TAG_FLOAT:
- g_fprintf (file, "%f", value.v_float);
+ g_fprintf (file, "%f", value->v_float);
break;
case GI_TYPE_TAG_DOUBLE:
- g_fprintf (file, "%Lf", value.v_double);
+ g_fprintf (file, "%Lf", value->v_double);
break;
case GI_TYPE_TAG_STRING:
- g_fprintf (file, "%s", value.v_string);
+ g_fprintf (file, "%s", value->v_string);
break;
case GI_TYPE_TAG_INT:
- g_fprintf (file, "%d", value.v_int);
+ g_fprintf (file, "%d", value->v_int);
break;
case GI_TYPE_TAG_UINT:
- g_fprintf (file, "%d", value.v_uint);
+ g_fprintf (file, "%d", value->v_uint);
break;
case GI_TYPE_TAG_LONG:
- g_fprintf (file, "%ld", value.v_long);
+ g_fprintf (file, "%ld", value->v_long);
break;
case GI_TYPE_TAG_ULONG:
- g_fprintf (file, "%ld", value.v_ulong);
+ g_fprintf (file, "%ld", value->v_ulong);
break;
}
+}
+
+static void
+write_constant_info (const gchar *namespace,
+ GIConstantInfo *info,
+ FILE *file,
+ gint indent)
+{
+ GITypeInfo *type;
+ const gchar *name;
+ gboolean deprecated;
+ GArgument value;
+
+ name = g_base_info_get_name ((GIBaseInfo *)info);
+ deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+
+ g_fprintf (file, "%*s<constant name=\"%s\" type=\"", indent, "", name);
+
+ type = g_constant_info_get_type (info);
+ write_type_info (namespace, type, file);
+ g_fprintf (file, "\" value=\"");
+
+ g_constant_info_get_value (info, &value);
+ write_constant_value (namespace, type, &value, file);
g_fprintf (file, "\" />\n");
g_base_info_unref ((GIBaseInfo *)type);
@@ -714,7 +742,7 @@ write_object_info (const gchar *namespace,
for (i = 0; i < g_object_info_get_n_fields (info); i++)
{
GIFieldInfo *field = g_object_info_get_field (info, i);
- write_field_info (namespace, field, file);
+ write_field_info (namespace, field, NULL, file);
g_base_info_unref ((GIBaseInfo *)field);
}
@@ -856,6 +884,67 @@ write_error_domain_info (const gchar *namespace,
}
static void
+write_union_info (const gchar *namespace,
+ GIUnionInfo *info,
+ FILE *file)
+{
+ const gchar *name;
+ const gchar *type_name;
+ const gchar *type_init;
+ gboolean deprecated;
+ gint i;
+
+ name = g_base_info_get_name ((GIBaseInfo *)info);
+ deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
+
+ type_name = g_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info);
+ type_init = g_registered_type_info_get_type_init ((GIRegisteredTypeInfo*)info);
+
+ g_fprintf (file, " <union name=\"%s\"", name);
+
+ if (type_name)
+ g_fprintf (file, " type-name=\"%s\" get-type=\"%s\"", type_name, type_init);
+
+ if (deprecated)
+ g_fprintf (file, " deprecated=\"1\"");
+
+ g_fprintf (file, ">\n");
+
+ if (g_union_info_is_discriminated (info))
+ {
+ gint offset;
+ GITypeInfo *type;
+
+ offset = g_union_info_get_discriminator_offset (info);
+ type = g_union_info_get_discriminator_type (info);
+
+ g_fprintf (file, " <discriminator offset=\"%d\" type=\"", offset);
+ write_type_info (namespace, type, file);
+ g_fprintf (file, "\" />\n");
+ g_base_info_unref ((GIBaseInfo *)type);
+ }
+
+ for (i = 0; i < g_union_info_get_n_fields (info); i++)
+ {
+ GIFieldInfo *field = g_union_info_get_field (info, i);
+ GIConstantInfo *constant = g_union_info_get_discriminator (info, i);
+ write_field_info (namespace, field, constant, file);
+ g_base_info_unref ((GIBaseInfo *)field);
+ if (constant)
+ g_base_info_unref ((GIBaseInfo *)constant);
+ }
+
+ for (i = 0; i < g_union_info_get_n_methods (info); i++)
+ {
+ GIFunctionInfo *function = g_union_info_get_method (info, i);
+ write_function_info (namespace, function, file, 6);
+ g_base_info_unref ((GIBaseInfo *)function);
+ }
+
+ g_fprintf (file, " </union>\n");
+}
+
+static void
write_repository (GIRepository *repository,
gboolean needs_prefix)
{
@@ -915,7 +1004,11 @@ write_repository (GIRepository *repository,
case GI_INFO_TYPE_BOXED:
write_struct_info (ns, (GIStructInfo *)info, file);
break;
-
+
+ case GI_INFO_TYPE_UNION:
+ write_union_info (ns, (GIUnionInfo *)info, file);
+ break;
+
case GI_INFO_TYPE_ENUM:
case GI_INFO_TYPE_FLAGS:
write_enum_info (ns, (GIEnumInfo *)info, file);
@@ -936,6 +1029,9 @@ write_repository (GIRepository *repository,
case GI_INFO_TYPE_ERROR_DOMAIN:
write_error_domain_info (ns, (GIErrorDomainInfo *)info, file);
break;
+
+ default:
+ g_error ("unknown info type %d\n", g_base_info_get_type (info));
}
g_base_info_unref (info);
diff --git a/src/gidlmodule.c b/src/gidlmodule.c
index de155f1b..6319e834 100644
--- a/src/gidlmodule.c
+++ b/src/gidlmodule.c
@@ -133,6 +133,7 @@ g_idl_module_build_metadata (GIdlModule *module,
header->struct_blob_size = 20;
header->object_blob_size = 32;
header->interface_blob_size = 28;
+ header->union_blob_size = 28;
/* fill in directory and content */
entry = (DirEntry *)&data[header->directory];
diff --git a/src/gidlnode.c b/src/gidlnode.c
index 2bf501a7..f8223c4c 100644
--- a/src/gidlnode.c
+++ b/src/gidlnode.c
@@ -125,6 +125,10 @@ g_idl_node_new (GIdlNodeTypeId type)
node = g_malloc0 (sizeof (GIdlNodeXRef));
break;
+ case G_IDL_NODE_UNION:
+ node = g_malloc0 (sizeof (GIdlNodeUnion));
+ break;
+
default:
g_error ("Unhandled node type %d\n", type);
break;
@@ -323,6 +327,22 @@ g_idl_node_free (GIdlNode *node)
}
break;
+ case G_IDL_NODE_UNION:
+ {
+ GIdlNodeUnion *union_ = (GIdlNodeUnion *)node;
+
+ g_free (node->name);
+ g_free (union_->gtype_name);
+ g_free (union_->gtype_init);
+
+ g_idl_node_free ((GIdlNode *)union_->discriminator_type);
+ for (l = union_->members; l; l = l->next)
+ g_idl_node_free ((GIdlNode *)l->data);
+ for (l = union_->discriminators; l; l = l->next)
+ g_idl_node_free ((GIdlNode *)l->data);
+ }
+ break;
+
default:
g_error ("Unhandled node type %d\n", node->type);
break;
@@ -442,6 +462,18 @@ g_idl_node_get_size (GIdlNode *node)
size = 0;
break;
+ case G_IDL_NODE_UNION:
+ {
+ GIdlNodeUnion *union_ = (GIdlNodeUnion *)node;
+
+ size = 28;
+ for (l = union_->members; l; l = l->next)
+ size += g_idl_node_get_size ((GIdlNode *)l->data);
+ for (l = union_->discriminators; l; l = l->next)
+ size += g_idl_node_get_size ((GIdlNode *)l->data);
+ }
+ break;
+
default:
g_error ("Unhandled node type %d\n", node->type);
size = 0;
@@ -699,6 +731,19 @@ g_idl_node_get_full_size (GIdlNode *node)
}
break;
+ case G_IDL_NODE_UNION:
+ {
+ GIdlNodeUnion *union_ = (GIdlNodeUnion *)node;
+
+ size = 28;
+ size += ALIGN_VALUE (strlen (node->name) + 1, 4);
+ for (l = union_->members; l; l = l->next)
+ size += g_idl_node_get_full_size ((GIdlNode *)l->data);
+ for (l = union_->discriminators; l; l = l->next)
+ size += g_idl_node_get_full_size ((GIdlNode *)l->data);
+ }
+ break;
+
default:
g_error ("Unknown type tag %d\n", node->type);
size = 0;
@@ -1419,6 +1464,86 @@ g_idl_node_build_metadata (GIdlNode *node,
}
break;
+ case G_IDL_NODE_UNION:
+ {
+ UnionBlob *blob = (UnionBlob *)&data[*offset];
+ GIdlNodeUnion *union_ = (GIdlNodeUnion *)node;
+
+ blob->blob_type = BLOB_TYPE_UNION;
+ blob->deprecated = union_->deprecated;
+ blob->reserved = 0;
+ blob->name = write_string (node->name, strings, data, offset2);
+ if (union_->gtype_name)
+ {
+ blob->unregistered = FALSE;
+ blob->gtype_name = write_string (union_->gtype_name, strings, data, offset2);
+ blob->gtype_init = write_string (union_->gtype_init, strings, data, offset2);
+ }
+ else
+ {
+ blob->unregistered = TRUE;
+ blob->gtype_name = 0;
+ blob->gtype_init = 0;
+ }
+
+ blob->n_fields = 0;
+ blob->n_functions = 0;
+
+ blob->discriminator_offset = union_->discriminator_offset;
+
+ if (union_->discriminator_type)
+ {
+ *offset += 24;
+ blob->discriminated = TRUE;
+ g_idl_node_build_metadata ((GIdlNode *)union_->discriminator_type,
+ module, modules, strings, types,
+ data, offset, offset2);
+ }
+ else
+ {
+ *offset += 28;
+ blob->discriminated = FALSE;
+ blob->discriminator_type.offset = 0;
+ }
+
+
+ for (l = union_->members; l; l = l->next)
+ {
+ GIdlNode *member = (GIdlNode *)l->data;
+
+ if (member->type == G_IDL_NODE_FIELD)
+ {
+ blob->n_fields++;
+ g_idl_node_build_metadata (member, module, modules, strings,
+ types, data, offset, offset2);
+ }
+ }
+
+ for (l = union_->members; l; l = l->next)
+ {
+ GIdlNode *member = (GIdlNode *)l->data;
+
+ if (member->type == G_IDL_NODE_FUNCTION)
+ {
+ blob->n_functions++;
+ g_idl_node_build_metadata (member, module, modules, strings,
+ types, data, offset, offset2);
+ }
+ }
+
+ if (union_->discriminator_type)
+ {
+ for (l = union_->discriminators; l; l = l->next)
+ {
+ GIdlNode *member = (GIdlNode *)l->data;
+
+ g_idl_node_build_metadata (member, module, modules, strings,
+ types, data, offset, offset2);
+ }
+ }
+ }
+ break;
+
case G_IDL_NODE_ENUM:
case G_IDL_NODE_FLAGS:
{
diff --git a/src/gidlnode.h b/src/gidlnode.h
index 394d2f4f..e81d7133 100644
--- a/src/gidlnode.h
+++ b/src/gidlnode.h
@@ -41,6 +41,7 @@ typedef struct _GIdlNodeStruct GIdlNodeStruct;
typedef struct _GIdlNodeConstant GIdlNodeConstant;
typedef struct _GIdlNodeErrorDomain GIdlNodeErrorDomain;
typedef struct _GIdlNodeXRef GIdlNodeXRef;
+typedef struct _GIdlNodeUnion GIdlNodeUnion;
typedef enum
{
@@ -55,6 +56,7 @@ typedef enum
G_IDL_NODE_INTERFACE,
G_IDL_NODE_CONSTANT,
G_IDL_NODE_ERROR_DOMAIN,
+ G_IDL_NODE_UNION,
G_IDL_NODE_PARAM,
G_IDL_NODE_TYPE,
G_IDL_NODE_PROPERTY,
@@ -271,6 +273,23 @@ struct _GIdlNodeStruct
GList *members;
};
+struct _GIdlNodeUnion
+{
+ GIdlNode node;
+
+ gboolean deprecated;
+
+ GList *members;
+ GList *discriminators;
+
+ gchar *gtype_name;
+ gchar *gtype_init;
+
+ gint discriminator_offset;
+ GIdlNodeType *discriminator_type;
+};
+
+
struct _GIdlNodeErrorDomain
{
GIdlNode node;
diff --git a/src/gidlparser.c b/src/gidlparser.c
index c175abae..8b38ed70 100644
--- a/src/gidlparser.c
+++ b/src/gidlparser.c
@@ -39,7 +39,8 @@ typedef enum
STATE_BOXED,
STATE_STRUCT,
STATE_SIGNAL,
- STATE_ERRORDOMAIN
+ STATE_ERRORDOMAIN,
+ STATE_UNION
} ParseState;
typedef struct _ParseContext ParseContext;
@@ -413,7 +414,8 @@ start_function (GMarkupParseContext *context,
((ctx->state == STATE_OBJECT ||
ctx->state == STATE_INTERFACE ||
ctx->state == STATE_BOXED ||
- ctx->state == STATE_STRUCT) &&
+ ctx->state == STATE_STRUCT ||
+ ctx->state == STATE_UNION) &&
strcmp (element_name, "method") == 0) ||
((ctx->state == STATE_OBJECT ||
ctx->state == STATE_BOXED) &&
@@ -504,6 +506,14 @@ start_function (GMarkupParseContext *context,
struct_ = (GIdlNodeStruct *)ctx->current_node;
struct_->members = g_list_append (struct_->members, function); }
break;
+ case G_IDL_NODE_UNION:
+ {
+ GIdlNodeUnion *union_;
+
+ union_ = (GIdlNodeUnion *)ctx->current_node;
+ union_->members = g_list_append (union_->members, function);
+ }
+ break;
}
ctx->current_node = (GIdlNode *)function;
@@ -657,19 +667,22 @@ start_field (GMarkupParseContext *context,
if (strcmp (element_name, "field") == 0 &&
(ctx->state == STATE_OBJECT ||
ctx->state == STATE_BOXED ||
- ctx->state == STATE_STRUCT))
+ ctx->state == STATE_STRUCT ||
+ ctx->state == STATE_UNION))
{
const gchar *name;
const gchar *type;
const gchar *readable;
const gchar *writable;
const gchar *bits;
+ const gchar *branch;
name = find_attribute ("name", attribute_names, attribute_values);
type = find_attribute ("type", attribute_names, attribute_values);
readable = find_attribute ("readable", attribute_names, attribute_values);
writable = find_attribute ("writable", attribute_names, attribute_values);
bits = find_attribute ("bits", attribute_names, attribute_values);
+ branch = find_attribute ("branch", attribute_names, attribute_values);
if (name == NULL)
MISSING_ATTRIBUTE (error, element_name, "name");
@@ -724,6 +737,26 @@ start_field (GMarkupParseContext *context,
struct_->members = g_list_append (struct_->members, field);
}
break;
+ case G_IDL_NODE_UNION:
+ {
+ GIdlNodeUnion *union_;
+
+ union_ = (GIdlNodeUnion *)ctx->current_node;
+ union_->members = g_list_append (union_->members, field);
+ if (branch)
+ {
+ GIdlNodeConstant *constant;
+
+ constant = (GIdlNodeConstant *) g_idl_node_new (G_IDL_NODE_CONSTANT);
+ ((GIdlNode *)constant)->name = g_strdup (name);
+ constant->value = g_strdup (branch);
+ constant->type = union_->discriminator_type;
+ constant->deprecated = FALSE;
+
+ union_->discriminators = g_list_append (union_->discriminators, constant);
+ }
+ }
+ break;
}
}
return TRUE;
@@ -1424,6 +1457,88 @@ start_struct (GMarkupParseContext *context,
return FALSE;
}
+
+static gboolean
+start_union (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ ParseContext *ctx,
+ GError **error)
+{
+ if (strcmp (element_name, "union") == 0 &&
+ ctx->state == STATE_NAMESPACE)
+ {
+ const gchar *name;
+ const gchar *deprecated;
+ const gchar *typename;
+ const gchar *typeinit;
+
+ name = find_attribute ("name", attribute_names, attribute_values);
+ deprecated = find_attribute ("deprecated", attribute_names, attribute_values);
+ typename = find_attribute ("type-name", attribute_names, attribute_values);
+ typeinit = find_attribute ("get-type", attribute_names, attribute_values);
+
+ if (name == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "name");
+ else
+ {
+ GIdlNodeUnion *union_;
+
+ union_ = (GIdlNodeUnion *) g_idl_node_new (G_IDL_NODE_UNION);
+
+ ((GIdlNode *)union_)->name = g_strdup (name);
+ union_->gtype_name = g_strdup (typename);
+ union_->gtype_init = g_strdup (typeinit);
+ if (deprecated && strcmp (deprecated, "1") == 0)
+ union_->deprecated = TRUE;
+ else
+ union_->deprecated = FALSE;
+
+ ctx->current_node = (GIdlNode *)union_;
+ ctx->current_module->entries =
+ g_list_append (ctx->current_module->entries, union_);
+
+ ctx->state = STATE_UNION;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean
+start_discriminator (GMarkupParseContext *context,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values,
+ ParseContext *ctx,
+ GError **error)
+{
+ if (strcmp (element_name, "discriminator") == 0 &&
+ ctx->state == STATE_UNION)
+ {
+ const gchar *type;
+ const gchar *offset;
+
+ type = find_attribute ("type", attribute_names, attribute_values);
+ offset = find_attribute ("offset", attribute_names, attribute_values);
+ if (type == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "type");
+ else if (offset == NULL)
+ MISSING_ATTRIBUTE (error, element_name, "offset");
+ {
+ ((GIdlNodeUnion *)ctx->current_node)->discriminator_type
+ = parse_type (type);
+ ((GIdlNodeUnion *)ctx->current_node)->discriminator_offset
+ = atoi (offset);
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
static void
start_element_handler (GMarkupParseContext *context,
const gchar *element_name,
@@ -1477,6 +1592,13 @@ start_element_handler (GMarkupParseContext *context,
goto out;
break;
+ case 'd':
+ if (start_discriminator (context, element_name,
+ attribute_names, attribute_values,
+ ctx, error))
+ goto out;
+ break;
+
case 'e':
if (start_enum (context, element_name,
attribute_names, attribute_values,
@@ -1660,6 +1782,13 @@ start_element_handler (GMarkupParseContext *context,
break;
+ case 'u':
+ if (start_union (context, element_name,
+ attribute_names, attribute_values,
+ ctx, error))
+ goto out;
+ break;
+
case 'v':
if (start_vfunc (context, element_name,
attribute_names, attribute_values,
@@ -1725,6 +1854,8 @@ end_element_handler (GMarkupParseContext *context,
ctx->state = STATE_BOXED;
else if (ctx->current_node->type == G_IDL_NODE_STRUCT)
ctx->state = STATE_STRUCT;
+ else if (ctx->current_node->type == G_IDL_NODE_UNION)
+ ctx->state = STATE_UNION;
}
break;
@@ -1776,6 +1907,14 @@ end_element_handler (GMarkupParseContext *context,
ctx->state = STATE_NAMESPACE;
}
break;
+ case STATE_UNION:
+ if (strcmp (element_name, "union") == 0)
+ {
+ ctx->current_node = NULL;
+ ctx->state = STATE_NAMESPACE;
+ }
+ break;
+
case STATE_IMPLEMENTS:
ctx->state = STATE_OBJECT;
break;
diff --git a/src/ginfo.c b/src/ginfo.c
index 4e44043f..54234241 100644
--- a/src/ginfo.c
+++ b/src/ginfo.c
@@ -121,12 +121,16 @@ struct _GIArgInfo
GIBaseInfo base;
};
-
struct _GITypeInfo
{
GIBaseInfo base;
};
+struct _GIUnionInfo
+{
+ GIRegisteredTypeInfo registered;
+};
+
/* info creation */
GIBaseInfo *
@@ -232,6 +236,7 @@ g_base_info_get_name (GIBaseInfo *info)
case GI_INFO_TYPE_INTERFACE:
case GI_INFO_TYPE_CONSTANT:
case GI_INFO_TYPE_ERROR_DOMAIN:
+ case GI_INFO_TYPE_UNION:
{
CommonBlob *blob = (CommonBlob *)&info->metadata[info->offset];
@@ -1638,3 +1643,100 @@ g_constant_info_get_value (GIConstantInfo *info,
return blob->size;
}
+
+/* GIUnionInfo functions */
+gint
+g_union_info_get_n_fields (GIUnionInfo *info)
+{
+ GIBaseInfo *base = (GIBaseInfo *)info;
+ UnionBlob *blob = (UnionBlob *)&base->metadata[base->offset];
+
+ return blob->n_fields;
+}
+
+GIFieldInfo *
+g_union_info_get_field (GIUnionInfo *info,
+ gint n)
+{
+ GIBaseInfo *base = (GIBaseInfo *)info;
+ Header *header = (Header *)base->metadata;
+
+ return (GIFieldInfo *) g_info_new (GI_INFO_TYPE_FIELD, base, base->metadata,
+ base->offset + header->union_blob_size +
+ n * header->field_blob_size);
+}
+
+gint
+g_union_info_get_n_methods (GIUnionInfo *info)
+{
+ GIBaseInfo *base = (GIBaseInfo *)info;
+ UnionBlob *blob = (UnionBlob *)&base->metadata[base->offset];
+
+ return blob->n_functions;
+}
+
+GIFunctionInfo *
+g_union_info_get_method (GIUnionInfo *info,
+ gint n)
+{
+ GIBaseInfo *base = (GIBaseInfo *)info;
+ UnionBlob *blob = (UnionBlob *)&base->metadata[base->offset];
+ Header *header = (Header *)base->metadata;
+ gint offset;
+
+ offset = base->offset + header->union_blob_size
+ + blob->n_fields * header->field_blob_size
+ + n * header->function_blob_size;
+ return (GIFunctionInfo *) g_info_new (GI_INFO_TYPE_FUNCTION, base,
+ base->metadata, offset);
+}
+
+gboolean
+g_union_info_is_discriminated (GIUnionInfo *info)
+{
+ GIBaseInfo *base = (GIBaseInfo *)info;
+ UnionBlob *blob = (UnionBlob *)&base->metadata[base->offset];
+
+ return blob->discriminated;
+}
+
+gint
+g_union_info_get_discriminator_offset (GIUnionInfo *info)
+{
+ GIBaseInfo *base = (GIBaseInfo *)info;
+ UnionBlob *blob = (UnionBlob *)&base->metadata[base->offset];
+
+ return blob->discriminator_offset;
+}
+
+GITypeInfo *
+g_union_info_get_discriminator_type (GIUnionInfo *info)
+{
+ GIBaseInfo *base = (GIBaseInfo *)info;
+
+ return g_type_info_new (base, base->metadata, base->offset + 24);
+}
+
+GIConstantInfo *
+g_union_info_get_discriminator (GIUnionInfo *info,
+ gint n)
+{
+ GIBaseInfo *base = (GIBaseInfo *)info;
+ UnionBlob *blob = (UnionBlob *)&base->metadata[base->offset];
+
+ if (blob->discriminated)
+ {
+ Header *header = (Header *)base->metadata;
+ gint offset;
+
+ offset = base->offset + header->union_blob_size
+ + blob->n_fields * header->field_blob_size
+ + blob->n_functions * header->function_blob_size
+ + n * header->constant_blob_size;
+
+ return (GIConstantInfo *) g_info_new (GI_INFO_TYPE_CONSTANT, base,
+ base->metadata, offset);
+ }
+
+ return NULL;
+}
diff --git a/src/girepository.h b/src/girepository.h
index 6a20cd89..8839d5c1 100644
--- a/src/girepository.h
+++ b/src/girepository.h
@@ -37,6 +37,7 @@ typedef struct _GIFunctionInfo GIFunctionInfo;
typedef struct _GICallbackInfo GICallbackInfo;
typedef struct _GIRegisteredTypeInfo GIRegisteredTypeInfo;
typedef struct _GIStructInfo GIStructInfo;
+typedef struct _GIUnionInfo GIUnionInfo;
typedef struct _GIEnumInfo GIEnumInfo;
typedef struct _GIObjectInfo GIObjectInfo;
typedef struct _GIInterfaceInfo GIInterfaceInfo;
@@ -102,6 +103,7 @@ typedef enum
GI_INFO_TYPE_INTERFACE,
GI_INFO_TYPE_CONSTANT,
GI_INFO_TYPE_ERROR_DOMAIN,
+ GI_INFO_TYPE_UNION,
GI_INFO_TYPE_VALUE,
GI_INFO_TYPE_SIGNAL,
GI_INFO_TYPE_VFUNC,
@@ -284,6 +286,20 @@ gint g_field_info_get_offset (GIFieldInfo *info);
GITypeInfo * g_field_info_get_type (GIFieldInfo *info);
+/* GIUnionInfo */
+gint g_union_info_get_n_fields (GIUnionInfo *info);
+GIFieldInfo * g_union_info_get_field (GIUnionInfo *info,
+ gint n);
+gint g_union_info_get_n_methods (GIUnionInfo *info);
+GIFunctionInfo * g_union_info_get_method (GIUnionInfo *info,
+ gint n);
+gboolean g_union_info_is_discriminated (GIUnionInfo *info);
+gint g_union_info_get_discriminator_offset (GIUnionInfo *info);
+GITypeInfo * g_union_info_get_discriminator_type (GIUnionInfo *info);
+GIConstantInfo * g_union_info_get_discriminator (GIUnionInfo *info,
+ gint n);
+
+
/* GIStructInfo */
gint g_struct_info_get_n_fields (GIStructInfo *info);
GIFieldInfo * g_struct_info_get_field (GIStructInfo *info,
diff --git a/src/gmetadata.c b/src/gmetadata.c
index 40d7d6f1..0e613fce 100644
--- a/src/gmetadata.c
+++ b/src/gmetadata.c
@@ -36,7 +36,7 @@ void
g_metadata_check_sanity (void)
{
/* Check that struct layout is as we expect */
- g_assert (sizeof (Header) == 80);
+ g_assert (sizeof (Header) == 84);
g_assert (sizeof (DirEntry) == 12);
g_assert (sizeof (SimpleTypeBlob) == 4);
g_assert (sizeof (ArgBlob) == 12);
@@ -60,6 +60,7 @@ g_metadata_check_sanity (void)
g_assert (sizeof (InterfaceBlob) == 28);
g_assert (sizeof (ConstantBlob) == 20);
g_assert (sizeof (AnnotationBlob) == 12);
+ g_assert (sizeof (UnionBlob) == 28);
}
diff --git a/src/gmetadata.h b/src/gmetadata.h
index 39c2cd26..c09a6b1a 100644
--- a/src/gmetadata.h
+++ b/src/gmetadata.h
@@ -38,7 +38,8 @@ enum
BLOB_TYPE_OBJECT,
BLOB_TYPE_INTERFACE,
BLOB_TYPE_CONSTANT,
- BLOB_TYPE_ERROR_DOMAIN
+ BLOB_TYPE_ERROR_DOMAIN,
+ BLOB_TYPE_UNION
};
typedef struct
@@ -74,6 +75,9 @@ typedef struct
guint16 struct_blob_size;
guint16 object_blob_size;
guint16 interface_blob_size;
+ guint16 union_blob_size;
+
+ guint16 padding;
} Header;
typedef struct
@@ -292,6 +296,31 @@ typedef struct
#endif
} StructBlob;
+typedef struct
+{
+ guint16 blob_type;
+ guint deprecated : 1;
+ guint unregistered : 1;
+ guint discriminated : 1;
+ guint reserved :13;
+ guint32 name;
+
+ guint32 gtype_name;
+ guint32 gtype_init;
+
+ guint16 n_fields;
+ guint16 n_functions;
+
+ gint32 discriminator_offset;
+ SimpleTypeBlob discriminator_type;
+
+#if 0
+ FieldBlob fields[];
+ FunctionBlob functions[];
+ ConstantBlob discriminator_values[]
+#endif
+} UnionBlob;
+
typedef struct
{
guint16 blob_type;
diff --git a/tests/roundtrips.sh b/tests/roundtrips.sh
index 8ed422af..e5cd0fee 100755
--- a/tests/roundtrips.sh
+++ b/tests/roundtrips.sh
@@ -1,6 +1,6 @@
#! /bin/sh
-SIMPLE_TESTS="array.test boxed.test enum.test errors.test function.test interface.test"
+SIMPLE_TESTS="array.test boxed.test enum.test errors.test function.test interface.test union.test"
for i in $SIMPLE_TESTS; do
echo $i
diff --git a/tests/union.test b/tests/union.test
new file mode 100644
index 00000000..329512e1
--- /dev/null
+++ b/tests/union.test
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<api version="1.0">
+ <namespace name="Foo">
+ <union name="union1" type-name="UnionType1" get-type="union1_get_type">
+ <discriminator offset="-4" type="gint" />
+ <field name="field1" readable="1" writable="1" offset="0" type="guint32" branch="0" />
+ <field name="field1" readable="1" writable="1" offset="0" type="gdouble" branch="1" />
+ </union>
+ <union name="union2" type-name="UnionType1" get-type="union1_get_type">
+ <field name="field1" readable="1" writable="1" offset="0" type="guint32" />
+ <field name="field1" readable="1" writable="1" offset="0" type="gdouble" />
+ </union>
+ </namespace>
+</api>