diff options
author | Johan Dahlin <johan@gnome.org> | 2010-06-07 10:52:43 -0300 |
---|---|---|
committer | Johan Dahlin <johan@gnome.org> | 2010-06-07 10:52:43 -0300 |
commit | 0c550391b29da17446e22cebb1ccbacf8561983d (patch) | |
tree | d88b31fb9a184b8c5bd10341fe503946e87d58b5 /girepository/girwriter.c | |
parent | e945a3cfdd3e599590075fe88f8c026ee96ce090 (diff) | |
download | gobject-introspection-0c550391b29da17446e22cebb1ccbacf8561983d.tar.gz |
[girwriter] Refactor out of generate.c
Move out the girwriter out of generate.c. Still a private API,
but that will probably change in the future.
Diffstat (limited to 'girepository/girwriter.c')
-rw-r--r-- | girepository/girwriter.c | 1402 |
1 files changed, 1402 insertions, 0 deletions
diff --git a/girepository/girwriter.c b/girepository/girwriter.c new file mode 100644 index 00000000..6fa892db --- /dev/null +++ b/girepository/girwriter.c @@ -0,0 +1,1402 @@ + +/* -*- Mode: C; c-file-style: "gnu"; -*- */ +/* GObject introspection: IDL generator + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <errno.h> +#include <string.h> +#include <stdio.h> + +#include <glib.h> +#include <glib-object.h> +#include <glib/gstdio.h> + +#include "girwriter.h" +#include "girepository.h" +#include "gitypelib-internal.h" + +typedef struct { + FILE *file; + GSList *stack; + gboolean show_all; +} Xml; + +typedef struct { + char *name; + guint has_children : 1; +} XmlElement; + +static XmlElement * +xml_element_new (const char *name) +{ + XmlElement *elem; + + elem = g_new (XmlElement, 1); + elem->name = g_strdup (name); + elem->has_children = FALSE; + return elem; +} + +static void +xml_element_free (XmlElement *elem) +{ + g_free (elem->name); + g_free (elem); +} + +static void +xml_printf (Xml *xml, const char *fmt, ...) +{ + va_list ap; + char *s; + + va_start (ap, fmt); + s = g_markup_vprintf_escaped (fmt, ap); + fputs (s, xml->file); + g_free (s); + va_end (ap); +} + +static void +xml_start_element (Xml *xml, const char *element_name) +{ + XmlElement *parent = NULL; + + if (xml->stack) + { + parent = xml->stack->data; + + if (!parent->has_children) + xml_printf (xml, ">\n"); + + parent->has_children = TRUE; + } + + xml_printf (xml, "%*s<%s", g_slist_length(xml->stack)*2, "", element_name); + + xml->stack = g_slist_prepend (xml->stack, xml_element_new (element_name)); +} + +static void +xml_end_element (Xml *xml, const char *name) +{ + XmlElement *elem; + + g_assert (xml->stack != NULL); + + elem = xml->stack->data; + xml->stack = g_slist_delete_link (xml->stack, xml->stack); + + if (name != NULL) + g_assert_cmpstr (name, ==, elem->name); + + if (elem->has_children) + xml_printf (xml, "%*s</%s>\n", g_slist_length (xml->stack)*2, "", elem->name); + else + xml_printf (xml, "/>\n"); + + xml_element_free (elem); +} + +static void +xml_end_element_unchecked (Xml *xml) +{ + xml_end_element (xml, NULL); +} + +static Xml * +xml_open (FILE *file) +{ + Xml *xml; + + xml = g_new (Xml, 1); + xml->file = file; + xml->stack = NULL; + + return xml; +} + +static void +xml_close (Xml *xml) +{ + g_assert (xml->stack == NULL); + if (xml->file != NULL) + { + fflush (xml->file); + if (xml->file != stdout) + fclose (xml->file); + xml->file = NULL; + } +} + +static void +xml_free (Xml *xml) +{ + xml_close (xml); + g_free (xml); +} + + +static void +check_unresolved (GIBaseInfo *info) +{ + if (g_base_info_get_type (info) != GI_INFO_TYPE_UNRESOLVED) + return; + + g_critical ("Found unresolved type '%s' '%s'\n", + g_base_info_get_name (info), g_base_info_get_namespace (info)); +} + +static void +write_type_name (const gchar *namespace, + GIBaseInfo *info, + Xml *file) +{ + if (strcmp (namespace, g_base_info_get_namespace (info)) != 0) + xml_printf (file, "%s.", g_base_info_get_namespace (info)); + + xml_printf (file, "%s", g_base_info_get_name (info)); +} + +static void +write_type_name_attribute (const gchar *namespace, + GIBaseInfo *info, + const char *attr_name, + Xml *file) +{ + xml_printf (file, " %s=\"", attr_name); + write_type_name (namespace, info, file); + xml_printf (file, "\""); +} + +static void +write_type_info (const gchar *namespace, + GITypeInfo *info, + Xml *file) +{ + gint tag; + gint i; + GITypeInfo *type; + gboolean is_pointer; + + check_unresolved ((GIBaseInfo*)info); + + tag = g_type_info_get_tag (info); + is_pointer = g_type_info_is_pointer (info); + + if (tag == GI_TYPE_TAG_VOID) + { + xml_start_element (file, "type"); + + xml_printf (file, " name=\"%s\"", is_pointer ? "any" : "none"); + + xml_end_element (file, "type"); + } + else if (G_TYPE_TAG_IS_BASIC (tag)) + { + xml_start_element (file, "type"); + xml_printf (file, " name=\"%s\"", g_type_tag_to_string (tag)); + xml_end_element (file, "type"); + } + else if (tag == GI_TYPE_TAG_ARRAY) + { + gint length, size; + char *name = NULL; + + xml_start_element (file, "array"); + + switch (g_type_info_get_array_type (info)) { + case GI_ARRAY_TYPE_C: + break; + case GI_ARRAY_TYPE_ARRAY: + name = "GLib.Array"; + break; + case GI_ARRAY_TYPE_PTR_ARRAY: + name = "GLib.PtrArray"; + break; + case GI_ARRAY_TYPE_BYTE_ARRAY: + name = "GLib.ByteArray"; + break; + default: + break; + } + + if (name) + xml_printf (file, " name=\"%s\"", name); + + type = g_type_info_get_param_type (info, 0); + + length = g_type_info_get_array_length (info); + if (length >= 0) + xml_printf (file, " length=\"%d\"", length); + + size = g_type_info_get_array_fixed_size (info); + if (size >= 0) + xml_printf (file, " fixed-size=\"%d\"", size); + + if (g_type_info_is_zero_terminated (info)) + xml_printf (file, " zero-terminated=\"1\""); + + write_type_info (namespace, type, file); + + g_base_info_unref ((GIBaseInfo *)type); + + xml_end_element (file, "array"); + } + else if (tag == GI_TYPE_TAG_INTERFACE) + { + GIBaseInfo *iface = g_type_info_get_interface (info); + xml_start_element (file, "type"); + write_type_name_attribute (namespace, iface, "name", file); + xml_end_element (file, "type"); + g_base_info_unref (iface); + } + else if (tag == GI_TYPE_TAG_GLIST) + { + xml_start_element (file, "type"); + xml_printf (file, " name=\"GLib.List\""); + type = g_type_info_get_param_type (info, 0); + if (type) + { + write_type_info (namespace, type, file); + g_base_info_unref ((GIBaseInfo *)type); + } + xml_end_element (file, "type"); + } + else if (tag == GI_TYPE_TAG_GSLIST) + { + xml_start_element (file, "type"); + xml_printf (file, " name=\"GLib.SList\""); + type = g_type_info_get_param_type (info, 0); + if (type) + { + write_type_info (namespace, type, file); + g_base_info_unref ((GIBaseInfo *)type); + } + xml_end_element (file, "type"); + } + else if (tag == GI_TYPE_TAG_GHASH) + { + xml_start_element (file, "type"); + xml_printf (file, " name=\"GLib.HashTable\""); + type = g_type_info_get_param_type (info, 0); + if (type) + { + write_type_info (namespace, type, file); + g_base_info_unref ((GIBaseInfo *)type); + type = g_type_info_get_param_type (info, 1); + write_type_info (namespace, type, file); + g_base_info_unref ((GIBaseInfo *)type); + } + xml_end_element (file, "type"); + } + else if (tag == GI_TYPE_TAG_ERROR) + { + gint n; + + xml_start_element (file, "type"); + xml_printf (file, " name=\"GLib.Error\""); + + n = g_type_info_get_n_error_domains (info); + if (n > 0) + { + for (i = 0; i < n; i++) + { + GIErrorDomainInfo *ed = g_type_info_get_error_domain (info, i); + xml_start_element (file, "type"); + write_type_name_attribute (namespace, (GIBaseInfo *)ed, "name", file); + xml_end_element (file, "type"); + g_base_info_unref ((GIBaseInfo *)ed); + } + } + + xml_end_element (file, "type"); + } + else + { + g_printerr ("Unhandled type tag %d\n", tag); + g_assert_not_reached (); + } +} + +static void +write_attributes (Xml *file, + GIBaseInfo *info) +{ + GIAttributeIter iter = { 0, }; + char *name, *value; + + while (g_base_info_iterate_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, + GArgument *argument, + Xml *file); + +static void +write_callback_info (const gchar *namespace, + GICallbackInfo *info, + Xml *file); + +static void +write_field_info (const gchar *namespace, + GIFieldInfo *info, + GIConstantInfo *branch, + Xml *file) +{ + const gchar *name; + GIFieldInfoFlags flags; + gint size; + gint offset; + GITypeInfo *type; + GIBaseInfo *interface; + GArgument value; + + name = g_base_info_get_name ((GIBaseInfo *)info); + flags = g_field_info_get_flags (info); + size = g_field_info_get_size (info); + offset = g_field_info_get_offset (info); + + xml_start_element (file, "field"); + xml_printf (file, " name=\"%s\"", name); + + /* Fields are assumed to be read-only + * (see also girwriter.py and girparser.c) + */ + if (!(flags & GI_FIELD_IS_READABLE)) + xml_printf (file, " readable=\"0\""); + if (flags & GI_FIELD_IS_WRITABLE) + xml_printf (file, " writable=\"1\""); + + if (size) + xml_printf (file, " bits=\"%d\"", size); + + write_attributes (file, (GIBaseInfo*) info); + + type = g_field_info_get_type (info); + + if (branch) + { + xml_printf (file, " branch=\""); + type = g_constant_info_get_type (branch); + g_constant_info_get_value (branch, &value); + write_constant_value (namespace, type, &value, file); + xml_printf (file, "\""); + } + + if (file->show_all) + { + if (offset >= 0) + xml_printf (file, "offset=\"%d\"", offset); + } + + interface = g_type_info_get_interface (type); + if (interface && g_base_info_get_type(interface) == GI_INFO_TYPE_CALLBACK) + write_callback_info (namespace, (GICallbackInfo *)interface, file); + else + write_type_info (namespace, type, file); + + if (interface) + g_base_info_unref (interface); + + g_base_info_unref ((GIBaseInfo *)type); + + xml_end_element (file, "field"); +} + +static void +write_callable_info (const gchar *namespace, + GICallableInfo *info, + Xml *file) +{ + GITypeInfo *type; + gint i; + + write_attributes (file, (GIBaseInfo*) info); + + type = g_callable_info_get_return_type (info); + + xml_start_element (file, "return-value"); + + switch (g_callable_info_get_caller_owns (info)) + { + case GI_TRANSFER_NOTHING: + xml_printf (file, " transfer-ownership=\"none\""); + break; + case GI_TRANSFER_CONTAINER: + xml_printf (file, " transfer-ownership=\"container\""); + break; + case GI_TRANSFER_EVERYTHING: + xml_printf (file, " transfer-ownership=\"full\""); + break; + default: + g_assert_not_reached (); + } + + if (g_callable_info_may_return_null (info)) + xml_printf (file, " allow-none=\"1\""); + + write_type_info (namespace, type, file); + + xml_end_element (file, "return-value"); + + if (g_callable_info_get_n_args (info) <= 0) + return; + + xml_start_element (file, "parameters"); + for (i = 0; i < g_callable_info_get_n_args (info); i++) + { + GIArgInfo *arg = g_callable_info_get_arg (info, i); + + xml_start_element (file, "parameter"); + xml_printf (file, " name=\"%s\"", + g_base_info_get_name ((GIBaseInfo *) arg)); + + switch (g_arg_info_get_ownership_transfer (arg)) + { + case GI_TRANSFER_NOTHING: + xml_printf (file, " transfer-ownership=\"none\""); + break; + case GI_TRANSFER_CONTAINER: + xml_printf (file, " transfer-ownership=\"container\""); + break; + case GI_TRANSFER_EVERYTHING: + xml_printf (file, " transfer-ownership=\"full\""); + break; + default: + g_assert_not_reached (); + } + + switch (g_arg_info_get_direction (arg)) + { + case GI_DIRECTION_IN: + break; + case GI_DIRECTION_OUT: + xml_printf (file, " direction=\"out\" caller-allocates=\"%s\"", + g_arg_info_is_caller_allocates (arg) ? "1" : "0"); + break; + case GI_DIRECTION_INOUT: + xml_printf (file, " direction=\"inout\""); + break; + } + + if (g_arg_info_may_be_null (arg)) + xml_printf (file, " allow-none=\"1\""); + + if (g_arg_info_is_return_value (arg)) + xml_printf (file, " retval=\"1\""); + + if (g_arg_info_is_optional (arg)) + xml_printf (file, " optional=\"1\""); + + switch (g_arg_info_get_scope (arg)) + { + case GI_SCOPE_TYPE_INVALID: + break; + case GI_SCOPE_TYPE_CALL: + xml_printf (file, " scope=\"call\""); + break; + case GI_SCOPE_TYPE_ASYNC: + xml_printf (file, " scope=\"async\""); + break; + case GI_SCOPE_TYPE_NOTIFIED: + xml_printf (file, " scope=\"notified\""); + break; + } + + if (g_arg_info_get_closure (arg) >= 0) + xml_printf (file, " closure=\"%d\"", g_arg_info_get_closure (arg)); + + if (g_arg_info_get_destroy (arg) >= 0) + xml_printf (file, " destroy=\"%d\"", g_arg_info_get_destroy (arg)); + + type = g_arg_info_get_type (arg); + write_type_info (namespace, type, file); + + xml_end_element (file, "parameter"); + + g_base_info_unref ((GIBaseInfo *)arg); + } + + xml_end_element (file, "parameters"); + g_base_info_unref ((GIBaseInfo *)type); +} + +static void +write_function_info (const gchar *namespace, + GIFunctionInfo *info, + Xml *file) +{ + GIFunctionInfoFlags flags; + const gchar *tag; + const gchar *name; + const gchar *symbol; + gboolean deprecated; + gboolean throws; + + flags = g_function_info_get_flags (info); + name = g_base_info_get_name ((GIBaseInfo *)info); + symbol = g_function_info_get_symbol (info); + deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info); + throws = flags & GI_FUNCTION_THROWS; + + if (flags & GI_FUNCTION_IS_CONSTRUCTOR) + tag = "constructor"; + else if (flags & GI_FUNCTION_IS_METHOD) + tag = "method"; + else + tag = "function"; + + xml_start_element (file, tag); + xml_printf (file, " name=\"%s\" c:identifier=\"%s\"", + name, symbol); + + if (flags & GI_FUNCTION_IS_SETTER) + xml_printf (file, " type=\"setter\""); + else if (flags & GI_FUNCTION_IS_GETTER) + xml_printf (file, " type=\"getter\""); + + if (deprecated) + xml_printf (file, " deprecated=\"1\""); + + if (throws) + xml_printf (file, " throws=\"1\""); + + write_callable_info (namespace, (GICallableInfo*)info, file); + xml_end_element (file, tag); +} + +static void +write_callback_info (const gchar *namespace, + GICallbackInfo *info, + Xml *file) +{ + const gchar *name; + gboolean deprecated; + + name = g_base_info_get_name ((GIBaseInfo *)info); + deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info); + + xml_start_element (file, "callback"); + xml_printf (file, " name=\"%s\"", name); + + if (deprecated) + xml_printf (file, " deprecated=\"1\""); + + write_callable_info (namespace, (GICallableInfo*)info, file); + xml_end_element (file, "callback"); +} + +static void +write_struct_info (const gchar *namespace, + GIStructInfo *info, + Xml *file) +{ + const gchar *name; + const gchar *type_name; + const gchar *type_init; + gboolean deprecated; + gboolean is_gtype_struct; + gboolean foreign; + gint i; + gint size; + int n_elts; + + 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); + + if (g_base_info_get_type ((GIBaseInfo *)info) == GI_INFO_TYPE_BOXED) + { + xml_start_element (file, "glib:boxed"); + xml_printf (file, " glib:name=\"%s\"", name); + } + else + { + xml_start_element (file, "record"); + xml_printf (file, " name=\"%s\"", name); + } + + if (type_name != NULL) + xml_printf (file, " glib:type-name=\"%s\" glib:get-type=\"%s\"", type_name, type_init); + + if (deprecated) + xml_printf (file, " deprecated=\"1\""); + + is_gtype_struct = g_struct_info_is_gtype_struct (info); + if (is_gtype_struct) + xml_printf (file, " glib:is-gtype-struct=\"1\""); + + write_attributes (file, (GIBaseInfo*) info); + + size = g_struct_info_get_size (info); + if (file->show_all && size >= 0) + xml_printf (file, " size=\"%d\"", size); + + foreign = g_struct_info_is_foreign (info); + if (foreign) + xml_printf (file, " foreign=\"1\""); + + n_elts = g_struct_info_get_n_fields (info) + g_struct_info_get_n_methods (info); + if (n_elts > 0) + { + 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, NULL, file); + g_base_info_unref ((GIBaseInfo *)field); + } + + for (i = 0; i < g_struct_info_get_n_methods (info); i++) + { + GIFunctionInfo *function = g_struct_info_get_method (info, i); + write_function_info (namespace, function, file); + g_base_info_unref ((GIBaseInfo *)function); + } + + } + + xml_end_element_unchecked (file); +} + +static void +write_value_info (const gchar *namespace, + GIValueInfo *info, + Xml *file) +{ + const gchar *name; + glong value; + gboolean deprecated; + + name = g_base_info_get_name ((GIBaseInfo *)info); + value = g_value_info_get_value (info); + deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info); + + xml_start_element (file, "member"); + xml_printf (file, " name=\"%s\" value=\"%ld\"", name, value); + + if (deprecated) + xml_printf (file, " deprecated=\"1\""); + + write_attributes (file, (GIBaseInfo*) info); + + xml_end_element (file, "member"); +} + +static void +write_constant_value (const gchar *namespace, + GITypeInfo *type, + GArgument *value, + Xml *file) +{ + switch (g_type_info_get_tag (type)) + { + case GI_TYPE_TAG_BOOLEAN: + xml_printf (file, "%d", value->v_boolean); + break; + case GI_TYPE_TAG_INT8: + xml_printf (file, "%d", value->v_int8); + break; + case GI_TYPE_TAG_UINT8: + xml_printf (file, "%d", value->v_uint8); + break; + case GI_TYPE_TAG_INT16: + xml_printf (file, "%" G_GINT16_FORMAT, value->v_int16); + break; + case GI_TYPE_TAG_UINT16: + xml_printf (file, "%" G_GUINT16_FORMAT, value->v_uint16); + break; + case GI_TYPE_TAG_INT32: + xml_printf (file, "%" G_GINT32_FORMAT, value->v_int32); + break; + case GI_TYPE_TAG_UINT32: + xml_printf (file, "%" G_GUINT32_FORMAT, value->v_uint32); + break; + case GI_TYPE_TAG_INT64: + xml_printf (file, "%" G_GINT64_FORMAT, value->v_int64); + break; + case GI_TYPE_TAG_UINT64: + xml_printf (file, "%" G_GUINT64_FORMAT, value->v_uint64); + break; + case GI_TYPE_TAG_INT: + xml_printf (file, "%d", value->v_int); + break; + case GI_TYPE_TAG_UINT: + xml_printf (file, "%d", value->v_uint); + break; + case GI_TYPE_TAG_LONG: + xml_printf (file, "%ld", value->v_long); + break; + case GI_TYPE_TAG_ULONG: + xml_printf (file, "%ld", value->v_ulong); + break; + case GI_TYPE_TAG_SSIZE: + xml_printf (file, "%zd", value->v_ssize); + break; + case GI_TYPE_TAG_SIZE: + xml_printf (file, "%zd", value->v_size); + break; + case GI_TYPE_TAG_FLOAT: + xml_printf (file, "%f", value->v_float); + break; + case GI_TYPE_TAG_DOUBLE: + xml_printf (file, "%f", value->v_double); + break; + case GI_TYPE_TAG_UTF8: + case GI_TYPE_TAG_FILENAME: + xml_printf (file, "%s", value->v_string); + break; + default: + g_assert_not_reached (); + } +} + +static void +write_constant_info (const gchar *namespace, + GIConstantInfo *info, + Xml *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); + + xml_start_element (file, "constant"); + xml_printf (file, " name=\"%s\"", name); + + type = g_constant_info_get_type (info); + xml_printf (file, " value=\""); + + g_constant_info_get_value (info, &value); + write_constant_value (namespace, type, &value, file); + xml_printf (file, "\""); + + write_type_info (namespace, type, file); + + write_attributes (file, (GIBaseInfo*) info); + + xml_end_element (file, "constant"); + + g_base_info_unref ((GIBaseInfo *)type); +} + + +static void +write_enum_info (const gchar *namespace, + GIEnumInfo *info, + Xml *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); + + if (g_base_info_get_type ((GIBaseInfo *)info) == GI_INFO_TYPE_ENUM) + xml_start_element (file, "enumeration"); + else + xml_start_element (file, "bitfield"); + xml_printf (file, " name=\"%s\"", name); + + if (type_init) + xml_printf (file, " glib:type-name=\"%s\" glib:get-type=\"%s\"", type_name, type_init); + + if (deprecated) + xml_printf (file, " deprecated=\"1\""); + + write_attributes (file, (GIBaseInfo*) info); + + for (i = 0; i < g_enum_info_get_n_values (info); i++) + { + GIValueInfo *value = g_enum_info_get_value (info, i); + write_value_info (namespace, value, file); + g_base_info_unref ((GIBaseInfo *)value); + } + + xml_end_element_unchecked (file); +} + +static void +write_signal_info (const gchar *namespace, + GISignalInfo *info, + Xml *file) +{ + GSignalFlags flags; + const gchar *name; + gboolean deprecated; + + name = g_base_info_get_name ((GIBaseInfo *)info); + flags = g_signal_info_get_flags (info); + deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info); + + xml_start_element (file, "glib:signal"); + xml_printf (file, " name=\"%s\"", name); + + if (deprecated) + xml_printf (file, " deprecated=\"1\""); + + if (flags & G_SIGNAL_RUN_FIRST) + xml_printf (file, " when=\"FIRST\""); + else if (flags & G_SIGNAL_RUN_LAST) + xml_printf (file, " when=\"LAST\""); + else if (flags & G_SIGNAL_RUN_CLEANUP) + xml_printf (file, " when=\"CLEANUP\""); + + if (flags & G_SIGNAL_NO_RECURSE) + xml_printf (file, " no-recurse=\"1\""); + + if (flags & G_SIGNAL_DETAILED) + xml_printf (file, " detailed=\"1\""); + + if (flags & G_SIGNAL_ACTION) + xml_printf (file, " action=\"1\""); + + if (flags & G_SIGNAL_NO_HOOKS) + xml_printf (file, " no-hooks=\"1\""); + + write_callable_info (namespace, (GICallableInfo*)info, file); + + xml_end_element (file, "glib:signal"); +} + +static void +write_vfunc_info (const gchar *namespace, + GIVFuncInfo *info, + Xml *file) +{ + GIVFuncInfoFlags flags; + const gchar *name; + GIFunctionInfo *invoker; + gboolean deprecated; + gint offset; + + name = g_base_info_get_name ((GIBaseInfo *)info); + flags = g_vfunc_info_get_flags (info); + deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info); + offset = g_vfunc_info_get_offset (info); + invoker = g_vfunc_info_get_invoker (info); + + xml_start_element (file, "virtual-method"); + xml_printf (file, " name=\"%s\"", name); + + if (deprecated) + xml_printf (file, " deprecated=\"1\""); + + if (flags & GI_VFUNC_MUST_CHAIN_UP) + xml_printf (file, " must-chain-up=\"1\""); + + if (flags & GI_VFUNC_MUST_OVERRIDE) + xml_printf (file, " override=\"always\""); + else if (flags & GI_VFUNC_MUST_NOT_OVERRIDE) + xml_printf (file, " override=\"never\""); + + xml_printf (file, " offset=\"%d\"", offset); + + if (invoker) + xml_printf (file, " invoker=\"%s\"", g_base_info_get_name ((GIBaseInfo*)invoker)); + + write_callable_info (namespace, (GICallableInfo*)info, file); + + xml_end_element (file, "virtual-method"); +} + +static void +write_property_info (const gchar *namespace, + GIPropertyInfo *info, + Xml *file) +{ + GParamFlags flags; + const gchar *name; + gboolean deprecated; + GITypeInfo *type; + + name = g_base_info_get_name ((GIBaseInfo *)info); + flags = g_property_info_get_flags (info); + deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info); + + xml_start_element (file, "property"); + xml_printf (file, " name=\"%s\"", name); + + if (deprecated) + xml_printf (file, " deprecated=\"1\""); + + /* Properties are assumed to be read-only (see also girwriter.py) */ + if (!(flags & G_PARAM_READABLE)) + xml_printf (file, " readable=\"0\""); + if (flags & G_PARAM_WRITABLE) + xml_printf (file, " writable=\"1\""); + + if (flags & G_PARAM_CONSTRUCT) + xml_printf (file, " construct=\"1\""); + + if (flags & G_PARAM_CONSTRUCT_ONLY) + xml_printf (file, " construct-only=\"1\""); + + write_attributes (file, (GIBaseInfo*) info); + + type = g_property_info_get_type (info); + + write_type_info (namespace, type, file); + + xml_end_element (file, "property"); +} + +static void +write_object_info (const gchar *namespace, + GIObjectInfo *info, + Xml *file) +{ + const gchar *name; + const gchar *type_name; + const gchar *type_init; + gboolean deprecated; + gboolean is_abstract; + GIObjectInfo *pnode; + GIStructInfo *class_struct; + gint i; + + name = g_base_info_get_name ((GIBaseInfo *)info); + deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info); + is_abstract = g_object_info_get_abstract (info); + + type_name = g_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info); + type_init = g_registered_type_info_get_type_init ((GIRegisteredTypeInfo*)info); + xml_start_element (file, "class"); + xml_printf (file, " name=\"%s\"", name); + + pnode = g_object_info_get_parent (info); + if (pnode) + { + write_type_name_attribute (namespace, (GIBaseInfo *)pnode, "parent", file); + g_base_info_unref ((GIBaseInfo *)pnode); + } + + class_struct = g_object_info_get_class_struct (info); + if (class_struct) + { + write_type_name_attribute (namespace, (GIBaseInfo*) class_struct, "glib:type-struct", file); + g_base_info_unref ((GIBaseInfo*)class_struct); + } + + if (is_abstract) + xml_printf (file, " abstract=\"1\""); + + xml_printf (file, " glib:type-name=\"%s\" glib:get-type=\"%s\"", type_name, type_init); + + if (deprecated) + xml_printf (file, " deprecated=\"1\""); + + write_attributes (file, (GIBaseInfo*) info); + + if (g_object_info_get_n_interfaces (info) > 0) + { + for (i = 0; i < g_object_info_get_n_interfaces (info); i++) + { + GIInterfaceInfo *imp = g_object_info_get_interface (info, i); + xml_start_element (file, "implements"); + write_type_name_attribute (namespace, (GIBaseInfo *)imp, "name", file); + xml_end_element (file, "implements"); + g_base_info_unref ((GIBaseInfo*)imp); + } + } + + 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, NULL, file); + g_base_info_unref ((GIBaseInfo *)field); + } + + for (i = 0; i < g_object_info_get_n_methods (info); i++) + { + GIFunctionInfo *function = g_object_info_get_method (info, i); + write_function_info (namespace, function, file); + g_base_info_unref ((GIBaseInfo *)function); + } + + for (i = 0; i < g_object_info_get_n_properties (info); i++) + { + GIPropertyInfo *prop = g_object_info_get_property (info, i); + write_property_info (namespace, prop, file); + g_base_info_unref ((GIBaseInfo *)prop); + } + + for (i = 0; i < g_object_info_get_n_signals (info); i++) + { + GISignalInfo *signal = g_object_info_get_signal (info, i); + write_signal_info (namespace, signal, file); + g_base_info_unref ((GIBaseInfo *)signal); + } + + for (i = 0; i < g_object_info_get_n_vfuncs (info); i++) + { + GIVFuncInfo *vfunc = g_object_info_get_vfunc (info, i); + write_vfunc_info (namespace, vfunc, file); + g_base_info_unref ((GIBaseInfo *)vfunc); + } + + for (i = 0; i < g_object_info_get_n_constants (info); i++) + { + GIConstantInfo *constant = g_object_info_get_constant (info, i); + write_constant_info (namespace, constant, file); + g_base_info_unref ((GIBaseInfo *)constant); + } + + xml_end_element (file, "class"); +} + +static void +write_interface_info (const gchar *namespace, + GIInterfaceInfo *info, + Xml *file) +{ + const gchar *name; + const gchar *type_name; + const gchar *type_init; + GIStructInfo *class_struct; + 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); + xml_start_element (file, "interface"); + xml_printf (file, " name=\"%s\" glib:type-name=\"%s\" glib:get-type=\"%s\"", + name, type_name, type_init); + + class_struct = g_interface_info_get_iface_struct (info); + if (class_struct) + { + write_type_name_attribute (namespace, (GIBaseInfo*) class_struct, "glib:type-struct", file); + g_base_info_unref ((GIBaseInfo*)class_struct); + } + + if (deprecated) + xml_printf (file, " deprecated=\"1\""); + + write_attributes (file, (GIBaseInfo*) info); + + if (g_interface_info_get_n_prerequisites (info) > 0) + { + for (i = 0; i < g_interface_info_get_n_prerequisites (info); i++) + { + GIBaseInfo *req = g_interface_info_get_prerequisite (info, i); + + xml_start_element (file, "prerequisite"); + write_type_name_attribute (namespace, req, "name", file); + + xml_end_element_unchecked (file); + g_base_info_unref (req); + } + } + + for (i = 0; i < g_interface_info_get_n_methods (info); i++) + { + GIFunctionInfo *function = g_interface_info_get_method (info, i); + write_function_info (namespace, function, file); + g_base_info_unref ((GIBaseInfo *)function); + } + + for (i = 0; i < g_interface_info_get_n_properties (info); i++) + { + GIPropertyInfo *prop = g_interface_info_get_property (info, i); + write_property_info (namespace, prop, file); + g_base_info_unref ((GIBaseInfo *)prop); + } + + for (i = 0; i < g_interface_info_get_n_signals (info); i++) + { + GISignalInfo *signal = g_interface_info_get_signal (info, i); + write_signal_info (namespace, signal, file); + g_base_info_unref ((GIBaseInfo *)signal); + } + + for (i = 0; i < g_interface_info_get_n_vfuncs (info); i++) + { + GIVFuncInfo *vfunc = g_interface_info_get_vfunc (info, i); + write_vfunc_info (namespace, vfunc, file); + g_base_info_unref ((GIBaseInfo *)vfunc); + } + + for (i = 0; i < g_interface_info_get_n_constants (info); i++) + { + GIConstantInfo *constant = g_interface_info_get_constant (info, i); + write_constant_info (namespace, constant, file); + g_base_info_unref ((GIBaseInfo *)constant); + } + + xml_end_element (file, "interface"); +} + +static void +write_error_domain_info (const gchar *namespace, + GIErrorDomainInfo *info, + Xml *file) +{ + GIBaseInfo *enum_; + const gchar *name, *quark; + + name = g_base_info_get_name ((GIBaseInfo *)info); + quark = g_error_domain_info_get_quark (info); + enum_ = (GIBaseInfo *)g_error_domain_info_get_codes (info); + xml_start_element (file, "errordomain"); + xml_printf (file, " name=\"%s\" get-quark=\"%s\"", + name, quark); + write_type_name_attribute (namespace, enum_, "codes", file); + xml_end_element (file, "errordomain"); + g_base_info_unref (enum_); +} + +static void +write_union_info (const gchar *namespace, + GIUnionInfo *info, + Xml *file) +{ + const gchar *name; + const gchar *type_name; + const gchar *type_init; + gboolean deprecated; + gint i; + gint size; + + 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); + + xml_start_element (file, "union"); + xml_printf (file, " name=\"%s\"", name); + + if (type_name) + xml_printf (file, " type-name=\"%s\" get-type=\"%s\"", type_name, type_init); + + if (deprecated) + xml_printf (file, " deprecated=\"1\""); + + size = g_union_info_get_size (info); + if (file->show_all && size >= 0) + xml_printf (file, " size=\"%d\"", size); + + write_attributes (file, (GIBaseInfo*) info); + + 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); + + xml_start_element (file, "discriminator"); + xml_printf (file, " offset=\"%d\" type=\"", offset); + write_type_info (namespace, type, file); + xml_end_element (file, "discriminator"); + 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); + g_base_info_unref ((GIBaseInfo *)function); + } + + xml_end_element (file, "union"); +} + + +/** + * gir_writer_write: + * @filename: filename to write to + * @namespace: GIR namespace to write + * @needs_prefix: + * @show_all: + * + * Writes the output of a typelib represented by @namespace + * into a GIR xml file named @filename. + */ +void +gir_writer_write (const char *filename, + const char *namespace, + gboolean needs_prefix, + gboolean show_all) +{ + FILE *ofile; + gint i, j; + char **dependencies; + GIRepository *repository; + Xml *xml; + + repository = g_irepository_get_default (); + + if (filename == NULL) + ofile = stdout; + else + { + gchar *full_filename; + + if (needs_prefix) + full_filename = g_strdup_printf ("%s-%s", namespace, filename); + else + full_filename = g_strdup (filename); + ofile = g_fopen (filename, "w"); + + if (ofile == NULL) + { + g_fprintf (stderr, "failed to open '%s': %s\n", + full_filename, g_strerror (errno)); + g_free (full_filename); + + return; + } + + g_free (full_filename); + } + + xml = xml_open (ofile); + xml->show_all = show_all; + xml_printf (xml, "<?xml version=\"1.0\"?>\n"); + xml_start_element (xml, "repository"); + xml_printf (xml, " version=\"1.0\"\n" + " xmlns=\"http://www.gtk.org/introspection/core/1.0\"\n" + " xmlns:c=\"http://www.gtk.org/introspection/c/1.0\"\n" + " xmlns:glib=\"http://www.gtk.org/introspection/glib/1.0\""); + + dependencies = g_irepository_get_dependencies (repository, + namespace); + if (dependencies != NULL) + { + for (i = 0; dependencies[i]; i++) + { + char **parts = g_strsplit (dependencies[i], "-", 2); + xml_start_element (xml, "include"); + xml_printf (xml, " name=\"%s\" version=\"%s\"", parts[0], parts[1]); + xml_end_element (xml, "include"); + g_strfreev (parts); + } + } + + if (TRUE) + { + const gchar *shared_library; + const gchar *c_prefix; + const char *ns = namespace; + const char *version; + + version = g_irepository_get_version (repository, ns); + + shared_library = g_irepository_get_shared_library (repository, ns); + c_prefix = g_irepository_get_c_prefix (repository, ns); + xml_start_element (xml, "namespace"); + xml_printf (xml, " name=\"%s\" version=\"%s\"", ns, version); + if (shared_library) + xml_printf (xml, " shared-library=\"%s\"", shared_library); + if (c_prefix) + xml_printf (xml, " c:prefix=\"%s\"", c_prefix); + + for (j = 0; j < g_irepository_get_n_infos (repository, ns); j++) + { + GIBaseInfo *info = g_irepository_get_info (repository, ns, j); + switch (g_base_info_get_type (info)) + { + case GI_INFO_TYPE_FUNCTION: + write_function_info (ns, (GIFunctionInfo *)info, xml); + break; + + case GI_INFO_TYPE_CALLBACK: + write_callback_info (ns, (GICallbackInfo *)info, xml); + break; + + case GI_INFO_TYPE_STRUCT: + case GI_INFO_TYPE_BOXED: + write_struct_info (ns, (GIStructInfo *)info, xml); + break; + + case GI_INFO_TYPE_UNION: + write_union_info (ns, (GIUnionInfo *)info, xml); + break; + + case GI_INFO_TYPE_ENUM: + case GI_INFO_TYPE_FLAGS: + write_enum_info (ns, (GIEnumInfo *)info, xml); + break; + + case GI_INFO_TYPE_CONSTANT: + write_constant_info (ns, (GIConstantInfo *)info, xml); + break; + + case GI_INFO_TYPE_OBJECT: + write_object_info (ns, (GIObjectInfo *)info, xml); + break; + + case GI_INFO_TYPE_INTERFACE: + write_interface_info (ns, (GIInterfaceInfo *)info, xml); + break; + + case GI_INFO_TYPE_ERROR_DOMAIN: + write_error_domain_info (ns, (GIErrorDomainInfo *)info, xml); + break; + + default: + g_error ("unknown info type %d\n", g_base_info_get_type (info)); + } + + g_base_info_unref (info); + } + + xml_end_element (xml, "namespace"); + } + + xml_end_element (xml, "repository"); + + xml_free (xml); +} |