[gobject-introspection] Add support for GArrays: add g_type_info_get_array_type() and properly scan GArray args



commit 87291e08b0fd34b62e1ad9811c174108b38311a9
Author: Tomeu Vizoso <tomeu sugarlabs org>
Date:   Fri Apr 30 18:15:23 2010 +0200

    Add support for GArrays: add g_type_info_get_array_type() and properly scan GArray args
    
    Based on a previous patch by C. Scott Ananian <cscott litl com>
    
    https://bugzilla.gnome.org/show_bug.cgi?id=581687

 gir/gimarshallingtests.c            |  263 +++++++++++++++++++++++++++++++++++
 gir/gimarshallingtests.h            |   20 +++
 girepository/ginfo.c                |   17 +++
 girepository/girepository.h         |    8 +
 girepository/girnode.c              |    1 +
 girepository/girnode.h              |    1 +
 girepository/girparser.c            |   48 +++++--
 girepository/gtypelib.h             |    8 +-
 giscanner/annotationparser.py       |    6 +
 tests/scanner/foo-1.0-expected.gir  |    7 +
 tests/scanner/foo-1.0-expected.tgir |    7 +
 tests/scanner/foo.c                 |   10 ++
 tests/scanner/foo.h                 |    2 +
 13 files changed, 382 insertions(+), 16 deletions(-)
