File: gperl-i11n-marshal-array.c

package info (click to toggle)
libglib-object-introspection-perl 0.009-1%2Bdeb7u1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 376 kB
  • sloc: ansic: 2,361; perl: 716; makefile: 5
file content (172 lines) | stat: -rw-r--r-- 5,041 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
/* -*- mode: c; indent-tabs-mode: t; c-basic-offset: 8; -*- */

/* This may call Perl code (via arg_to_sv), so it needs to be wrapped with
 * PUTBACK/SPAGAIN by the caller. */
static SV *
array_to_sv (GITypeInfo *info,
             gpointer pointer,
             GITransfer transfer,
             GPerlI11nInvocationInfo *iinfo)
{
	GITypeInfo *param_info;
	gboolean is_zero_terminated;
	gsize item_size;
	GITransfer item_transfer;
	gssize length, i;
	AV *av;

	if (pointer == NULL) {
		return &PL_sv_undef;
	}

	is_zero_terminated = g_type_info_is_zero_terminated (info);
	param_info = g_type_info_get_param_type (info, 0);
	item_size = size_of_type_info (param_info);

	/* FIXME: What about an array containing arrays of strings, where the
	 * outer array is GI_TRANSFER_EVERYTHING but the inner arrays are
	 * GI_TRANSFER_CONTAINER? */
	item_transfer = transfer == GI_TRANSFER_EVERYTHING
		? GI_TRANSFER_EVERYTHING
		: GI_TRANSFER_NOTHING;

	if (is_zero_terminated) {
		length = g_strv_length (pointer);
	} else {
                length = g_type_info_get_array_fixed_size (info);
                if (length < 0) {
			guint length_pos = g_type_info_get_array_length (info);
			g_assert (iinfo && iinfo->aux_args);
			/* FIXME: Is it OK to always use v_size here? */
			length = iinfo->aux_args[length_pos].v_size;
                }
	}

	if (length < 0) {
		ccroak ("Could not determine the length of the array");
	}

	av = newAV ();

	dwarn ("    C array: pointer %p, length %d, item size %d, "
	       "param_info %p with type tag %d (%s)\n",
	       pointer,
	       length,
	       item_size,
	       param_info,
	       g_type_info_get_tag (param_info),
	       g_type_tag_to_string (g_type_info_get_tag (param_info)));

	for (i = 0; i < length; i++) {
		GIArgument *arg;
		SV *value;
		arg = pointer + i * item_size;
		value = arg_to_sv (arg, param_info, item_transfer, iinfo);
		if (value)
			av_push (av, value);
	}

	if (transfer >= GI_TRANSFER_CONTAINER)
		g_free (pointer);

	g_base_info_unref ((GIBaseInfo *) param_info);

	return newRV_noinc ((SV *) av);
}

static gpointer
sv_to_array (GITransfer transfer,
             GITypeInfo *type_info,
             SV *sv,
             GPerlI11nInvocationInfo *iinfo)
{
	AV *av;
	GITransfer item_transfer;
	GITypeInfo *param_info;
	GITypeTag param_tag;
	gint i, length, length_pos;
	GPerlI11nArrayInfo *array_info = NULL;
        GArray *array;
        gboolean is_zero_terminated = FALSE;
        gsize item_size;
	gboolean need_struct_value_semantics;

	dwarn ("%s: sv %p\n", G_STRFUNC, sv);

	/* Add an array info entry even before the undef check so that the
	 * corresponding length arg is set to zero later by
	 * handle_automatic_arg. */
	length_pos = g_type_info_get_array_length (type_info);
	if (length_pos >= 0) {
		array_info = g_new0 (GPerlI11nArrayInfo, 1);
		array_info->length_pos = length_pos;
		array_info->length = 0;
		iinfo->array_infos = g_slist_prepend (iinfo->array_infos, array_info);
	}

	if (!gperl_sv_is_defined (sv))
		return NULL;

	if (!gperl_sv_is_array_ref (sv))
		ccroak ("need an array ref to convert to GArray");

	av = (AV *) SvRV (sv);

        item_transfer = transfer == GI_TRANSFER_CONTAINER
                      ? GI_TRANSFER_NOTHING
                      : transfer;

	param_info = g_type_info_get_param_type (type_info, 0);
	param_tag = g_type_info_get_tag (param_info);
	dwarn ("  GArray: param_info %p with type tag %d (%s) and transfer %d\n",
	       param_info, param_tag,
	       g_type_tag_to_string (g_type_info_get_tag (param_info)),
	       transfer);

        is_zero_terminated = g_type_info_is_zero_terminated (type_info);
        item_size = size_of_type_info (param_info);
	length = av_len (av) + 1;
        array = g_array_sized_new (is_zero_terminated, FALSE, item_size, length);

	/* Arrays containing non-basic types as non-pointers need to be treated
	 * specially.  Prime example: GValue *values = g_new0 (GValue, n);
	 */
	need_struct_value_semantics =
		/* is a compound type, and... */
		!G_TYPE_TAG_IS_BASIC (param_tag) &&
		/* ... a non-pointer is wanted */
		!g_type_info_is_pointer (param_info);
	for (i = 0; i < length; i++) {
		SV **svp;
		svp = av_fetch (av, i, 0);
		if (svp && gperl_sv_is_defined (*svp)) {
			GIArgument arg;

			dwarn ("    converting SV %p\n", *svp);
			/* FIXME: Is it OK to always allow undef here? */
			sv_to_arg (*svp, &arg, NULL, param_info,
			           item_transfer, TRUE, NULL);

                        if (need_struct_value_semantics) {
				/* Copy from the memory area pointed to by
				 * arg.v_pointer. */
				g_array_insert_vals (array, i, arg.v_pointer, 1);
			} else {
				/* Copy from &arg, i.e. the memory area that is
				 * arg. */
				g_array_insert_val (array, i, arg);
			}
		}
	}

	dwarn ("    -> array %p of size %d\n", array, array->len);

	if (length_pos >= 0) {
		array_info->length = length;
	}

	g_base_info_unref ((GIBaseInfo *) param_info);

	/* FIXME: for transfer=nothing, we seem to be leaking the bare array. */
	return g_array_free (array, FALSE);
}