diff options
-rw-r--r-- | ChangeLog | 27 | ||||
-rw-r--r-- | TODO | 3 | ||||
-rw-r--r-- | gidl.dtd | 20 | ||||
-rw-r--r-- | metadata-format.txt | 53 | ||||
-rw-r--r-- | src/generate.c | 174 | ||||
-rw-r--r-- | src/gidlmodule.c | 1 | ||||
-rw-r--r-- | src/gidlnode.c | 125 | ||||
-rw-r--r-- | src/gidlnode.h | 19 | ||||
-rw-r--r-- | src/gidlparser.c | 145 | ||||
-rw-r--r-- | src/ginfo.c | 104 | ||||
-rw-r--r-- | src/girepository.h | 16 | ||||
-rw-r--r-- | src/gmetadata.c | 3 | ||||
-rw-r--r-- | src/gmetadata.h | 31 | ||||
-rwxr-xr-x | tests/roundtrips.sh | 2 | ||||
-rw-r--r-- | tests/union.test | 14 |
15 files changed, 683 insertions, 54 deletions
@@ -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. @@ -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 ------- @@ -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> |