---
diff --git a/gir/gimarshallingtests.c b/gir/gimarshallingtests.c
index c48a430..0a8b794 100644
--- a/gir/gimarshallingtests.c
+++ b/gir/gimarshallingtests.c
@@ -1318,6 +1318,269 @@ g_i_marshalling_tests_array_zero_terminated_inout (gchar ***utf8s)
 
 
 /**
+ * g_i_marshalling_tests_garray_int_none_return:
+ * Returns: (element-type gint) (transfer none):
+ */
+GArray *
+g_i_marshalling_tests_garray_int_none_return (void)
+{
+    static GArray *array = NULL;
+    gint i;
+
+    if (array == NULL) {
+        array = g_array_new (TRUE, TRUE, sizeof (gint));
+        for (i = -1; i < 3; i++)
+            g_array_append_val (array, i);
+    }
+
+    return array;
+}
+
+/**
+ * g_i_marshalling_tests_garray_utf8_none_return:
+ * Returns: (element-type utf8) (transfer none):
+ */
+GArray *
+g_i_marshalling_tests_garray_utf8_none_return (void)
+{
+    static GArray *array = NULL;
+    static gchar *values[] = {"0", "1", "2", NULL};
+    gint i;
+
+    if (array == NULL) {
+        array = g_array_new (TRUE, TRUE, sizeof (gint));
+        for (i = 0; values[i]; i++)
+            g_array_append_val (array, values[i]);
+    }
+
+    return array;
+}
+
+/**
+ * g_i_marshalling_tests_garray_utf8_container_return:
+ * Returns: (element-type utf8) (transfer container):
+ */
+GArray *
+g_i_marshalling_tests_garray_utf8_container_return (void)
+{
+    GArray *array = NULL;
+    static gchar *values[] = {"0", "1", "2", NULL};
+    gint i;
+
+    array = g_array_new (TRUE, TRUE, sizeof (gint));
+    for (i = 0; values[i]; i++)
+        g_array_append_val (array, values[i]);
+
+    return array;
+}
+
+/**
+ * g_i_marshalling_tests_garray_utf8_full_return:
+ * Returns: (element-type utf8) (transfer full):
+ */
+GArray *
+g_i_marshalling_tests_garray_utf8_full_return (void)
+{
+    GArray *array = NULL;
+    static gchar *values[] = {"0", "1", "2", NULL};
+    gint i;
+
+    array = g_array_new (TRUE, TRUE, sizeof (gint));
+    for (i = 0; values[i]; i++) {
+        gchar *str = g_strdup (values[i]);
+        g_array_append_val (array, str);
+    }
+
+    return array;
+}
+
+/**
+ * g_i_marshalling_tests_garray_int_none_in:
+ * @array_: (element-type gint) (transfer none):
+ */
+void
+g_i_marshalling_tests_garray_int_none_in (GArray *array_)
+{
+    g_assert (array_->len == 4);
+    g_assert (g_array_index (array_, gint, 0) == -1);
+    g_assert (g_array_index (array_, gint, 1) == 0);
+    g_assert (g_array_index (array_, gint, 2) == 1);
+    g_assert (g_array_index (array_, gint, 3) == 2);
+}
+
+/**
+ * g_i_marshalling_tests_garray_utf8_none_in:
+ * @array_: (element-type utf8) (transfer none):
+ */
+void
+g_i_marshalling_tests_garray_utf8_none_in (GArray *array_)
+{
+    g_assert (array_->len == 3);
+    g_assert (strcmp (g_array_index (array_, gchar*, 0), "0") == 0);
+    g_assert (strcmp (g_array_index (array_, gchar*, 1), "1") == 0);
+    g_assert (strcmp (g_array_index (array_, gchar*, 2), "2") == 0);
+}
+
+/**
+ * g_i_marshalling_tests_garray_utf8_container_in:
+ * @array_: (element-type utf8) (transfer container):
+ */
+void
+g_i_marshalling_tests_garray_utf8_container_in (GArray *array_)
+{
+    g_assert (array_->len == 3);
+    g_assert (strcmp (g_array_index (array_, gchar*, 0), "0") == 0);
+    g_assert (strcmp (g_array_index (array_, gchar*, 1), "1") == 0);
+    g_assert (strcmp (g_array_index (array_, gchar*, 2), "2") == 0);
+    g_array_free (array_, TRUE);
+}
+
+/**
+ * g_i_marshalling_tests_garray_utf8_full_in:
+ * @array_: (element-type utf8) (transfer full):
+ */
+void
+g_i_marshalling_tests_garray_utf8_full_in (GArray *array_)
+{
+    g_assert (array_->len == 3);
+    g_assert (strcmp (g_array_index (array_, gchar*, 0), "0") == 0);
+    g_assert (strcmp (g_array_index (array_, gchar*, 1), "1") == 0);
+    g_assert (strcmp (g_array_index (array_, gchar*, 2), "2") == 0);
+    g_free (g_array_index (array_, gchar*, 0));
+    g_free (g_array_index (array_, gchar*, 1));
+    g_free (g_array_index (array_, gchar*, 2));
+    g_array_free (array_, TRUE);
+}
+
+/**
+ * g_i_marshalling_tests_garray_utf8_none_out:
+ * @array_: (out) (element-type utf8) (transfer none):
+ */
+void
+g_i_marshalling_tests_garray_utf8_none_out (GArray **array_)
+{
+    static GArray *internal = NULL;
+    static gchar *values[] = {"0", "1", "2", NULL};
+    gint i;
+
+    if (internal == NULL) {
+        internal = g_array_new (TRUE, TRUE, sizeof (gint));
+        for (i = 0; values[i]; i++)
+            g_array_append_val (internal, values[i]);
+    }
+
+    *array_ = internal;
+}
+
+/**
+ * g_i_marshalling_tests_garray_utf8_container_out:
+ * @array_: (out) (element-type utf8) (transfer container):
+ */
+void
+g_i_marshalling_tests_garray_utf8_container_out (GArray **array_)
+{
+    static gchar *values[] = {"0", "1", "2", NULL};
+    gint i;
+
+    *array_ = NULL;
+
+    *array_ = g_array_new (TRUE, TRUE, sizeof (gint));
+    for (i = 0; values[i]; i++)
+        g_array_append_val (*array_, values[i]);
+}
+
+/**
+ * g_i_marshalling_tests_garray_utf8_full_out:
+ * @array_: (out) (element-type utf8) (transfer full):
+ */
+void
+g_i_marshalling_tests_garray_utf8_full_out (GArray **array_)
+{
+    static gchar *values[] = {"0", "1", "2", NULL};
+    gint i;
+
+    *array_ = NULL;
+
+    *array_ = g_array_new (TRUE, TRUE, sizeof (gint));
+    for (i = 0; values[i]; i++) {
+        gchar *str = g_strdup (values[i]);
+        g_array_append_val (*array_, str);
+    }
+}
+
+/**
+ * g_i_marshalling_tests_garray_utf8_none_inout:
+ * @array_: (inout) (element-type utf8) (transfer none):
+ */
+void
+g_i_marshalling_tests_garray_utf8_none_inout (GArray **array_)
+{
+    static GArray *internal = NULL;
+    static gchar *values[] = {"-2", "-1", "0", "1", NULL};
+    gint i;
+
+    g_assert ((*array_)->len == 3);
+    g_assert (strcmp (g_array_index (*array_, gchar*, 0), "0") == 0);
+    g_assert (strcmp (g_array_index (*array_, gchar*, 1), "1") == 0);
+    g_assert (strcmp (g_array_index (*array_, gchar*, 2), "2") == 0);
+
+    if (internal == NULL) {
+        internal = g_array_new (TRUE, TRUE, sizeof (gint));
+        for (i = 0; values[i]; i++)
+            g_array_append_val (internal, values[i]);
+    }
+
+    *array_ = internal;
+}
+
+/**
+ * g_i_marshalling_tests_garray_utf8_container_inout:
+ * @array_: (inout) (element-type utf8) (transfer container):
+ */
+void
+g_i_marshalling_tests_garray_utf8_container_inout (GArray **array_)
+{
+    static gchar *val1 = "-1";
+    static gchar *val2 = "-2";
+
+    g_assert ((*array_)->len == 3);
+    g_assert (strcmp (g_array_index (*array_, gchar*, 0), "0") == 0);
+    g_assert (strcmp (g_array_index (*array_, gchar*, 1), "1") == 0);
+    g_assert (strcmp (g_array_index (*array_, gchar*, 2), "2") == 0);
+
+    g_array_remove_index (*array_, (*array_)->len - 1);
+
+    g_array_prepend_val (*array_, val1);
+    g_array_prepend_val (*array_, val2);
+}
+
+/**
+ * g_i_marshalling_tests_garray_utf8_full_inout:
+ * @array_: (inout) (element-type utf8) (transfer full):
+ */
+void
+g_i_marshalling_tests_garray_utf8_full_inout (GArray **array_)
+{
+    static gchar *val1 = "-1";
+    static gchar *val2 = "-2";
+    gchar *val;
+
+    g_assert ((*array_)->len == 3);
+    g_assert (strcmp (g_array_index (*array_, gchar*, 0), "0") == 0);
+    g_assert (strcmp (g_array_index (*array_, gchar*, 1), "1") == 0);
+    g_assert (strcmp (g_array_index (*array_, gchar*, 2), "2") == 0);
+
+    g_free (g_array_index (*array_, gchar*, (*array_)->len - 1));
+    g_array_remove_index (*array_, (*array_)->len - 1);
+
+    val = g_strdup (val1);
+    g_array_prepend_val (*array_, val);
+
+    val = g_strdup (val2);
+    g_array_prepend_val (*array_, val);
+}
+
+/**
  * g_i_marshalling_tests_glist_int_none_return:
  * Returns: (element-type gint) (transfer none):
  */
