Bug 552371 – implement struct field get/set
authorOwen Taylor <otaylor@src.gnome.org>
Sun, 16 Nov 2008 21:14:19 +0000 (21:14 +0000)
committerOwen Taylor <otaylor@src.gnome.org>
Sun, 16 Nov 2008 21:14:19 +0000 (21:14 +0000)
Add convenience functions g_field_info_set_field() and
g_field_info_get_field() to set and get fields based on the offsets
in GIFieldInfo.

svn path=/trunk/; revision=929

ChangeLog
girepository/Makefile.am
girepository/gfield.c [new file with mode: 0644]
girepository/girepository.h

index 721a9a5..ff663e8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,10 +1,19 @@
+2008-11-16  Owen Taylor  <otaylor@redhat.com>
+
+       Bug 552371 – implement struct field get/set
+
+       * girepository/gfield.c girepository/girepository.h: Add
+       convenience functions g_field_info_set_field() and
+       g_field_info_get_field() to set and get fields based on the
+       offsets in GIFieldInfo.
+
 2008-11-16  Andreas Rottmann  <a.rottmann@gmx.at>
 
        Bug 560241 - Out-arguments should not be marked as being pointers
        in all cases
 
        * girepository/girparser.c: Improved logic for out arguments.
-       
+
 2008-11-16  Andreas Rottmann  <a.rottmann@gmx.at>
 
        Bug 559601 - Pointers in structs/unions unduly treated as arrays
index b58288e..f98dda2 100644 (file)
@@ -12,6 +12,7 @@ libgirepository_la_SOURCES =                  \
        girepository.c                          \
        gtypelib.h                              \
        gtypelib.c                              \
+       gfield.c                                \
        ginfo.c                                 \
        girffi.c                                \
        girffi.h                                \
