glib/girepository/gibaseinfo.c
Philip Withnall 64ad0ecebc girepository: Rename gi_base_info_get_type() to get_info_type()
This method doesn’t return a `GType`, so when the code gets ported to
`GTypeInstance` in an upcoming commit, that will become quite confusing.

Rename it to `gi_base_info_get_info_type()` instead.

This introduces no functional changes, but it is an API break.

Signed-off-by: Philip Withnall <pwithnall@gnome.org>

Helps: #3155
2023-12-12 16:58:04 +00:00

678 lines
17 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
* GObject introspection: Base struct implementation
*
* Copyright (C) 2005 Matthias Clasen
* Copyright (C) 2008,2009 Red Hat, Inc.
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*
* 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 "config.h"
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <glib-object.h>
#include "gitypelib-internal.h"
#include "girepository-private.h"
#include "gibaseinfo.h"
#define INVALID_REFCOUNT 0x7FFFFFFF
/* GBoxed registration of BaseInfo. */
GType
gi_base_info_gtype_get_type (void)
{
static GType our_type = 0;
if (our_type == 0)
our_type =
g_boxed_type_register_static ("GIBaseInfo",
(GBoxedCopyFunc) gi_base_info_ref,
(GBoxedFreeFunc) gi_base_info_unref);
return our_type;
}
/* info creation */
GIBaseInfo *
gi_info_new_full (GIInfoType type,
GIRepository *repository,
GIBaseInfo *container,
GITypelib *typelib,
guint32 offset)
{
GIRealInfo *info;
g_return_val_if_fail (container != NULL || repository != NULL, NULL);
info = g_slice_new (GIRealInfo);
gi_info_init (info, type, repository, container, typelib, offset);
info->ref_count = 1;
if (container && ((GIRealInfo *) container)->ref_count != INVALID_REFCOUNT)
gi_base_info_ref (info->container);
g_object_ref (info->repository);
return (GIBaseInfo*)info;
}
/**
* gi_info_new:
* @type: TODO
* @container: TODO
* @typelib: TODO
* @offset: TODO
*
* TODO
*
* Returns: (transfer full): TODO
*/
GIBaseInfo *
gi_info_new (GIInfoType type,
GIBaseInfo *container,
GITypelib *typelib,
guint32 offset)
{
return gi_info_new_full (type, ((GIRealInfo*)container)->repository, container, typelib, offset);
}
void
gi_info_init (GIRealInfo *info,
GIInfoType type,
GIRepository *repository,
GIBaseInfo *container,
GITypelib *typelib,
guint32 offset)
{
memset (info, 0, sizeof (GIRealInfo));
/* Invalid refcount used to flag stack-allocated infos */
info->ref_count = INVALID_REFCOUNT;
info->type = type;
info->typelib = typelib;
info->offset = offset;
if (container)
info->container = container;
g_assert (GI_IS_REPOSITORY (repository));
info->repository = repository;
}
GIBaseInfo *
gi_info_from_entry (GIRepository *repository,
GITypelib *typelib,
guint16 index)
{
GIBaseInfo *result;
DirEntry *entry = gi_typelib_get_dir_entry (typelib, index);
if (entry->local)
result = gi_info_new_full (entry->blob_type, repository, NULL, typelib, entry->offset);
else
{
const gchar *namespace = gi_typelib_get_string (typelib, entry->offset);
const gchar *name = gi_typelib_get_string (typelib, entry->name);
result = gi_repository_find_by_name (repository, namespace, name);
if (result == NULL)
{
GIUnresolvedInfo *unresolved;
unresolved = g_slice_new0 (GIUnresolvedInfo);
unresolved->type = GI_INFO_TYPE_UNRESOLVED;
unresolved->ref_count = 1;
unresolved->repository = g_object_ref (repository);
unresolved->container = NULL;
unresolved->name = name;
unresolved->namespace = namespace;
return (GIBaseInfo *)unresolved;
}
return (GIBaseInfo *)result;
}
return (GIBaseInfo *)result;
}
GITypeInfo *
gi_type_info_new (GIBaseInfo *container,
GITypelib *typelib,
guint32 offset)
{
SimpleTypeBlob *type = (SimpleTypeBlob *)&typelib->data[offset];
return (GITypeInfo *) gi_info_new (GI_INFO_TYPE_TYPE, container, typelib,
(type->flags.reserved == 0 && type->flags.reserved2 == 0) ? offset : type->offset);
}
void
gi_type_info_init (GIBaseInfo *info,
GIBaseInfo *container,
GITypelib *typelib,
guint32 offset)
{
GIRealInfo *rinfo = (GIRealInfo*)container;
SimpleTypeBlob *type = (SimpleTypeBlob *)&typelib->data[offset];
gi_info_init ((GIRealInfo*)info, GI_INFO_TYPE_TYPE, rinfo->repository, container, typelib,
(type->flags.reserved == 0 && type->flags.reserved2 == 0) ? offset : type->offset);
}
/* GIBaseInfo functions */
/**
* SECTION:gibaseinfo
* @title: GIBaseInfo
* @short_description: Base struct for all GITypelib structs
*
* GIBaseInfo is the common base struct of all other Info structs
* accessible through the #GIRepository API.
*
* All info structures can be cast to a #GIBaseInfo, for instance:
*
* |[<!-- language="C" -->
* GIFunctionInfo *function_info = ...;
* GIBaseInfo *info = (GIBaseInfo *) function_info;
* ]|
*
* Most #GIRepository APIs returning a #GIBaseInfo is actually
* creating a new struct; in other words, gi_base_info_unref() has to
* be called when done accessing the data.
*
* #GIBaseInfo structuress are normally accessed by calling either
* gi_repository_find_by_name(), gi_repository_find_by_gtype() or
* gi_repository_get_info().
*
* |[<!-- language="C" -->
* GIBaseInfo *button_info =
* gi_repository_find_by_name (NULL, "Gtk", "Button");
*
* // ... use button_info ...
*
* gi_base_info_unref (button_info);
* ]|
*
* ## Hierarchy
*
* |[<!-- language="plain" -->
* GIBaseInfo
* +---- GIArgInfo
* +---- GICallableInfo
* +---- GIConstantInfo
* +---- GIFieldInfo
* +---- GIPropertyInfo
* +---- GIRegisteredTypeInfo
* +---- GITypeInfo
* ]|
*/
/**
* gi_base_info_ref: (skip)
* @info: a #GIBaseInfo
*
* Increases the reference count of @info.
*
* Returns: the same @info.
*/
GIBaseInfo *
gi_base_info_ref (GIBaseInfo *info)
{
GIRealInfo *rinfo = (GIRealInfo*)info;
g_assert (rinfo->ref_count != INVALID_REFCOUNT);
g_atomic_int_inc (&rinfo->ref_count);
return info;
}
/**
* gi_base_info_unref: (skip)
* @info: a #GIBaseInfo
*
* Decreases the reference count of @info. When its reference count
* drops to 0, the info is freed.
*/
void
gi_base_info_unref (GIBaseInfo *info)
{
GIRealInfo *rinfo = (GIRealInfo*)info;
g_assert (rinfo->ref_count > 0 && rinfo->ref_count != INVALID_REFCOUNT);
if (!g_atomic_int_dec_and_test (&rinfo->ref_count))
return;
if (rinfo->container && ((GIRealInfo *) rinfo->container)->ref_count != INVALID_REFCOUNT)
gi_base_info_unref (rinfo->container);
if (rinfo->repository)
g_object_unref (rinfo->repository);
if (rinfo->type == GI_INFO_TYPE_UNRESOLVED)
g_slice_free (GIUnresolvedInfo, (GIUnresolvedInfo *) rinfo);
else
g_slice_free (GIRealInfo, rinfo);
}
/**
* gi_base_info_get_info_type:
* @info: a #GIBaseInfo
*
* Obtain the info type of the GIBaseInfo.
*
* Returns: the info type of @info
*/
GIInfoType
gi_base_info_get_info_type (GIBaseInfo *info)
{
return ((GIRealInfo*)info)->type;
}
/**
* gi_base_info_get_name:
* @info: a #GIBaseInfo
*
* Obtain the name of the @info. What the name represents depends on
* the #GIInfoType of the @info. For instance for #GIFunctionInfo it is
* the name of the function.
*
* Returns: the name of @info or %NULL if it lacks a name.
*/
const gchar *
gi_base_info_get_name (GIBaseInfo *info)
{
GIRealInfo *rinfo = (GIRealInfo*)info;
g_assert (rinfo->ref_count > 0);
switch (gi_base_info_get_info_type ((GIBaseInfo *) info))
{
case GI_INFO_TYPE_FUNCTION:
case GI_INFO_TYPE_CALLBACK:
case GI_INFO_TYPE_STRUCT:
case GI_INFO_TYPE_BOXED:
case GI_INFO_TYPE_ENUM:
case GI_INFO_TYPE_FLAGS:
case GI_INFO_TYPE_OBJECT:
case GI_INFO_TYPE_INTERFACE:
case GI_INFO_TYPE_CONSTANT:
case GI_INFO_TYPE_INVALID_0:
case GI_INFO_TYPE_UNION:
{
CommonBlob *blob = (CommonBlob *)&rinfo->typelib->data[rinfo->offset];
return gi_typelib_get_string (rinfo->typelib, blob->name);
}
break;
case GI_INFO_TYPE_VALUE:
{
ValueBlob *blob = (ValueBlob *)&rinfo->typelib->data[rinfo->offset];
return gi_typelib_get_string (rinfo->typelib, blob->name);
}
break;
case GI_INFO_TYPE_SIGNAL:
{
SignalBlob *blob = (SignalBlob *)&rinfo->typelib->data[rinfo->offset];
return gi_typelib_get_string (rinfo->typelib, blob->name);
}
break;
case GI_INFO_TYPE_PROPERTY:
{
PropertyBlob *blob = (PropertyBlob *)&rinfo->typelib->data[rinfo->offset];
return gi_typelib_get_string (rinfo->typelib, blob->name);
}
break;
case GI_INFO_TYPE_VFUNC:
{
VFuncBlob *blob = (VFuncBlob *)&rinfo->typelib->data[rinfo->offset];
return gi_typelib_get_string (rinfo->typelib, blob->name);
}
break;
case GI_INFO_TYPE_FIELD:
{
FieldBlob *blob = (FieldBlob *)&rinfo->typelib->data[rinfo->offset];
return gi_typelib_get_string (rinfo->typelib, blob->name);
}
break;
case GI_INFO_TYPE_ARG:
{
ArgBlob *blob = (ArgBlob *)&rinfo->typelib->data[rinfo->offset];
return gi_typelib_get_string (rinfo->typelib, blob->name);
}
break;
case GI_INFO_TYPE_UNRESOLVED:
{
GIUnresolvedInfo *unresolved = (GIUnresolvedInfo *)info;
return unresolved->name;
}
break;
case GI_INFO_TYPE_TYPE:
return NULL;
default: ;
g_assert_not_reached ();
/* unnamed */
}
return NULL;
}
/**
* gi_base_info_get_namespace:
* @info: a #GIBaseInfo
*
* Obtain the namespace of @info.
*
* Returns: the namespace
*/
const gchar *
gi_base_info_get_namespace (GIBaseInfo *info)
{
GIRealInfo *rinfo = (GIRealInfo*) info;
Header *header = (Header *)rinfo->typelib->data;
g_assert (rinfo->ref_count > 0);
if (gi_base_info_get_info_type (info) == GI_INFO_TYPE_UNRESOLVED)
{
GIUnresolvedInfo *unresolved = (GIUnresolvedInfo *)info;
return unresolved->namespace;
}
return gi_typelib_get_string (rinfo->typelib, header->namespace);
}
/**
* gi_base_info_is_deprecated:
* @info: a #GIBaseInfo
*
* Obtain whether the @info is represents a metadata which is
* deprecated or not.
*
* Returns: %TRUE if deprecated
*/
gboolean
gi_base_info_is_deprecated (GIBaseInfo *info)
{
GIRealInfo *rinfo = (GIRealInfo*) info;
switch (gi_base_info_get_info_type ((GIBaseInfo *) info))
{
case GI_INFO_TYPE_FUNCTION:
case GI_INFO_TYPE_CALLBACK:
case GI_INFO_TYPE_STRUCT:
case GI_INFO_TYPE_BOXED:
case GI_INFO_TYPE_ENUM:
case GI_INFO_TYPE_FLAGS:
case GI_INFO_TYPE_OBJECT:
case GI_INFO_TYPE_INTERFACE:
case GI_INFO_TYPE_CONSTANT:
case GI_INFO_TYPE_INVALID_0:
{
CommonBlob *blob = (CommonBlob *)&rinfo->typelib->data[rinfo->offset];
return blob->deprecated;
}
break;
case GI_INFO_TYPE_VALUE:
{
ValueBlob *blob = (ValueBlob *)&rinfo->typelib->data[rinfo->offset];
return blob->deprecated;
}
break;
case GI_INFO_TYPE_SIGNAL:
{
SignalBlob *blob = (SignalBlob *)&rinfo->typelib->data[rinfo->offset];
return blob->deprecated;
}
break;
case GI_INFO_TYPE_PROPERTY:
{
PropertyBlob *blob = (PropertyBlob *)&rinfo->typelib->data[rinfo->offset];
return blob->deprecated;
}
break;
case GI_INFO_TYPE_VFUNC:
case GI_INFO_TYPE_FIELD:
case GI_INFO_TYPE_ARG:
case GI_INFO_TYPE_TYPE:
default: ;
/* no deprecation flag for these */
}
return FALSE;
}
/**
* gi_base_info_get_attribute:
* @info: a #GIBaseInfo
* @name: a freeform string naming an attribute
*
* Retrieve an arbitrary attribute associated with this node.
*
* Returns: The value of the attribute, or %NULL if no such attribute exists
*/
const gchar *
gi_base_info_get_attribute (GIBaseInfo *info,
const gchar *name)
{
GIAttributeIter iter = { 0, };
gchar *curname, *curvalue;
while (gi_base_info_iterate_attributes (info, &iter, &curname, &curvalue))
{
if (strcmp (name, curname) == 0)
return (const gchar*) curvalue;
}
return NULL;
}
static int
cmp_attribute (const void *av,
const void *bv)
{
const AttributeBlob *a = av;
const AttributeBlob *b = bv;
if (a->offset < b->offset)
return -1;
else if (a->offset == b->offset)
return 0;
else
return 1;
}
/*
* _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 = blob_offset;
first = (AttributeBlob *) &rinfo->typelib->data[header->attributes];
res = bsearch (&blob, first, header->n_attributes,
header->attribute_blob_size, cmp_attribute);
if (res == NULL)
return NULL;
previous = res - 1;
while (previous >= first && previous->offset == blob_offset)
{
res = previous;
previous = res - 1;
}
return res;
}
/**
* gi_base_info_iterate_attributes:
* @info: a #GIBaseInfo
* @iterator: (inout): 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 this node. The iterator
* structure is typically stack allocated, and must have its first
* member initialized to %NULL. Attributes are arbitrary namespaced keyvalue
* pairs which can be attached to almost any item. They are intended for use
* by software higher in the toolchain than bindings, and are distinct from
* normal GIR annotations.
*
* Both the @name and @value should be treated as constants
* and must not be freed.
*
* |[<!-- language="C" -->
* void
* print_attributes (GIBaseInfo *info)
* {
* GIAttributeIter iter = { 0, };
* char *name;
* char *value;
* while (gi_base_info_iterate_attributes (info, &iter, &name, &value))
* {
* g_print ("attribute name: %s value: %s", name, value);
* }
* }
* ]|
*
* Returns: %TRUE if there are more attributes
*/
gboolean
gi_base_info_iterate_attributes (GIBaseInfo *info,
GIAttributeIter *iterator,
gchar **name,
gchar **value)
{
GIRealInfo *rinfo = (GIRealInfo *)info;
Header *header = (Header *)rinfo->typelib->data;
AttributeBlob *next, *after;
after = (AttributeBlob *) &rinfo->typelib->data[header->attributes +
header->n_attributes * header->attribute_blob_size];
if (iterator->data != NULL)
next = (AttributeBlob *) iterator->data;
else
next = _attribute_blob_find_first (info, rinfo->offset);
if (next == NULL || next->offset != rinfo->offset || next >= after)
return FALSE;
*name = (gchar*) gi_typelib_get_string (rinfo->typelib, next->name);
*value = (gchar*) gi_typelib_get_string (rinfo->typelib, next->value);
iterator->data = next + 1;
return TRUE;
}
/**
* gi_base_info_get_container:
* @info: a #GIBaseInfo
*
* Obtain the container of the @info. The container is the parent
* GIBaseInfo. For instance, the parent of a #GIFunctionInfo is an
* #GIObjectInfo or #GIInterfaceInfo.
*
* Returns: (transfer none): the container
*/
GIBaseInfo *
gi_base_info_get_container (GIBaseInfo *info)
{
return ((GIRealInfo*)info)->container;
}
/**
* gi_base_info_get_typelib:
* @info: a #GIBaseInfo
*
* Obtain the typelib this @info belongs to
*
* Returns: (transfer none): the typelib.
*/
GITypelib *
gi_base_info_get_typelib (GIBaseInfo *info)
{
return ((GIRealInfo*)info)->typelib;
}
/**
* gi_base_info_equal:
* @info1: a #GIBaseInfo
* @info2: a #GIBaseInfo
*
* Compare two #GIBaseInfo.
*
* Using pointer comparison is not practical since many functions return
* different instances of #GIBaseInfo that refers to the same part of the
* TypeLib; use this function instead to do #GIBaseInfo comparisons.
*
* Returns: %TRUE if and only if @info1 equals @info2.
*/
gboolean
gi_base_info_equal (GIBaseInfo *info1, GIBaseInfo *info2)
{
/* Compare the TypeLib pointers, which are mmapped. */
GIRealInfo *rinfo1 = (GIRealInfo*)info1;
GIRealInfo *rinfo2 = (GIRealInfo*)info2;
return rinfo1->typelib->data + rinfo1->offset == rinfo2->typelib->data + rinfo2->offset;
}