diff --git a/gir/gimarshallingtests.h b/gir/gimarshallingtests.h
index 298f544..dd41866 100644
--- a/gir/gimarshallingtests.h
+++ b/gir/gimarshallingtests.h
@@ -296,6 +296,26 @@ void g_i_marshalling_tests_array_zero_terminated_out (gchar ***utf8s);
 void g_i_marshalling_tests_array_zero_terminated_inout (gchar ***utf8s);
 
 
+/* GArray */
+
+GArray *g_i_marshalling_tests_garray_int_none_return (void);
+GArray *g_i_marshalling_tests_garray_utf8_none_return (void);
+GArray *g_i_marshalling_tests_garray_utf8_container_return (void);
+GArray *g_i_marshalling_tests_garray_utf8_full_return (void);
+
+void g_i_marshalling_tests_garray_int_none_in (GArray *array_);
+void g_i_marshalling_tests_garray_utf8_none_in (GArray *array_);
+void g_i_marshalling_tests_garray_utf8_container_in (GArray *array_);
+void g_i_marshalling_tests_garray_utf8_full_in (GArray *array_);
+
+void g_i_marshalling_tests_garray_utf8_none_out (GArray **array_);
+void g_i_marshalling_tests_garray_utf8_container_out (GArray **array_);
+void g_i_marshalling_tests_garray_utf8_full_out (GArray **array_);
+
+void g_i_marshalling_tests_garray_utf8_none_inout (GArray **array_);
+void g_i_marshalling_tests_garray_utf8_container_inout (GArray **array_);
+void g_i_marshalling_tests_garray_utf8_full_inout (GArray **array_);
+
 /* GList */
 
 GList *g_i_marshalling_tests_glist_int_none_return (void);
