diff --git a/gibaseinfo.c b/gibaseinfo.c index c8444a5ea..81b936d85 100644 --- a/gibaseinfo.c +++ b/gibaseinfo.c @@ -475,7 +475,7 @@ g_base_info_get_attribute (GIBaseInfo *info, static int cmp_attribute (const void *av, - const void *bv) + const void *bv) { const AttributeBlob *a = av; const AttributeBlob *b = bv; @@ -488,13 +488,25 @@ cmp_attribute (const void *av, return 1; } -static AttributeBlob * -find_first_attribute (GIRealInfo *rinfo) +/* + * _attribute_blob_find_first: + * @GIBaseInfo: A #GIBaseInfo. + * @blob_offset: The offset for the blob to find the first attribute for. + * + * Searches for the first #AttributeBlob for @blob_offset and returns + * it if found. + * + * Returns: A pointer to #AttributeBlob or %NULL if not found. + */ +AttributeBlob * +_attribute_blob_find_first (GIBaseInfo *info, + guint32 blob_offset) { + GIRealInfo *rinfo = (GIRealInfo *) info; Header *header = (Header *)rinfo->typelib->data; AttributeBlob blob, *first, *res, *previous; - blob.offset = rinfo->offset; + blob.offset = blob_offset; first = (AttributeBlob *) &rinfo->typelib->data[header->attributes]; @@ -505,7 +517,7 @@ find_first_attribute (GIRealInfo *rinfo) return NULL; previous = res - 1; - while (previous >= first && previous->offset == rinfo->offset) + while (previous >= first && previous->offset == blob_offset) { res = previous; previous = res - 1; @@ -563,7 +575,7 @@ g_base_info_iterate_attributes (GIBaseInfo *info, if (iterator->data != NULL) next = (AttributeBlob *) iterator->data; else - next = find_first_attribute (rinfo); + next = _attribute_blob_find_first (info, rinfo->offset); if (next == NULL || next->offset != rinfo->offset || next >= after) return FALSE; diff --git a/gicallableinfo.c b/gicallableinfo.c index 6097cb483..6b79e62cc 100644 --- a/gicallableinfo.c +++ b/gicallableinfo.c @@ -19,6 +19,8 @@ * Boston, MA 02111-1307, USA. */ +#include + #include #include @@ -259,3 +261,77 @@ g_callable_info_load_arg (GICallableInfo *info, _g_info_init ((GIRealInfo*)arg, GI_INFO_TYPE_ARG, rinfo->repository, (GIBaseInfo*)info, rinfo->typelib, offset + header->signature_blob_size + n * header->arg_blob_size); } + +/** + * g_callable_info_get_return_attribute: + * @info: a #GICallableInfo + * @name: a freeform string naming an attribute + * + * Retrieve an arbitrary attribute associated with the return value. + * + * Returns: The value of the attribute, or %NULL if no such attribute exists + */ +const gchar * +g_callable_info_get_return_attribute (GICallableInfo *info, + const gchar *name) +{ + GIAttributeIter iter = { 0, }; + gchar *curname, *curvalue; + while (g_callable_info_iterate_return_attributes (info, &iter, &curname, &curvalue)) + { + if (g_strcmp0 (name, curname) == 0) + return (const gchar*) curvalue; + } + + return NULL; +} + +/** + * g_callable_info_iterate_return_attributes: + * @info: a #GICallableInfo + * @iterator: a #GIAttributeIter structure, must be initialized; see below + * @name: (out) (transfer none): Returned name, must not be freed + * @value: (out) (transfer none): Returned name, must not be freed + * + * Iterate over all attributes associated with the return value. The + * iterator structure is typically stack allocated, and must have its + * first member initialized to %NULL. + * + * Both the @name and @value should be treated as constants + * and must not be freed. + * + * See g_base_info_iterate_attributes() for an example of how to use a + * similar API. + * + * Returns: %TRUE if there are more attributes + */ +gboolean +g_callable_info_iterate_return_attributes (GICallableInfo *info, + GIAttributeIter *iterator, + char **name, + char **value) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header = (Header *)rinfo->typelib->data; + AttributeBlob *next, *after; + guint32 blob_offset; + + after = (AttributeBlob *) &rinfo->typelib->data[header->attributes + + header->n_attributes * header->attribute_blob_size]; + + blob_offset = signature_offset (info); + + if (iterator->data != NULL) + next = (AttributeBlob *) iterator->data; + else + next = _attribute_blob_find_first (info, blob_offset); + + if (next == NULL || next->offset != blob_offset || next >= after) + return FALSE; + + *name = (gchar*) g_typelib_get_string (rinfo->typelib, next->name); + *value = (gchar*) g_typelib_get_string (rinfo->typelib, next->value); + iterator->data = next + 1; + + return TRUE; +} diff --git a/gicallableinfo.h b/gicallableinfo.h index 479baa2ae..54d2cacb7 100644 --- a/gicallableinfo.h +++ b/gicallableinfo.h @@ -39,6 +39,12 @@ G_BEGIN_DECLS GITypeInfo * g_callable_info_get_return_type (GICallableInfo *info); void g_callable_info_load_return_type (GICallableInfo *info, GITypeInfo *type); +const gchar * g_callable_info_get_return_attribute (GICallableInfo *info, + const gchar *name); +gboolean g_callable_info_iterate_return_attributes (GICallableInfo *info, + GIAttributeIter *iterator, + char **name, + char **value); GITransfer g_callable_info_get_caller_owns (GICallableInfo *info); gboolean g_callable_info_may_return_null (GICallableInfo *info); gint g_callable_info_get_n_args (GICallableInfo *info); diff --git a/girnode.c b/girnode.c index fbdcdf965..576ac1006 100644 --- a/girnode.c +++ b/girnode.c @@ -1678,6 +1678,14 @@ g_ir_node_build_typelib (GIrNode *node, blob->symbol = write_string (function->symbol, strings, data, offset2); blob->signature = signature; + /* function->result is special since it doesn't appear in the serialized format but + * we do want the attributes for it to appear + */ + build->nodes_with_attributes = g_list_prepend (build->nodes_with_attributes, function->result); + build->n_attributes += g_hash_table_size (((GIrNode *) function->result)->attributes); + g_assert (((GIrNode *) function->result)->offset == 0); + ((GIrNode *) function->result)->offset = signature; + g_debug ("building function '%s'", function->symbol); g_ir_node_build_typelib ((GIrNode *)function->result->type, @@ -1770,6 +1778,14 @@ g_ir_node_build_typelib (GIrNode *node, blob->name = write_string (node->name, strings, data, offset2); blob->signature = signature; + /* signal->result is special since it doesn't appear in the serialized format but + * we do want the attributes for it to appear + */ + build->nodes_with_attributes = g_list_prepend (build->nodes_with_attributes, signal->result); + build->n_attributes += g_hash_table_size (((GIrNode *) signal->result)->attributes); + g_assert (((GIrNode *) signal->result)->offset == 0); + ((GIrNode *) signal->result)->offset = signature; + g_ir_node_build_typelib ((GIrNode *)signal->result->type, node, build, &signature, offset2); diff --git a/girparser.c b/girparser.c index 2713bb463..5efe7fded 100644 --- a/girparser.c +++ b/girparser.c @@ -1990,7 +1990,14 @@ start_attribute (GMarkupParseContext *context, curnode = CURRENT_NODE (ctx); - g_hash_table_insert (curnode->attributes, g_strdup (name), g_strdup (value)); + if (ctx->current_typed && ctx->current_typed->type == G_IR_NODE_PARAM) + { + g_hash_table_insert (ctx->current_typed->attributes, g_strdup (name), g_strdup (value)); + } + else + { + g_hash_table_insert (curnode->attributes, g_strdup (name), g_strdup (value)); + } return TRUE; } diff --git a/girwriter.c b/girwriter.c index b123a1345..19862b0da 100644 --- a/girwriter.c +++ b/girwriter.c @@ -358,7 +358,7 @@ write_type_info (const gchar *namespace, static void write_attributes (Xml *file, - GIBaseInfo *info) + GIBaseInfo *info) { GIAttributeIter iter = { 0, }; char *name, *value; @@ -371,6 +371,21 @@ write_attributes (Xml *file, } } +static void +write_return_value_attributes (Xml *file, + GICallableInfo *info) +{ + GIAttributeIter iter = { 0, }; + char *name, *value; + + while (g_callable_info_iterate_return_attributes (info, &iter, &name, &value)) + { + xml_start_element (file, "attribute"); + xml_printf (file, " name=\"%s\" value=\"%s\"", name, value); + xml_end_element (file, "attribute"); + } +} + static void write_constant_value (const gchar *namespace, GITypeInfo *info, @@ -467,6 +482,8 @@ write_callable_info (const gchar *namespace, if (g_callable_info_may_return_null (info)) xml_printf (file, " allow-none=\"1\""); + write_return_value_attributes (file, info); + write_type_info (namespace, type, file); xml_end_element (file, "return-value"); @@ -528,6 +545,8 @@ write_callable_info (const gchar *namespace, if (g_arg_info_get_destroy (arg) >= 0) xml_printf (file, " destroy=\"%d\"", g_arg_info_get_destroy (arg)); + write_attributes (file, (GIBaseInfo*) arg); + type = g_arg_info_get_type (arg); write_type_info (namespace, type, file); diff --git a/gitypelib-internal.h b/gitypelib-internal.h index 90113ac2c..d4577acc7 100644 --- a/gitypelib-internal.h +++ b/gitypelib-internal.h @@ -1110,6 +1110,10 @@ gboolean g_typelib_validate (GTypelib *typelib, GError **error); +/* defined in gibaseinfo.c */ +AttributeBlob *_attribute_blob_find_first (GIBaseInfo *info, + guint32 blob_offset); + G_END_DECLS #endif /* __G_TYPELIB_H__ */