diff options
author | Colin Walters <walters@src.gnome.org> | 2008-11-13 20:13:39 +0000 |
---|---|---|
committer | Colin Walters <walters@src.gnome.org> | 2008-11-13 20:13:39 +0000 |
commit | e2d30c66e3003d8e03559526adaf765737b615f4 (patch) | |
tree | 1de0cb2d8749652ca183cb3e2152e76e82ef6f33 /girepository | |
parent | b76cca0eb5ea3363ef738b7c9b3d3e9eefea6b79 (diff) | |
download | gobject-introspection-e2d30c66e3003d8e03559526adaf765737b615f4.tar.gz |
Add new files from last commit
svn path=/trunk/; revision=913
Diffstat (limited to 'girepository')
-rw-r--r-- | girepository/gdump.c | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/girepository/gdump.c b/girepository/gdump.c new file mode 100644 index 00000000..90ca27c5 --- /dev/null +++ b/girepository/gdump.c @@ -0,0 +1,386 @@ +/* GObject introspection: Dump introspection data + * + * Copyright (C) 2008 Colin Walters <walters@verbum.org> + * + * 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 <stdlib.h> + +#include <glib.h> +#include <glib-object.h> +#include <gio/gio.h> + +#include "girepository.h" +#include "config.h" + +#include <string.h> + +static void +escaped_printf (GOutputStream *out, const char *fmt, ...) +{ + char *str; + va_list args; + gsize written; + GError *error = NULL; + + va_start (args, fmt); + + str = g_markup_vprintf_escaped (fmt, args); + if (!g_output_stream_write_all (out, str, strlen (str), &written, NULL, &error)) + { + g_critical ("failed to write to iochannel: %s", error->message); + g_clear_error (&error); + } + g_free (str); + + va_end (args); +} + +static void +goutput_write (GOutputStream *out, const char *str) +{ + gsize written; + GError *error = NULL; + if (!g_output_stream_write_all (out, str, strlen (str), &written, NULL, &error)) + { + g_critical ("failed to write to iochannel: %s", error->message); + g_clear_error (&error); + } +} + +typedef GType (*GetTypeFunc)(void); + +static GType +invoke_get_type (GModule *self, const char *symbol, GError **error) +{ + GetTypeFunc sym; + + if (!g_module_symbol (self, symbol, (void**)&sym)) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "Failed to find symbol '%s'", symbol); + return G_TYPE_INVALID; + } + + return sym (); +} + +static void +dump_properties (GType type, GOutputStream *out) +{ + guint i; + guint n_properties; + GParamSpec **props; + + if (G_TYPE_FUNDAMENTAL (type) == G_TYPE_OBJECT) + { + GObjectClass *klass; + klass = g_type_class_ref (type); + props = g_object_class_list_properties (klass, &n_properties); + } + else + { + void *klass; + klass = g_type_default_interface_ref (type); + props = g_object_interface_list_properties (klass, &n_properties); + } + + for (i = 0; i < n_properties; i++) + { + GParamSpec *prop; + + prop = props[i]; + if (prop->owner_type != type) + continue; + + escaped_printf (out, " <property name=\"%s\" type=\"%s\" flags=\"%d\"/>\n", + prop->name, g_type_name (prop->value_type), prop->flags); + } + g_free (props); +} + +static void +dump_signals (GType type, GOutputStream *out) +{ + guint i; + guint n_sigs; + guint *sig_ids; + + sig_ids = g_signal_list_ids (type, &n_sigs); + for (i = 0; i < n_sigs; i++) + { + guint sigid; + GSignalQuery query; + guint j; + + sigid = sig_ids[i]; + g_signal_query (sigid, &query); + + escaped_printf (out, " <signal name=\"%s\" return=\"%s\">\n", + query.signal_name, g_type_name (query.return_type)); + + for (j = 0; j < query.n_params; j++) + { + escaped_printf (out, " <param type=\"%s\"/>\n", + g_type_name (query.param_types[j])); + } + goutput_write (out, " </signal>\n"); + } +} + +static void +dump_object_type (GType type, const char *symbol, GOutputStream *out) +{ + guint n_interfaces; + guint i; + GType *interfaces; + + escaped_printf (out, " <class name=\"%s\" get-type=\"%s\"", + g_type_name (type), symbol); + if (type != G_TYPE_OBJECT) + escaped_printf (out, " parent=\"%s\"", g_type_name (g_type_parent (type))); + + if (G_TYPE_IS_ABSTRACT (type)) + escaped_printf (out, " abstract=\"1\""); + goutput_write (out, ">\n"); + + interfaces = g_type_interfaces (type, &n_interfaces); + for (i = 0; i < n_interfaces; i++) + { + GType itype = interfaces[i]; + escaped_printf (out, " <implements name=\"%s\"/>\n", + g_type_name (itype)); + } + dump_properties (type, out); + dump_signals (type, out); + goutput_write (out, " </class>\n"); +} + +static void +dump_interface_type (GType type, const char *symbol, GOutputStream *out) +{ + guint n_interfaces; + guint i; + GType *interfaces; + + escaped_printf (out, " <interface name=\"%s\" get-type=\"%s\">\n", + g_type_name (type), symbol); + + interfaces = g_type_interface_prerequisites (type, &n_interfaces); + for (i = 0; i < n_interfaces; i++) + { + GType itype = interfaces[i]; + escaped_printf (out, " <extends>%s</extends>\n", + g_type_name (itype)); + } + dump_properties (type, out); + dump_signals (type, out); + goutput_write (out, " </interface>\n"); +} + +static void +dump_boxed_type (GType type, const char *symbol, GOutputStream *out) +{ + escaped_printf (out, " <boxed name=\"%s\" get-type=\"%s\"/>\n", + g_type_name (type), symbol); +} + +static void +dump_flags_type (GType type, const char *symbol, GOutputStream *out) +{ + guint i; + GFlagsClass *klass; + + klass = g_type_class_ref (type); + escaped_printf (out, " <flags name=\"%s\" get-type=\"%s\">\n", + g_type_name (type), symbol); + + for (i = 0; i < klass->n_values; i++) + { + GFlagsValue *value = &(klass->values[i]); + + escaped_printf (out, " <member name=\"%s\" nick=\"%s\" value=\"%d\"/>\n", + value->value_name, value->value_nick, value->value); + } + goutput_write (out, " </flags>\n"); +} + +static void +dump_enum_type (GType type, const char *symbol, GOutputStream *out) +{ + guint i; + GEnumClass *klass; + + klass = g_type_class_ref (type); + escaped_printf (out, " <enum name=\"%s\" get-type=\"%s\">\n", + g_type_name (type), symbol); + + for (i = 0; i < klass->n_values; i++) + { + GEnumValue *value = &(klass->values[i]); + + escaped_printf (out, " <member name=\"%s\" nick=\"%s\" value=\"%d\"/>\n", + value->value_name, value->value_nick, value->value); + } + goutput_write (out, " </enum>"); +} + +static void +dump_type (GType type, const char *symbol, GOutputStream *out) +{ + g_printerr ("processing %s\n", g_type_name (type)); + switch (g_type_fundamental (type)) + { + case G_TYPE_OBJECT: + dump_object_type (type, symbol, out); + break; + case G_TYPE_INTERFACE: + dump_interface_type (type, symbol, out); + break; + case G_TYPE_BOXED: + dump_boxed_type (type, symbol, out); + break; + case G_TYPE_FLAGS: + dump_flags_type (type, symbol, out); + break; + case G_TYPE_ENUM: + dump_enum_type (type, symbol, out); + break; + case G_TYPE_POINTER: + /* GValue, etc. Just skip them. */ + break; + default: + g_warning ("unhandled gtype %s", g_type_name (type)); + } +} + +/** + * g_irepository_dump: + * @arg: Comma-separated pair of input and output filenames + * @error: a %GError + * + * Argument specified is a comma-separated pair of filenames; i.e. of + * the form "input.txt,output.xml". The input file should be a + * UTF-8 Unix-line-ending text file, with each line containing the name + * of a GType _get_type function. + * + * The output file should already exist, but be empty. This function will + * overwrite its contents. + * + * Returns: %TRUE on success, %FALSE on error + */ +gboolean +g_irepository_dump (const char *arg, GError **error) +{ + GHashTable *output_types; + char **args; + GFile *input_file; + GFile *output_file; + GFileInputStream *input; + GFileOutputStream *output; + GDataInputStream *in; + GModule *self; + gboolean caught_error = FALSE; + + self = g_module_open (NULL, 0); + if (!self) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "failed to open self: %s", + g_module_error ()); + return FALSE; + } + + args = g_strsplit (arg, ",", 2); + + input_file = g_file_new_for_path (args[0]); + output_file = g_file_new_for_path (args[1]); + + input = g_file_read (input_file, NULL, error); + if (input == NULL) + return FALSE; + + output = g_file_replace (output_file, NULL, FALSE, 0, NULL, error); + if (output == NULL) + { + g_input_stream_close (G_INPUT_STREAM (input), NULL, NULL); + return FALSE; + } + + goutput_write (G_OUTPUT_STREAM (output), "<?xml version=\"1.0\"?>\n"); + goutput_write (G_OUTPUT_STREAM (output), "<dump>\n"); + + output_types = g_hash_table_new (NULL, NULL); + + in = g_data_input_stream_new (G_INPUT_STREAM (input)); + g_object_unref (input); + + while (TRUE) + { + gsize len; + char *line = g_data_input_stream_read_line (in, &len, NULL, NULL); + GType type; + + if (line == NULL || *line == '\0') + { + g_free (line); + break; + } + + g_strchomp (line); + type = invoke_get_type (self, line, error); + + if (type == G_TYPE_INVALID) + { + caught_error = TRUE; + g_free (line); + break; + } + + if (g_hash_table_lookup (output_types, (gpointer) type)) + goto next; + g_hash_table_insert (output_types, (gpointer) type, (gpointer) type); + + dump_type (type, line, G_OUTPUT_STREAM (output)); + + next: + g_free (line); + } + + g_hash_table_destroy (output_types); + + goutput_write (G_OUTPUT_STREAM (output), "</dump>\n"); + + { + GError **ioerror; + /* Avoid overwriting an earlier set error */ + if (caught_error) + ioerror = NULL; + else + ioerror = error; + if (!g_input_stream_close (G_INPUT_STREAM (in), NULL, ioerror)) + return FALSE; + if (!g_output_stream_close (G_OUTPUT_STREAM (output), NULL, ioerror)) + return FALSE; + } + + return !caught_error; +} |