diff --git a/girepository/ginfo.c b/girepository/ginfo.c
index 724109f..1d56a22 100644
--- a/girepository/ginfo.c
+++ b/girepository/ginfo.c
@@ -1093,6 +1093,23 @@ g_type_info_is_zero_terminated (GITypeInfo *info)
   return FALSE;
 }
 
+GIArrayType
+g_type_info_get_array_type (GITypeInfo *info)
+{
+  GIRealInfo *rinfo = (GIRealInfo *)info;
+  SimpleTypeBlob *type = (SimpleTypeBlob *)&rinfo->typelib->data[rinfo->offset];
+
+  if (!(type->flags.reserved == 0 && type->flags.reserved2 == 0))
+    {
+      ArrayTypeBlob *blob = (ArrayTypeBlob *)&rinfo->typelib->data[rinfo->offset];
+      g_return_val_if_fail (blob->tag == GI_TYPE_TAG_ARRAY, -1);
+
+      return blob->array_type;
+    }
+
+  return -1;
+}
+
 gint
 g_type_info_get_n_error_domains (GITypeInfo *info)
 {
diff --git a/girepository/girepository.h b/girepository/girepository.h
index cfa5b39..9e62ab1 100644
--- a/girepository/girepository.h
+++ b/girepository/girepository.h
@@ -383,6 +383,13 @@ typedef enum {
    * See docs/typelib-format.txt SimpleTypeBlob definition */
 } GITypeTag;
 
+typedef enum {
+  GI_ARRAY_TYPE_C,
+  GI_ARRAY_TYPE_ARRAY,
+  GI_ARRAY_TYPE_PTR_ARRAY,
+  GI_ARRAY_TYPE_BYTE_ARRAY
+} GIArrayType;
+
 #define G_TYPE_TAG_IS_BASIC(tag) (tag < GI_TYPE_TAG_ARRAY)
 
 const gchar*           g_type_tag_to_string            (GITypeTag   type);
@@ -395,6 +402,7 @@ GIBaseInfo *           g_type_info_get_interface       (GITypeInfo *info);
 gint                   g_type_info_get_array_length    (GITypeInfo *info);
 gint                   g_type_info_get_array_fixed_size(GITypeInfo *info);
 gboolean               g_type_info_is_zero_terminated  (GITypeInfo *info);
+GIArrayType            g_type_info_get_array_type      (GITypeInfo *info);
 
 gint                   g_type_info_get_n_error_domains (GITypeInfo *info);
 GIErrorDomainInfo     *g_type_info_get_error_domain    (GITypeInfo *info,
diff --git a/girepository/girnode.c b/girepository/girnode.c
index 1694406..6f4a44a 100644
--- a/girepository/girnode.c
+++ b/girepository/girnode.c
@@ -1497,6 +1497,7 @@ g_ir_node_build_typelib (GIrNode         *node,
 		      array->zero_terminated = type->zero_terminated;
 		      array->has_length = type->has_length;
                       array->has_size = type->has_size;
+                      array->array_type = type->array_type;
 		      array->reserved2 = 0;
                       if (array->has_length)
                         array->dimensions.length = type->length;
diff --git a/girepository/girnode.h b/girepository/girnode.h
index 7fe235b..5e6cba0 100644
--- a/girepository/girnode.h
+++ b/girepository/girnode.h
@@ -138,6 +138,7 @@ struct _GIrNodeType
   gint length;
   gboolean has_size;
   gint size;
+  gint array_type;
 
   GIrNodeType *parameter_type1;
   GIrNodeType *parameter_type2;
diff --git a/girepository/girparser.c b/girepository/girparser.c
index 5b24604..85f85e2 100644
--- a/girepository/girparser.c
+++ b/girepository/girparser.c
@@ -1717,22 +1717,40 @@ start_type (GMarkupParseContext *context,
       typenode->is_pointer = TRUE;
       typenode->is_array = TRUE;
 
-      zero = find_attribute ("zero-terminated", attribute_names, attribute_values);
-      len = find_attribute ("length", attribute_names, attribute_values);
-      size = find_attribute ("fixed-size", attribute_names, attribute_values);
-
-      typenode->zero_terminated = !(zero && strcmp (zero, "1") != 0);
-      typenode->has_length = len != NULL;
-      typenode->length = typenode->has_length ? atoi (len) : -1;
-
-      typenode->has_size = size != NULL;
-      typenode->size = typenode->has_size ? atoi (size) : -1;
+      ctype = find_attribute ("c:type", attribute_names, attribute_values);
+      if (g_str_has_prefix (ctype, "GArray")) {
+        typenode->array_type = GI_ARRAY_TYPE_ARRAY;
+      } else if (g_str_has_prefix (ctype, "GByteArray")) {
+        typenode->array_type = GI_ARRAY_TYPE_BYTE_ARRAY;
+      } else if (g_str_has_prefix (ctype, "GPtrArray")) {
+        typenode->array_type = GI_ARRAY_TYPE_PTR_ARRAY;
+      } else {
+        typenode->array_type = GI_ARRAY_TYPE_C;
+      }
 
-      if (zero)
-        typenode->zero_terminated = strcmp(zero, "1") == 0;
-      else
-        /* If neither zero-terminated nor length nor fixed-size is given, assume zero-terminated. */
-        typenode->zero_terminated = !(typenode->has_length || typenode->has_size);
+      if (typenode->array_type == GI_ARRAY_TYPE_C) {
+          zero = find_attribute ("zero-terminated", attribute_names, attribute_values);
+          len = find_attribute ("length", attribute_names, attribute_values);
+          size = find_attribute ("fixed-size", attribute_names, attribute_values);
+
+          typenode->has_length = len != NULL;
+          typenode->length = typenode->has_length ? atoi (len) : -1;
+
+          typenode->has_size = size != NULL;
+          typenode->size = typenode->has_size ? atoi (size) : -1;
+
+          if (zero)
+            typenode->zero_terminated = strcmp(zero, "1") == 0;
+          else
+            /* If neither zero-terminated nor length nor fixed-size is given, assume zero-terminated. */
+            typenode->zero_terminated = !(typenode->has_length || typenode->has_size);
+        } else {
+          typenode->zero_terminated = FALSE;
+          typenode->has_length = FALSE;
+          typenode->length = -1;
+          typenode->has_size = FALSE;
+          typenode->size = -1;
+        }
     }
   else
     {
diff --git a/girepository/gtypelib.h b/girepository/gtypelib.h
index 14edc98..8208014 100644
--- a/girepository/gtypelib.h
+++ b/girepository/gtypelib.h
@@ -524,9 +524,14 @@ typedef struct {
  * of the array. If both has_length and zero_terminated are set, the
  * convention is to pass -1 for the length if the array is
  * zero-terminated.
+ * @has_size: Indicates that size is the fixed size of the array.
+ * @array_type: Indicates whether this is a C array, GArray, GPtrArray, or
+ * GByteArray. If something other than a C array, the length and element size
+ * are implicit in the structure.
  * @length: The index of the parameter which is used to pass the length of the
  * array. The parameter must be an integer type and have the same
  * direction as this one.
+ * @size: The fixed size of the array.
  * @type: The type of the array elements.
  *
  * Arrays are passed by reference, thus is_pointer is always 1.
@@ -539,7 +544,8 @@ typedef struct {
   guint16 zero_terminated :1;
   guint16 has_length      :1;
   guint16 has_size        :1;
-  guint16 reserved2       :5;
+  guint16 array_type      :2;
+  guint16 reserved2       :3;
 
   union {
     guint16 length;
diff --git a/giscanner/annotationparser.py b/giscanner/annotationparser.py
index 3480ac7..f70bfa4 100644
--- a/giscanner/annotationparser.py
+++ b/giscanner/annotationparser.py
@@ -605,6 +605,12 @@ class AnnotationApplier(object):
         has_element_type = OPT_ELEMENT_TYPE in options
         has_array = OPT_ARRAY in options
 
+        if not has_array:
+            has_array = \
+                node.type.name in ['GLib.Array', 'GLib.PtrArray',
+                                   'GLib.ByteArray'] or \
+                node.type.ctype in ['GArray*', 'GPtrArray*', 'GByteArray*']
+
         # FIXME: This is a hack :-(
         if (not isinstance(node, Field) and
             (not has_element_type and
diff --git a/tests/scanner/foo-1.0-expected.gir b/tests/scanner/foo-1.0-expected.gir
index d29a068..3bd2d89 100644
--- a/tests/scanner/foo-1.0-expected.gir
+++ b/tests/scanner/foo-1.0-expected.gir
@@ -789,6 +789,13 @@ uses a C sugar return type.">
         </parameter>
       </parameters>
     </function>
+    <function name="test_array" c:identifier="foo_test_array">
+      <return-value transfer-ownership="container">
+        <array c:type="GArray*">
+          <type name="utf8"/>
+        </array>
+      </return-value>
+    </function>
     <function name="test_const_char_param"
               c:identifier="foo_test_const_char_param">
       <return-value transfer-ownership="none">
diff --git a/tests/scanner/foo-1.0-expected.tgir b/tests/scanner/foo-1.0-expected.tgir
index ea7aa70..29753af 100644
--- a/tests/scanner/foo-1.0-expected.tgir
+++ b/tests/scanner/foo-1.0-expected.tgir
@@ -645,6 +645,13 @@
         </parameter>
       </parameters>
     </function>
+    <function name="test_array" c:identifier="foo_test_array">
+      <return-value transfer-ownership="container">
+        <array>
+          <type name="utf8"/>
+        </array>
+      </return-value>
+    </function>
     <function name="test_const_char_param" c:identifier="foo_test_const_char_param">
       <return-value transfer-ownership="none">
         <type name="none"/>
diff --git a/tests/scanner/foo.c b/tests/scanner/foo.c
index d2fb23b..a404aac 100644
--- a/tests/scanner/foo.c
+++ b/tests/scanner/foo.c
@@ -455,6 +455,16 @@ foo_test_string_array (char **array)
 }
 
 /**
+ * foo_test_array:
+ * Returns: (element-type utf8) (transfer container):
+ */
+GArray *
+foo_test_array (void)
+{
+  return NULL;
+}
+
+/**
  * foo_rectangle_add:
  * @r1: (inout): add to this rect
  * @r2: source rectangle
diff --git a/tests/scanner/foo.h b/tests/scanner/foo.h
index 61c2ca4..0ebcca2 100644
--- a/tests/scanner/foo.h
+++ b/tests/scanner/foo.h
@@ -334,6 +334,8 @@ void foo_test_string_array (char **array);
 
 void foo_test_string_array_with_g (gchar **array);
 
+GArray *foo_test_array (void);
+
 const char * foo_test_const_char_retval (void);
 const FooStruct * foo_test_const_struct_retval (void);
 void foo_test_const_char_param (const char * param);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]