glib/girepository/tools/generate.c
Mark Doffman e56744c907 girepository/ginfo.c girepository/girepository.h tools/generate.c
2008-02-21  Mark Doffman  <mark.doffman@codethink.co.uk>

    * girepository/ginfo.c
    * girepository/girepository.h
    * tools/generate.c

      Add a function to check if an enum is registered or not.
      Previously anything testing this relied on the g-type
      string offset having a value of 0.

    * girepository/gmetadata.c
    * girepository/gmetadata.h
    * tools/generate.c

      Remove unneccesary or erroneous checks. There were two
      metadata validation checks which made sure that the blob
      sizes were the same as some magic numbers compiled into the code.
      This is wrong as it breaks any forwards compatibility that may
      be possible.

      Checks were also present that made sure that unregistered type
      blobs had a value of 0 in the g-type offset field. This is
      unneccessary. If a type blob is unregistered then any value
      in its g-type field is simply invalid.

WARNING: This commit does not compile. It is a partial change.

svn path=/trunk/; revision=132
2024-02-08 13:53:59 +00:00

1231 lines
32 KiB
C

/* -*- Mode: C; c-file-style: "gnu"; -*- */
/* GObject introspection: IDL generator
*
* Copyright (C) 2005 Matthias Clasen
*
* 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 <dlfcn.h>
#include <string.h>
#include <glib.h>
#include <glib-object.h>
#include <glib/gstdio.h>
#include "girepository.h"
#include "gmetadata.h"
gboolean raw = FALSE;
gchar **input = NULL;
gchar *output = NULL;
static void
write_type_name (const gchar *namespace,
GIBaseInfo *info,
FILE *file)
{
if (strcmp (namespace, g_base_info_get_namespace (info)) != 0)
g_fprintf (file, "%s.", g_base_info_get_namespace (info));
g_fprintf (file, "%s", g_base_info_get_name (info));
}
static void
write_type_info (const gchar *namespace,
GITypeInfo *info,
FILE *file)
{
gint tag;
gint i;
GITypeInfo *type;
const gchar* basic[] = {
"void",
"gboolean",
"gint8",
"guint8",
"gint16",
"guint16",
"gint32",
"guint32",
"gint64",
"guint64",
"gint",
"guint",
"glong",
"gulong",
"gssize",
"gsize",
"gfloat",
"gdouble",
"utf8",
"filename"
};
tag = g_type_info_get_tag (info);
if (tag < TYPE_TAG_UTF8)
g_fprintf (file, "%s%s", basic[tag], g_type_info_is_pointer (info) ? "*" : "");
else if (tag <= TYPE_TAG_FILENAME)
g_fprintf (file, "%s", basic[tag]);
else if (tag == TYPE_TAG_ARRAY)
{
gint length;
type = g_type_info_get_param_type (info, 0);
write_type_info (namespace, type, file);
g_fprintf (file, "[");
length = g_type_info_get_array_length (info);
if (length >= 0)
g_fprintf (file, "length=%d", length);
if (g_type_info_is_zero_terminated (info))
g_fprintf (file, "%szero-terminated=1", length >= 0 ? "," : "");
g_fprintf (file, "]");
g_base_info_unref ((GIBaseInfo *)type);
}
else if (tag == TYPE_TAG_SYMBOL)
{
GIBaseInfo *iface = g_type_info_get_interface (info);
write_type_name (namespace, iface, file);
if (g_type_info_is_pointer (info))
g_fprintf (file, "*");
g_base_info_unref (iface);
}
else if (tag == TYPE_TAG_LIST)
{
type = g_type_info_get_param_type (info, 0);
g_fprintf (file, "GList");
if (type)
{
g_fprintf (file, "<");
write_type_info (namespace, type, file);
g_fprintf (file, ">");
g_base_info_unref ((GIBaseInfo *)type);
}
g_fprintf (file, "*");
}
else if (tag == TYPE_TAG_SLIST)
{
type = g_type_info_get_param_type (info, 0);
g_fprintf (file, "GSList");
if (type)
{
g_fprintf (file, "<");
write_type_info (namespace, type, file);
g_fprintf (file, ">");
g_base_info_unref ((GIBaseInfo *)type);
}
g_fprintf (file, "*");
}
else if (tag == TYPE_TAG_HASH)
{
type = g_type_info_get_param_type (info, 0);
g_fprintf (file, "GHashTable");
if (type)
{
g_fprintf (file, "<");
write_type_info (namespace, type, file);
g_base_info_unref ((GIBaseInfo *)type);
type = g_type_info_get_param_type (info, 1);
g_fprintf (file, ",");
write_type_info (namespace, type, file);
g_fprintf (file, ">");
g_base_info_unref ((GIBaseInfo *)type);
}
g_fprintf (file, "*");
}
else if (tag == TYPE_TAG_ERROR)
{
gint n;
g_fprintf (file, "GError");
n = g_type_info_get_n_error_domains (info);
if (n > 0)
{
g_fprintf (file, "<");
for (i = 0; i < n; i++)
{
GIErrorDomainInfo *ed = g_type_info_get_error_domain (info, i);
if (i > 0)
g_fprintf (file, ",");
write_type_name (namespace, (GIBaseInfo *)ed, file);
g_base_info_unref ((GIBaseInfo *)ed);
}
g_fprintf (file, ">");
}
g_fprintf (file, "*");
}
}
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;
GIFieldInfoFlags flags;
gint size;
gint offset;
GITypeInfo *type;
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);
g_fprintf (file,
" <field name=\"%s\" readable=\"%s\" writable=\"%s\" ",
name,
flags & GI_FIELD_IS_READABLE ? "1" : "0",
flags & GI_FIELD_IS_WRITABLE ? "1" : "0");
if (size)
g_fprintf (file, "bits=\"%d\" ", size);
g_fprintf (file, "offset=\"%d\" ", offset);
g_fprintf (file, "type=\"");
type = g_field_info_get_type (info);
write_type_info (namespace, type, file);
g_base_info_unref ((GIBaseInfo *)type);
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
write_callable_info (const gchar *namespace,
GICallableInfo *info,
FILE *file,
gint indent)
{
GITypeInfo *type;
gint i;
g_fprintf (file, "%*s <return-type type=\"", indent, "");
type = g_callable_info_get_return_type (info);
write_type_info (namespace, type, file);
g_fprintf (file, "\"");
if (g_type_info_is_pointer (type))
{
switch (g_callable_info_get_caller_owns (info))
{
case GI_TRANSFER_NOTHING:
g_fprintf (file, " transfer=\"none\"");
break;
case GI_TRANSFER_CONTAINER:
g_fprintf (file, " transfer=\"shallow\"");
break;
case GI_TRANSFER_EVERYTHING:
g_fprintf (file, " transfer=\"full\"");
break;
default:
g_assert_not_reached ();
}
}
g_base_info_unref ((GIBaseInfo *)type);
if (g_callable_info_may_return_null (info))
g_fprintf (file, " null-ok=\"1\"");
g_fprintf (file, " />\n");
if (g_callable_info_get_n_args (info) > 0)
{
g_fprintf (file, "%*s <parameters>\n", indent, "");
for (i = 0; i < g_callable_info_get_n_args (info); i++)
{
GIArgInfo *arg = g_callable_info_get_arg (info, i);
g_fprintf (file, "%*s <parameter name=\"%s\" type=\"",
indent, "", g_base_info_get_name ((GIBaseInfo *) arg));
type = g_arg_info_get_type (arg);
write_type_info (namespace, type, file);
g_fprintf (file, "\"");
if (g_type_info_is_pointer (type))
{
switch (g_arg_info_get_ownership_transfer (arg))
{
case GI_TRANSFER_NOTHING:
g_fprintf (file, " transfer=\"none\"");
break;
case GI_TRANSFER_CONTAINER:
g_fprintf (file, " transfer=\"shallow\"");
break;
case GI_TRANSFER_EVERYTHING:
g_fprintf (file, " transfer=\"full\"");
break;
default:
g_assert_not_reached ();
}
}
g_base_info_unref ((GIBaseInfo *)type);
g_fprintf (file, " direction=\"");
switch (g_arg_info_get_direction (arg))
{
case GI_DIRECTION_IN:
g_fprintf (file, "in");
break;
case GI_DIRECTION_OUT:
g_fprintf (file, "out");
break;
case GI_DIRECTION_INOUT:
g_fprintf (file, "inout");
break;
}
g_fprintf (file, "\"");
if (g_arg_info_may_be_null (arg))
g_fprintf (file, " null-ok=\"1\"");
if (g_arg_info_is_dipper (arg))
g_fprintf (file, " dipper=\"1\"");
if (g_arg_info_is_return_value (arg))
g_fprintf (file, " retval=\"1\"");
if (g_arg_info_is_optional (arg))
g_fprintf (file, " optional=\"1\"");
g_fprintf (file, " />\n");
g_base_info_unref ((GIBaseInfo *)arg);
}
g_fprintf (file, "%*s </parameters>\n", indent, "");
}
}
static void
write_function_info (const gchar *namespace,
GIFunctionInfo *info,
FILE *file,
gint indent)
{
GIFunctionInfoFlags flags;
const gchar *tag;
const gchar *name;
const gchar *symbol;
gboolean deprecated;
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);
if (flags & GI_FUNCTION_IS_CONSTRUCTOR)
tag = "constructor";
else if (flags & GI_FUNCTION_IS_METHOD)
tag = "method";
else
tag = "function";
g_fprintf (file, "%*s<%s name=\"%s\" symbol=\"%s\"",
indent, "", tag, name, symbol);
if (flags & GI_FUNCTION_IS_SETTER)
g_fprintf (file, " type=\"setter\"");
else if (flags & GI_FUNCTION_IS_GETTER)
g_fprintf (file, " type=\"getter\"");
if (deprecated)
g_fprintf (file, " deprecated=\"1\"");
g_fprintf (file, ">\n");
write_callable_info (namespace, (GICallableInfo*)info, file, indent);
g_fprintf (file, "%*s</%s>\n", indent, "", tag);
}
static void
write_callback_info (const gchar *namespace,
GICallbackInfo *info,
FILE *file,
gint indent)
{
const gchar *name;
gboolean deprecated;
name = g_base_info_get_name ((GIBaseInfo *)info);
deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
g_fprintf (file, "%*s<callback name=\"%s\"", indent, "", name);
if (deprecated)
g_fprintf (file, " deprecated=\"1\"");
g_fprintf (file, ">\n");
write_callable_info (namespace, (GICallableInfo*)info, file, indent);
g_fprintf (file, "%*s</callback>\n", indent, "");
}
static void
write_struct_info (const gchar *namespace,
GIStructInfo *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);
if (g_base_info_get_type ((GIBaseInfo *)info) == GI_INFO_TYPE_BOXED)
{
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, " <boxed name=\"%s\" type-name=\"%s\" get-type=\"%s\"", name, type_name, type_init);
}
else
g_fprintf (file, " <struct name=\"%s\"", name);
if (deprecated)
g_fprintf (file, " deprecated=\"1\"");
g_fprintf (file, ">\n");
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, 6);
g_base_info_unref ((GIBaseInfo *)function);
}
if (g_base_info_get_type ((GIBaseInfo *)info) == GI_INFO_TYPE_BOXED)
g_fprintf (file, " </boxed>\n");
else
g_fprintf (file, " </struct>\n");
}
static void
write_value_info (const gchar *namespace,
GIValueInfo *info,
FILE *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);
g_fprintf (file, " <member name=\"%s\" value=\"%ld\"", name, value);
if (deprecated)
g_fprintf (file, " deprecated=\"1\"");
g_fprintf (file, " />\n");
}
static void
write_constant_value (const gchar *namespace,
GITypeInfo *type,
GArgument *value,
FILE *file)
{
switch (g_type_info_get_tag (type))
{
case GI_TYPE_TAG_BOOLEAN:
g_fprintf (file, "%d", value->v_boolean);
break;
case GI_TYPE_TAG_INT8:
g_fprintf (file, "%d", value->v_int8);
break;
case GI_TYPE_TAG_UINT8:
g_fprintf (file, "%d", value->v_uint8);
break;
case GI_TYPE_TAG_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);
break;
case GI_TYPE_TAG_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);
break;
case GI_TYPE_TAG_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);
break;
case GI_TYPE_TAG_INT:
g_fprintf (file, "%d", value->v_int);
break;
case GI_TYPE_TAG_UINT:
g_fprintf (file, "%d", value->v_uint);
break;
case GI_TYPE_TAG_LONG:
g_fprintf (file, "%ld", value->v_long);
break;
case GI_TYPE_TAG_ULONG:
g_fprintf (file, "%ld", value->v_ulong);
break;
case GI_TYPE_TAG_SSIZE:
g_fprintf (file, "%zd", value->v_ssize);
break;
case GI_TYPE_TAG_SIZE:
g_fprintf (file, "%zd", value->v_size);
break;
case GI_TYPE_TAG_FLOAT:
g_fprintf (file, "%f", value->v_float);
break;
case GI_TYPE_TAG_DOUBLE:
g_fprintf (file, "%f", value->v_double);
break;
case GI_TYPE_TAG_UTF8:
case GI_TYPE_TAG_FILENAME:
g_fprintf (file, "%s", value->v_string);
break;
case GI_TYPE_TAG_SYMBOL:
g_fprintf (file, "%s", value->v_string);
break;
default:
g_warning ("Could not get type tag for constant");
}
}
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);
}
static void
write_enum_info (const gchar *namespace,
GIEnumInfo *info,
FILE *file)
{
const gchar *name;
const gchar *type_name = NULL;
const gchar *type_init = NULL;
gboolean deprecated;
gint i;
name = g_base_info_get_name ((GIBaseInfo *)info);
deprecated = g_base_info_is_deprecated ((GIBaseInfo *)info);
/* Make sure this is a registered enum before filling out the
* GType information
*/
if (g_enum_info_is_registered ((GIEnumInfo *)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)
g_fprintf (file, " <enum ");
else
g_fprintf (file, " <flags ");
g_fprintf (file, "name=\"%s\"", name);
if (type_init)
g_fprintf (file, " type-name=\"%s\" get-type=\"%s\"", type_name, type_init);
if (deprecated)
g_fprintf (file, " deprecated=\"1\"");
g_fprintf (file, ">\n");
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);
}
if (g_base_info_get_type ((GIBaseInfo *)info) == GI_INFO_TYPE_ENUM)
g_fprintf (file, " </enum>\n");
else
g_fprintf (file, " </flags>\n");
}
static void
write_signal_info (const gchar *namespace,
GISignalInfo *info,
FILE *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);
g_fprintf (file, " <signal name=\"%s\"", name);
if (deprecated)
g_fprintf (file, " deprecated=\"1\"");
if (flags & G_SIGNAL_RUN_FIRST)
g_fprintf (file, " when=\"FIRST\"");
else if (flags & G_SIGNAL_RUN_LAST)
g_fprintf (file, " when=\"LAST\"");
else if (flags & G_SIGNAL_RUN_CLEANUP)
g_fprintf (file, " when=\"CLEANUP\"");
if (flags & G_SIGNAL_NO_RECURSE)
g_fprintf (file, " no-recurse=\"1\"");
if (flags & G_SIGNAL_DETAILED)
g_fprintf (file, " detailed=\"1\"");
if (flags & G_SIGNAL_ACTION)
g_fprintf (file, " action=\"1\"");
if (flags & G_SIGNAL_NO_HOOKS)
g_fprintf (file, " no-hooks=\"1\"");
g_fprintf (file, ">\n");
write_callable_info (namespace, (GICallableInfo*)info, file, 6);
g_fprintf (file, " </signal>\n");
}
static void
write_vfunc_info (const gchar *namespace,
GIVFuncInfo *info,
FILE *file)
{
GIVFuncInfoFlags flags;
const gchar *name;
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);
g_fprintf (file, " <vfunc name=\"%s\"", name);
if (deprecated)
g_fprintf (file, " deprecated=\"1\"");
if (flags & GI_VFUNC_MUST_CHAIN_UP)
g_fprintf (file, " must-chain-up=\"1\"");
if (flags & GI_VFUNC_MUST_OVERRIDE)
g_fprintf (file, " override=\"always\"");
else if (flags & GI_VFUNC_MUST_NOT_OVERRIDE)
g_fprintf (file, " override=\"never\"");
g_fprintf (file, " offset=\"%d\"", offset);
g_fprintf (file, ">\n");
write_callable_info (namespace, (GICallableInfo*)info, file, 6);
g_fprintf (file, " </vfunc>\n");
}
static void
write_property_info (const gchar *namespace,
GIPropertyInfo *info,
FILE *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);
g_fprintf (file, " <property name=\"%s\"", name);
if (deprecated)
g_fprintf (file, " deprecated=\"1\"");
if (flags & G_PARAM_READABLE)
g_fprintf (file, " readable=\"1\"");
else
g_fprintf (file, " readable=\"0\"");
if (flags & G_PARAM_WRITABLE)
g_fprintf (file, " writable=\"1\"");
else
g_fprintf (file, " writable=\"0\"");
if (flags & G_PARAM_CONSTRUCT)
g_fprintf (file, " construct=\"1\"");
if (flags & G_PARAM_CONSTRUCT_ONLY)
g_fprintf (file, " construct-only=\"1\"");
type = g_property_info_get_type (info);
g_fprintf (file, " type=\"");
write_type_info (namespace, type, file);
g_fprintf (file, "\"");
g_fprintf (file, " />\n");
}
static void
write_object_info (const gchar *namespace,
GIObjectInfo *info,
FILE *file)
{
const gchar *name;
const gchar *type_name;
const gchar *type_init;
gboolean deprecated;
GIObjectInfo *pnode;
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, " <object name=\"%s\"", name);
pnode = g_object_info_get_parent (info);
if (pnode)
{
g_fprintf (file, " parent=\"");
write_type_name (namespace, (GIBaseInfo *)pnode, file);
g_fprintf (file, "\"" );
g_base_info_unref ((GIBaseInfo *)pnode);
}
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_object_info_get_n_interfaces (info) > 0)
{
g_fprintf (file, " <implements>\n");
for (i = 0; i < g_object_info_get_n_interfaces (info); i++)
{
GIInterfaceInfo *imp = g_object_info_get_interface (info, i);
g_fprintf (file, " <interface name=\"");
write_type_name (namespace, (GIBaseInfo*)imp, file);
g_fprintf (file,"\" />\n");
g_base_info_unref ((GIBaseInfo*)imp);
}
g_fprintf (file, " </implements>\n");
}
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, 6);
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, 6);
g_base_info_unref ((GIBaseInfo *)constant);
}
g_fprintf (file, " </object>\n");
}
static void
write_interface_info (const gchar *namespace,
GIInterfaceInfo *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, " <interface name=\"%s\" type-name=\"%s\" get-type=\"%s\"",
name, type_name, type_init);
if (deprecated)
g_fprintf (file, " deprecated=\"1\"");
g_fprintf (file, ">\n");
if (g_interface_info_get_n_prerequisites (info) > 0)
{
g_fprintf (file, " <requires>\n");
for (i = 0; i < g_interface_info_get_n_prerequisites (info); i++)
{
GIBaseInfo *req = g_interface_info_get_prerequisite (info, i);
if (g_base_info_get_type (req) == GI_INFO_TYPE_INTERFACE)
g_fprintf (file, " <interface name=\"");
else
g_fprintf (file, " <object name=\"");
write_type_name (namespace, req, file);
g_fprintf (file, "\" />\n");
g_base_info_unref (req);
}
g_fprintf (file, " </requires>\n");
}
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, 6);
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, 6);
g_base_info_unref ((GIBaseInfo *)constant);
}
g_fprintf (file, " </interface>\n");
}
static void
write_error_domain_info (const gchar *namespace,
GIErrorDomainInfo *info,
FILE *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);
g_fprintf (file,
" <errordomain name=\"%s\" get-quark=\"%s\" codes=\"",
name, quark);
write_type_name (namespace, enum_, file);
g_fprintf (file, "\" />\n");
g_base_info_unref (enum_);
}
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)
{
FILE *file;
gchar **namespaces;
gchar *ns;
gint i, j;
namespaces = g_irepository_get_namespaces (repository);
if (output == NULL)
file = stdout;
else
{
gchar *filename;
if (needs_prefix)
filename = g_strdup_printf ("%s-%s", namespaces[0], output);
else
filename = g_strdup (output);
file = g_fopen (filename, "w");
if (file == NULL)
{
g_fprintf (stderr, "failed to open '%s': %s\n",
filename, g_strerror (errno));
g_free (filename);
return;
}
g_free (filename);
}
g_fprintf (file, "<?xml version=\"1.0\"?>\n");
g_fprintf (file, "<api version=\"1.0\">\n");
for (i = 0; namespaces[i]; i++)
{
const gchar *shared_library;
ns = namespaces[i];
shared_library = g_irepository_get_shared_library (repository, ns);
if (shared_library)
g_fprintf (file, " <namespace name=\"%s\" shared-library=\"%s\">\n",
ns, shared_library);
else
g_fprintf (file, " <namespace name=\"%s\">\n", ns);
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, file, 4);
break;
case GI_INFO_TYPE_CALLBACK:
write_callback_info (ns, (GICallbackInfo *)info, file, 4);
break;
case GI_INFO_TYPE_STRUCT:
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);
break;
case GI_INFO_TYPE_CONSTANT:
write_constant_info (ns, (GIConstantInfo *)info, file, 4);
break;
case GI_INFO_TYPE_OBJECT:
write_object_info (ns, (GIObjectInfo *)info, file);
break;
case GI_INFO_TYPE_INTERFACE:
write_interface_info (ns, (GIInterfaceInfo *)info, file);
break;
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);
}
g_fprintf (file, " </namespace>\n");
}
g_fprintf (file, "</api>\n");
if (output != NULL)
fclose (file);
g_strfreev (namespaces);
}
static GOptionEntry options[] =
{
{ "raw", 0, 0, G_OPTION_ARG_NONE, &raw, "handle raw metadata", NULL },
{ "output", 'o', 0, G_OPTION_ARG_FILENAME, &output, "output file", "FILE" },
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &input, NULL, NULL },
{ NULL, }
};
static const guchar *
load_metadata (const gchar *filename,
GModule **dlhandle,
gsize *len)
{
guchar *metadata;
gsize *metadata_size;
GModule *handle;
handle = g_module_open (filename, G_MODULE_BIND_LOCAL|G_MODULE_BIND_LAZY);
if (!g_module_symbol (handle, "_G_METADATA", (gpointer *) &metadata))
{
g_printerr ("Could not load metadata from '%s': %s\n",
filename, g_module_error ());
return NULL;
}
if (!g_module_symbol (handle, "_G_METADATA_SIZE", (gpointer *) &metadata_size))
{
g_printerr ("Could not load metadata from '%s': %s\n",
filename, g_module_error ());
return NULL;
}
*len = *metadata_size;
if (dlhandle)
*dlhandle = handle;
return metadata;
}
int
main (int argc, char *argv[])
{
GOptionContext *context;
GError *error = NULL;
gboolean needs_prefix;
gint i;
GMetadata *data;
g_type_init ();
context = g_option_context_new ("");
g_option_context_add_main_entries (context, options, NULL);
g_option_context_parse (context, &argc, &argv, &error);
if (!input)
{
g_fprintf (stderr, "no input files\n");
return 1;
}
for (i = 0; input[i]; i++)
{
GModule *dlhandle = NULL;
const guchar *metadata;
gsize len;
if (raw)
{
if (!g_file_get_contents (input[i], (gchar **)&metadata, &len, &error))
{
g_fprintf (stderr, "failed to read '%s': %s\n",
input[i], error->message);
g_clear_error (&error);
continue;
}
}
else
{
metadata = load_metadata (input[i], &dlhandle, &len);
if (!metadata)
{
g_fprintf (stderr, "failed to load metadata from '%s'\n",
input[i]);
continue;
}
}
if (input[i + 1] && output)
needs_prefix = TRUE;
else
needs_prefix = FALSE;
data = g_metadata_new_from_const_memory (metadata, len);
{
GError *error = NULL;
if (!g_metadata_validate (data, &error)) {
g_printerr ("metadata not valid: %s\n", error->message);
g_clear_error (&error);
}
}
g_irepository_register (g_irepository_get_default (), data);
write_repository (g_irepository_get_default (), needs_prefix);
g_irepository_unregister (g_irepository_get_default (),
g_metadata_get_namespace (data));
if (dlhandle)
{
g_module_close (dlhandle);
dlhandle = NULL;
}
/* when writing to stdout, stop after the first module */
if (input[i + 1] && !output)
{
g_fprintf (stderr, "warning, %d modules omitted\n",
g_strv_length (input) - 1);
break;
}
}
return 0;
}