diff --git a/girepository/gfield.c b/girepository/gfield.c
new file mode 100644 (file)
index 0000000..79a5a0d
--- /dev/null
@@ -0,0 +1,308 @@
+#include "girepository.h"
+
+/**
+ * g_field_info_get_field:
+ * @field_info: a #GIFieldInfo
+ * @mem: pointer to a block of memory representing a C structure or union
+ * @value: a #GArgument into which to store the value retrieved
+ *
+ * Reads a field identified by a #GFieldInfo from a C structure or
+ * union.  This only handles fields of simple C types. It will fail
+ * for a field of a composite type like a nested structure or union
+ * even if that is actually readable.
+ *
+ * Returns: %TRUE if reading the field succeeded, otherwise %FALSE
+ */
+gboolean
+g_field_info_get_field (GIFieldInfo *field_info,
+                       gpointer     mem,
+                       GArgument   *value)
+{
+    int offset;
+    GITypeInfo *type_info;
+    gboolean result = FALSE;
+
+    if (!g_field_info_get_flags (field_info) & GI_FIELD_IS_READABLE)
+      return FALSE;
+
+    offset = g_field_info_get_offset (field_info);
+    type_info = g_field_info_get_type (field_info);
+
+    if (g_type_info_is_pointer (type_info))
+      {
+       value->v_pointer = G_STRUCT_MEMBER(gpointer, mem, offset);
+       result = TRUE;
+      }
+    else
+      {
+       switch (g_type_info_get_tag (type_info))
+         {
+         case GI_TYPE_TAG_VOID:
+           g_warning("Field %s: should not be have void type",
+                     g_base_info_get_name ((GIBaseInfo *)field_info));
+           break;
+         case GI_TYPE_TAG_BOOLEAN:
+           value->v_boolean = G_STRUCT_MEMBER(gboolean, mem, offset) != FALSE;
+           result = TRUE;
+           break;
+         case GI_TYPE_TAG_INT8:
+         case GI_TYPE_TAG_UINT8:
+           value->v_uint8 = G_STRUCT_MEMBER(guint8, mem, offset);
+           result = TRUE;
+           break;
+         case GI_TYPE_TAG_INT16:
+         case GI_TYPE_TAG_UINT16:
+           value->v_uint16 = G_STRUCT_MEMBER(guint16, mem, offset);
+           result = TRUE;
+           break;
+         case GI_TYPE_TAG_INT32:
+         case GI_TYPE_TAG_UINT32:
+         case GI_TYPE_TAG_INT:
+         case GI_TYPE_TAG_UINT:
+           value->v_uint32 = G_STRUCT_MEMBER(guint32, mem, offset);
+           result = TRUE;
+           break;
+         case GI_TYPE_TAG_INT64:
+         case GI_TYPE_TAG_UINT64:
+           value->v_uint64 = G_STRUCT_MEMBER(guint64, mem, offset);
+           result = TRUE;
+           break;
+         case GI_TYPE_TAG_LONG:
+         case GI_TYPE_TAG_ULONG:
+           value->v_ulong = G_STRUCT_MEMBER(gulong, mem, offset);
+           result = TRUE;
+           break;
+         case GI_TYPE_TAG_SSIZE:
+         case GI_TYPE_TAG_SIZE:
+         case GI_TYPE_TAG_GTYPE:
+           value->v_size = G_STRUCT_MEMBER(gsize, mem, offset);
+           result = TRUE;
+           break;
+         case GI_TYPE_TAG_FLOAT:
+           value->v_float = G_STRUCT_MEMBER(gfloat, mem, offset);
+           result = TRUE;
+           break;
+         case GI_TYPE_TAG_DOUBLE:
+           value->v_double = G_STRUCT_MEMBER(gdouble, mem, offset);
+           result = TRUE;
+           break;
+         case GI_TYPE_TAG_TIME_T:
+           value->v_long = G_STRUCT_MEMBER(time_t, mem, offset);
+           result = TRUE;
+           break;
+         case GI_TYPE_TAG_UTF8:
+         case GI_TYPE_TAG_FILENAME:
+         case GI_TYPE_TAG_ARRAY:
+         case GI_TYPE_TAG_GLIST:
+         case GI_TYPE_TAG_GSLIST:
+         case GI_TYPE_TAG_GHASH:
+           g_warning("Field %s: type %s should have is_pointer set",
+                     g_base_info_get_name ((GIBaseInfo *)field_info),
+                     g_type_tag_to_string (g_type_info_get_tag (type_info)));
+           break;
+         case GI_TYPE_TAG_ERROR:
+           /* Needs to be handled by the language binding directly */
+           break;
+         case GI_TYPE_TAG_INTERFACE:
+           {
+             GIBaseInfo *interface = g_type_info_get_interface (type_info);
+             switch (g_base_info_get_type (interface))
+               {
+               case GI_INFO_TYPE_STRUCT:
+               case GI_INFO_TYPE_UNION:
+               case GI_INFO_TYPE_BOXED:
+                 /* Needs to be handled by the language binding directly */
+                 break;
+               case GI_INFO_TYPE_OBJECT:
+                 break;
+               case GI_INFO_TYPE_ENUM:
+               case GI_INFO_TYPE_FLAGS:
+                 /* Not yet implemented */
+                 break;
+               case GI_INFO_TYPE_VFUNC:
+               case GI_INFO_TYPE_CALLBACK:
+                 g_warning("Field%s: Interface type %d should have is_pointer set",
+                           g_base_info_get_name ((GIBaseInfo *)field_info),
+                           g_base_info_get_type (interface));
+                 break;
+               case GI_INFO_TYPE_INVALID:
+               case GI_INFO_TYPE_INTERFACE:
+               case GI_INFO_TYPE_FUNCTION:
+               case GI_INFO_TYPE_CONSTANT:
+               case GI_INFO_TYPE_ERROR_DOMAIN:
+               case GI_INFO_TYPE_VALUE:
+               case GI_INFO_TYPE_SIGNAL:
+               case GI_INFO_TYPE_PROPERTY:
+               case GI_INFO_TYPE_FIELD:
+               case GI_INFO_TYPE_ARG:
+               case GI_INFO_TYPE_TYPE:
+               case GI_INFO_TYPE_UNRESOLVED:
+                 g_warning("Field %s: Interface type %d not expected",
+                           g_base_info_get_name ((GIBaseInfo *)field_info),
+                           g_base_info_get_type (interface));
+                 break;
+               }
+
+             g_base_info_unref ((GIBaseInfo *)interface);
+             break;
+           }
+           break;
+         }
+      }
+
+    g_base_info_unref ((GIBaseInfo *)field_info);
+
+    return result;
+}
+
+/**
+ * g_field_info_set_field:
+ * @field_info: a #GIFieldInfo
+ * @mem: pointer to a block of memory representing a C structure or union
+ * @value: a #GArgument holding the value to store
+ *
+ * Writes a field identified by a #GFieldInfo to a C structure or
+ * union.  This only handles fields of simple C types. It will fail
+ * for a field of a composite type like a nested structure or union
+ * even if that is actually writable. Note also that that it will refuse
+ * to write fields where memory management would by required. A field
+ * with a type such as 'char *' must be set with a setter function.
+ *
+ * Returns: %TRUE if reading the field succeeded, otherwise %FALSE
+ */
+gboolean
+g_field_info_set_field (GIFieldInfo     *field_info,
+                       gpointer         mem,
+                       const GArgument *value)
+{
+    int offset;
+    GITypeInfo *type_info;
+    gboolean result = FALSE;
+
+    if (!g_field_info_get_flags (field_info) & GI_FIELD_IS_WRITABLE)
+      return FALSE;
+
+    offset = g_field_info_get_offset (field_info);
+    type_info = g_field_info_get_type (field_info);
+
+    if (!g_type_info_is_pointer (type_info))
+      {
+       switch (g_type_info_get_tag (type_info))
+         {
+         case GI_TYPE_TAG_VOID:
+           g_warning("Field %s: should not be have void type",
+                     g_base_info_get_name ((GIBaseInfo *)field_info));
+           break;
+         case GI_TYPE_TAG_BOOLEAN:
+           G_STRUCT_MEMBER(gboolean, mem, offset) = value->v_boolean != FALSE;
+           result = TRUE;
+           break;
+         case GI_TYPE_TAG_INT8:
+         case GI_TYPE_TAG_UINT8:
+           G_STRUCT_MEMBER(guint8, mem, offset) = value->v_uint8;
+           result = TRUE;
+           break;
+         case GI_TYPE_TAG_INT16:
+         case GI_TYPE_TAG_UINT16:
+           G_STRUCT_MEMBER(guint16, mem, offset) = value->v_uint16;
+           result = TRUE;
+           break;
+         case GI_TYPE_TAG_INT32:
+         case GI_TYPE_TAG_UINT32:
+         case GI_TYPE_TAG_INT:
+         case GI_TYPE_TAG_UINT:
+           G_STRUCT_MEMBER(guint32, mem, offset) = value->v_uint32;
+           result = TRUE;
+           break;
+         case GI_TYPE_TAG_INT64:
+         case GI_TYPE_TAG_UINT64:
+           G_STRUCT_MEMBER(guint64, mem, offset) = value->v_uint64;
+           result = TRUE;
+           break;
+         case GI_TYPE_TAG_LONG:
+         case GI_TYPE_TAG_ULONG:
+           G_STRUCT_MEMBER(gulong, mem, offset)= value->v_ulong;
+           result = TRUE;
+           break;
+         case GI_TYPE_TAG_SSIZE:
+         case GI_TYPE_TAG_SIZE:
+         case GI_TYPE_TAG_GTYPE:
+           G_STRUCT_MEMBER(gsize, mem, offset) = value->v_size;
+           result = TRUE;
+           break;
+         case GI_TYPE_TAG_FLOAT:
+           G_STRUCT_MEMBER(gfloat, mem, offset) = value->v_float;
+           result = TRUE;
+           break;
+         case GI_TYPE_TAG_DOUBLE:
+           G_STRUCT_MEMBER(gdouble, mem, offset)= value->v_double;
+           result = TRUE;
+           break;
+         case GI_TYPE_TAG_TIME_T:
+           G_STRUCT_MEMBER(time_t, mem, offset) = value->v_long;
+           result = TRUE;
+           break;
+         case GI_TYPE_TAG_UTF8:
+         case GI_TYPE_TAG_FILENAME:
+         case GI_TYPE_TAG_ARRAY:
+         case GI_TYPE_TAG_GLIST:
+         case GI_TYPE_TAG_GSLIST:
+         case GI_TYPE_TAG_GHASH:
+           g_warning("Field %s: type %s should have is_pointer set",
+                     g_base_info_get_name ((GIBaseInfo *)field_info),
+                     g_type_tag_to_string (g_type_info_get_tag (type_info)));
+           break;
+         case GI_TYPE_TAG_ERROR:
+           /* Needs to be handled by the language binding directly */
+           break;
+         case GI_TYPE_TAG_INTERFACE:
+           {
+             GIBaseInfo *interface = g_type_info_get_interface (type_info);
+             switch (g_base_info_get_type (interface))
+               {
+               case GI_INFO_TYPE_STRUCT:
+               case GI_INFO_TYPE_UNION:
+               case GI_INFO_TYPE_BOXED:
+                 /* Needs to be handled by the language binding directly */
+                 break;
+               case GI_INFO_TYPE_OBJECT:
+                 break;
+               case GI_INFO_TYPE_ENUM:
+               case GI_INFO_TYPE_FLAGS:
+                 /* Not yet implemented */
+                 break;
+               case GI_INFO_TYPE_VFUNC:
+               case GI_INFO_TYPE_CALLBACK:
+                 g_warning("Field%s: Interface type %d should have is_pointer set",
+                           g_base_info_get_name ((GIBaseInfo *)field_info),
+                           g_base_info_get_type (interface));
+                 break;
+               case GI_INFO_TYPE_INVALID:
+               case GI_INFO_TYPE_INTERFACE:
+               case GI_INFO_TYPE_FUNCTION:
+               case GI_INFO_TYPE_CONSTANT:
+               case GI_INFO_TYPE_ERROR_DOMAIN:
+               case GI_INFO_TYPE_VALUE:
+               case GI_INFO_TYPE_SIGNAL:
+               case GI_INFO_TYPE_PROPERTY:
+               case GI_INFO_TYPE_FIELD:
+               case GI_INFO_TYPE_ARG:
+               case GI_INFO_TYPE_TYPE:
+               case GI_INFO_TYPE_UNRESOLVED:
+                 g_warning("Field %s: Interface type %d not expected",
+                           g_base_info_get_name ((GIBaseInfo *)field_info),
+                           g_base_info_get_type (interface));
+                 break;
+               }
+
+             g_base_info_unref ((GIBaseInfo *)interface);
+             break;
+           }
+           break;
+         }
+      }
+
+    g_base_info_unref ((GIBaseInfo *)field_info);
+
+    return result;
+}
index 46082e0..fc5768c 100644 (file)
@@ -356,6 +356,12 @@ gint                   g_field_info_get_size       (GIFieldInfo *info);
 gint                   g_field_info_get_offset     (GIFieldInfo *info);
 GITypeInfo *           g_field_info_get_type       (GIFieldInfo *info);
 
+gboolean g_field_info_get_field (GIFieldInfo     *field_info,
+                                gpointer         mem,
+                                GArgument       *value);
+gboolean g_field_info_set_field (GIFieldInfo     *field_info,
+                                gpointer         mem,
+                                const GArgument *value);
 
 /* GIUnionInfo */
 gint                   g_union_info_get_n_fields  (GIUnionInfo *info);