blob: f0a5abcd9532d24440d3011c0ddad662ccc5e697 [file] [log] [blame]
/* nih-dbus-tool
*
* marshal.c - type marshalling
*
* Copyright © 2009 Scott James Remnant <scott@netsplit.com>.
* Copyright © 2009 Canonical Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* HAVE_CONFIG_H */
#include <dbus/dbus.h>
#include <string.h>
#include <nih/macros.h>
#include <nih/alloc.h>
#include <nih/list.h>
#include <nih/string.h>
#include <nih/logging.h>
#include "indent.h"
#include "symbol.h"
#include "type.h"
#include "marshal.h"
/* Prototypes for static functions */
static char *marshal_basic (const void *parent,
DBusSignatureIter *iter,
const char *iter_name, const char *name,
const char *oom_error_code,
NihList *inputs, NihList *locals,
const char *prefix, const char *interface_symbol,
const char *member_symbol, const char *symbol,
NihList *structs)
__attribute__ ((warn_unused_result, malloc));
static char *marshal_array (const void *parent,
DBusSignatureIter *iter,
const char *iter_name, const char *name,
const char *oom_error_code,
NihList *inputs, NihList *locals,
const char *prefix, const char *interface_symbol,
const char *member_symbol, const char *symbol,
NihList *structs)
__attribute__ ((warn_unused_result, malloc));
static char *marshal_struct (const void *parent,
DBusSignatureIter *iter,
const char *iter_name, const char *name,
const char *oom_error_code,
NihList *inputs, NihList *locals,
const char *prefix, const char *interface_symbol,
const char *member_symbol, const char *symbol,
NihList *structs)
__attribute__ ((warn_unused_result, malloc));
/**
* marshal:
* @parent: parent object for new string,
* @signature: signature of type,
* @iter_name: name of iterator variable,
* @name: name of variable,
* @oom_error_code: code to execute on OOM Error,
* @inputs: list to append input variables to,
* @locals: list to append local variables to,
* @prefix: prefix for structure names,
* @interface_symbol: symbol of interface for structure names,
* @member_symbol: symbol of interface member for structure names,
* @symbol: symbol of argument or variable for structure names,
* @structs: list to append structure definitions to.
*
* Generates C code to marshal any D-Bus type from an appropriately typed
* variable named @name into the D-Bus iterator variable named @iter_name.
*
* The type should be the current element of the signature iterator @iter.
* This then simply calls marshal_fixed(), marshal_string(),
* marshal_fixed_array(), marshal_flexible_array() or marshal_struct()
* as appropriate.
*
* The generated code detects out-of-memory conditions but does not know
* how to handle them, therefore you need to pass the appropriate handling
* code in @oom_error_code. This code will be inserted wherever an OOM
* condition is detected.
*
* The expected input variable types and names are given as TypeVar objects
* appended to the @inputs list, each name is guaranteed to begin with @name
* and the first member will always be @name itself. Should the C code
* require local variables, similar TypeVar objects will be appended to
* the @locals list.
*
* If the variable requires a structure to be defined, the definition is
* returned as a TypeStruct object appended to the @structs list. The name
* is generated from @prefix, @interface_symbol, @member_symbol and @symbol.
*
* If @parent is not NULL, it should be a pointer to another object which
* will be used as a parent for the returned string. When all parents
* of the returned string are freed, the returned string will also be
* freed.
*
* Returns: newly allocated string or NULL if insufficient memory.
**/
char *
marshal (const void * parent,
DBusSignatureIter *iter,
const char * iter_name,
const char * name,
const char * oom_error_code,
NihList * inputs,
NihList * locals,
const char * prefix,
const char * interface_symbol,
const char * member_symbol,
const char * symbol,
NihList * structs)
{
int dbus_type;
nih_assert (iter != NULL);
nih_assert (iter_name != NULL);
nih_assert (name != NULL);
nih_assert (oom_error_code != NULL);
nih_assert (inputs != NULL);
nih_assert (locals != NULL);
nih_assert (prefix != NULL);
nih_assert (member_symbol != NULL);
nih_assert (structs != NULL);
dbus_type = dbus_signature_iter_get_current_type (iter);
if (dbus_type_is_basic (dbus_type)) {
return marshal_basic (parent, iter,
iter_name, name,
oom_error_code,
inputs, locals,
prefix, interface_symbol,
member_symbol, symbol,
structs);
} else if (dbus_type == DBUS_TYPE_ARRAY) {
return marshal_array (parent, iter,
iter_name, name,
oom_error_code,
inputs, locals,
prefix, interface_symbol,
member_symbol, symbol,
structs);
} else if ((dbus_type == DBUS_TYPE_STRUCT)
|| (dbus_type == DBUS_TYPE_DICT_ENTRY)) {
return marshal_struct (parent, iter,
iter_name, name,
oom_error_code,
inputs, locals,
prefix, interface_symbol,
member_symbol, symbol,
structs);
} else {
nih_assert_not_reached ();
}
}
/**
* marshal_basic:
* @parent: parent object for new string,
* @iter: D-Bus signature iterator,
* @iter_name: name of iterator variable,
* @name: name of variable,
* @oom_error_code: code to execute on OOM Error,
* @inputs: list to append input variables to,
* @locals: list to append local variables to,
* @interface_symbol: symbol of interface for structure names,
* @member_symbol: symbol of interface member for structure names,
* @symbol: symbol of argument or variable for structure names,
* @structs: list to append structure definitions to.
*
* Generates C code to marshal a D-Bus basic type (ie. numerics and strings)
* from an appropriately typed variable named @name into the D-Bus iterator
* variable named @iter_name.
*
* The type should be the current element of the signature iterator @iter.
*
* The generated code detects out-of-memory conditions but does not know
* how to handle them, therefore you need to pass the appropriate handling
* code in @oom_error_code. This code will be inserted wherever an OOM
* condition is detected.
*
* The expected input variable types and names are given as TypeVar objects
* appended to the @inputs list, each name is guaranteed to begin with @name
* and the first member will always be @name itself. Should the C code
* require local variables, similar TypeVar objects will be appended to
* the @locals list.
*
* If the variable requires a structure to be defined, the definition is
* returned as a TypeStruct object appended to the @structs list. The name
* is generated from @prefix, @interface_symbol, @member_symbol and @symbol.
*
* If @parent is not NULL, it should be a pointer to another object which
* will be used as a parent for the returned string. When all parents
* of the returned string are freed, the returned string will also be
* freed.
*
* Returns: newly allocated string or NULL if insufficient memory.
**/
static char *
marshal_basic (const void * parent,
DBusSignatureIter *iter,
const char * iter_name,
const char * name,
const char * oom_error_code,
NihList * inputs,
NihList * locals,
const char * prefix,
const char * interface_symbol,
const char * member_symbol,
const char * symbol,
NihList * structs)
{
int dbus_type;
const char * dbus_const;
nih_local char *oom_error_block = NULL;
nih_local char *c_type = NULL;
char * code = NULL;
TypeVar * var;
nih_assert (iter != NULL);
nih_assert (iter_name != NULL);
nih_assert (name != NULL);
nih_assert (oom_error_code != NULL);
nih_assert (inputs != NULL);
nih_assert (locals != NULL);
nih_assert (prefix != NULL);
nih_assert (member_symbol != NULL);
nih_assert (structs != NULL);
dbus_type = dbus_signature_iter_get_current_type (iter);
dbus_const = type_const (dbus_type);
oom_error_block = nih_strdup (NULL, oom_error_code);
if (! oom_error_block)
return NULL;
if (! indent (&oom_error_block, NULL, 1))
return NULL;
c_type = type_of (NULL, iter);
if (! c_type)
return NULL;
if (! nih_strcat_sprintf (&code, parent,
"/* Marshal a %s onto the message */\n"
"if (! dbus_message_iter_append_basic (&%s, %s, &%s)) {\n"
"%s"
"}\n",
c_type,
iter_name, dbus_const, name,
oom_error_block))
return NULL;
/* Append our required input variable */
var = type_var_new (code, c_type, name);
if (! var) {
nih_free (code);
return NULL;
}
nih_list_add (inputs, &var->entry);
return code;
}
/**
* marshal_array:
* @parent: parent object for new string,
* @iter: D-Bus signature iterator,
* @iter_name: name of iterator variable,
* @name: name of variable,
* @oom_error_code: code to execute on OOM Error,
* @inputs: list to append input variables to,
* @locals: list to append local variables to,
* @interface_symbol: symbol of interface for structure names,
* @member_symbol: symbol of interface member for structure names,
* @symbol: symbol of argument or variable for structure names,
* @structs: list to append structure definitions to.
*
* Generates C code to marshal a D-Bus array type from an appropriately
* typed, NULL-terminated, array variable named @name into the D-Bus
* iterator variable named @iter_name. In the case of arrays (of any
* number of levels) ultimately to a fixed type, an additional input
* named "@name"_len is required of size_t type or an appropriate number
* of pointers to it.
*
* The type should be the current element of the signature iterator @iter.
*
* The generated code detects out-of-memory conditions but does not know
* how to handle them, therefore you need to pass the appropriate handling
* code in @oom_error_code. This code will be inserted wherever an OOM
* condition is detected.
*
* The expected input variable types and names are given as TypeVar objects
* appended to the @inputs list, each name is guaranteed to begin with @name
* and the first member will always be @name itself. Should the C code
* require local variables, similar TypeVar objects will be appended to
* the @locals list.
*
* If the variable requires a structure to be defined, the definition is
* returned as a TypeStruct object appended to the @structs list. The name
* is generated from @prefix, @interface_symbol, @member_symbol and @symbol.
*
* If @parent is not NULL, it should be a pointer to another object which
* will be used as a parent for the returned string. When all parents
* of the returned string are freed, the returned string will also be
* freed.
*
* Returns: newly allocated string or NULL if insufficient memory.
**/
static char *
marshal_array (const void * parent,
DBusSignatureIter *iter,
const char * iter_name,
const char * name,
const char * oom_error_code,
NihList * inputs,
NihList * locals,
const char * prefix,
const char * interface_symbol,
const char * member_symbol,
const char * symbol,
NihList * structs)
{
nih_local char * array_iter_name = NULL;
nih_local char * loop_name = NULL;
nih_local char * element_name = NULL;
nih_local char * element_symbol = NULL;
nih_local char * len_name = NULL;
nih_local char * oom_error_block = NULL;
nih_local char * child_oom_error_code = NULL;
nih_local char * child_oom_error_block = NULL;
DBusSignatureIter subiter;
int element_type;
char * signature;
char * code = NULL;
TypeVar * array_iter_var;
NihList element_inputs;
NihList element_locals;
NihList element_structs;
nih_local char * element_block = NULL;
nih_local char * element_c_type = NULL;
nih_local TypeVar *element_var = NULL;
nih_local TypeVar *element_len_var = NULL;
nih_local char * block = NULL;
nih_local char * vars_block = NULL;
nih_assert (iter != NULL);
nih_assert (iter_name != NULL);
nih_assert (name != NULL);
nih_assert (oom_error_code != NULL);
nih_assert (inputs != NULL);
nih_assert (locals != NULL);
nih_assert (prefix != NULL);
nih_assert (member_symbol != NULL);
nih_assert (structs != NULL);
array_iter_name = nih_sprintf (NULL, "%s_iter", name);
if (! array_iter_name)
return NULL;
loop_name = nih_sprintf (NULL, "%s_i", name);
if (! loop_name)
return NULL;
element_name = nih_sprintf (NULL, "%s_element", name);
if (! element_name)
return NULL;
element_symbol = (symbol
? nih_sprintf (NULL, "%s_element", symbol)
: nih_strdup (NULL, "element"));
if (! element_symbol)
return NULL;
len_name = nih_sprintf (NULL, "%s_len", name);
if (! len_name)
return NULL;
oom_error_block = nih_strdup (NULL, oom_error_code);
if (! oom_error_block)
return NULL;
if (! indent (&oom_error_block, NULL, 1))
return NULL;
child_oom_error_code = nih_sprintf (NULL, ("dbus_message_iter_abandon_container (&%s, &%s);\n"
"%s"),
iter_name, array_iter_name, oom_error_code);
if (! child_oom_error_code)
return NULL;
child_oom_error_block = nih_strdup (NULL, child_oom_error_code);
if (! child_oom_error_block)
return NULL;
if (! indent (&child_oom_error_block, NULL, 1))
return NULL;
/* Open the array container, we need to give D-Bus the container
* signature to do this and we need a local variable for the
* recursed iterator.
*/
dbus_signature_iter_recurse (iter, &subiter);
element_type = dbus_signature_iter_get_current_type (&subiter);
signature = dbus_signature_iter_get_signature (&subiter);
if (! nih_strcat_sprintf (&code, parent,
"/* Marshal an array onto the message */\n"
"if (! dbus_message_iter_open_container (&%s, DBUS_TYPE_ARRAY, \"%s\", &%s)) {\n"
"%s"
"}\n"
"\n",
iter_name, signature, array_iter_name,
oom_error_block)) {
dbus_free (signature);
return NULL;
}
dbus_free (signature);
array_iter_var = type_var_new (code, "DBusMessageIter",
array_iter_name);
if (! array_iter_var) {
nih_free (code);
return NULL;
}
nih_list_add (locals, &array_iter_var->entry);
if (dbus_type_is_fixed (element_type)) {
if (! nih_strcat_sprintf (&code, parent,
"for (size_t %s = 0; %s < %s; %s++) {\n",
loop_name, loop_name, len_name, loop_name)) {
nih_free (code);
return NULL;
}
} else {
if (! nih_strcat_sprintf (&code, parent,
"for (size_t %s = 0; %s[%s]; %s++) {\n",
loop_name, name, loop_name, loop_name)) {
nih_free (code);
return NULL;
}
}
/* Get the code that will marshal the individual elements, the
* inputs that we need to give and any local variables we have
* to declare.
*/
nih_list_init (&element_inputs);
nih_list_init (&element_locals);
nih_list_init (&element_structs);
element_block = marshal (NULL, &subiter,
array_iter_name, element_name,
child_oom_error_code,
&element_inputs,
&element_locals,
prefix, interface_symbol,
member_symbol, element_symbol,
&element_structs);
if (! element_block) {
nih_free (code);
return NULL;
}
/* Each of the inputs of the marshalling code equates to one of our
* own inputs, except that we add another level of pointers for the
* array; at the same time, we keep the suffix and append it to our
* own name. Instead of mucking around with pointers and structure
* members, we also append the inputs onto the local lists (making it
* const in the process) for the value to be marshalled into this
* variable.
*/
NIH_LIST_FOREACH_SAFE (&element_inputs, iter) {
TypeVar * input_var = (TypeVar *)iter;
nih_local char *var_type = NULL;
char * suffix;
nih_local char *var_name = NULL;
TypeVar * var;
var_type = nih_strdup (NULL, input_var->type);
if (! var_type) {
nih_free (code);
return NULL;
}
if (! type_to_pointer (&var_type, NULL)) {
nih_free (code);
return NULL;
}
nih_assert (! strncmp (input_var->name, element_name,
strlen (element_name)));
suffix = input_var->name + strlen (element_name);
var_name = nih_sprintf (NULL, "%s%s", name, suffix);
if (! var_name) {
nih_free (code);
return NULL;
}
var = type_var_new (code, var_type, var_name);
if (! var) {
nih_free (code);
return NULL;
}
nih_list_add (inputs, &var->entry);
if (! nih_strcat_sprintf (&block, NULL,
"%s = %s[%s];\n",
input_var->name, var_name,
loop_name)) {
nih_free (code);
return NULL;
}
if (! type_to_const (&input_var->type, input_var)) {
nih_free (code);
return NULL;
}
nih_list_add (&element_locals, &input_var->entry);
}
vars_block = type_var_layout (NULL, &element_locals);
if (! vars_block) {
nih_free (code);
return NULL;
}
NIH_LIST_FOREACH_SAFE (&element_structs, iter) {
TypeStruct *structure = (TypeStruct *)iter;
nih_ref (structure, code);
nih_list_add (structs, &structure->entry);
}
/* Lay all that out in an indented block inside the for loop.
* Make sure that we initialise the individual elements from the
* pointer.
*/
if (! indent (&vars_block, NULL, 1)) {
nih_free (code);
return NULL;
}
if (! indent (&block, NULL, 1)) {
nih_free (code);
return NULL;
}
if (! indent (&element_block, NULL, 1)) {
nih_free (code);
return NULL;
}
if (! nih_strcat_sprintf (&code, parent,
"%s"
"\n"
"%s"
"\n"
"%s",
vars_block,
block,
element_block)) {
nih_free (code);
return NULL;
}
/* Close the container again */
if (! nih_strcat_sprintf (&code, parent,
"}\n"
"\n"
"if (! dbus_message_iter_close_container (&%s, &%s)) {\n"
"%s"
"}\n",
iter_name, array_iter_name,
oom_error_block)) {
nih_free (code);
return NULL;
}
/* When iterating a fixed type, we get an extra length input */
if (dbus_type_is_fixed (element_type)) {
TypeVar *var;
var = type_var_new (code, "size_t", len_name);
if (! var) {
nih_free (code);
return NULL;
}
nih_list_add (inputs, &var->entry);
}
return code;
}
/**
* marshal_struct:
* @parent: parent object for new string,
* @iter: D-Bus signature iterator,
* @iter_name: name of iterator variable,
* @name: name of variable,
* @oom_error_code: code to execute on OOM Error,
* @inputs: list to append input variables to,
* @locals: list to append local variables to,
* @interface_symbol: symbol of interface for structure names,
* @member_symbol: symbol of interface member for structure names,
* @symbol: symbol of argument or variable for structure names,
* @structs: list to append structure definitions to.
*
* Generates C code to marshal a D-Bus structure type, and its members,
* from an appropriately typed variable named @name into the D-Bus iterator
* variable named @iter_name.
*
* The type should be the current element of the signature iterator @iter.
*
* The generated code detects out-of-memory conditions but does not know
* how to handle them, therefore you need to pass the appropriate handling
* code in @oom_error_code. This code will be inserted wherever an OOM
* condition is detected.
*
* The expected input variable types and names are given as TypeVar objects
* appended to the @inputs list, each name is guaranteed to begin with @name
* and the first member will always be @name itself. Should the C code
* require local variables, similar TypeVar objects will be appended to
* the @locals list.
*
* If the variable requires a structure to be defined, the definition is
* returned as a TypeStruct object appended to the @structs list. The name
* is generated from @prefix, @interface_symbol, @member_symbol and @symbol.
*
* If @parent is not NULL, it should be a pointer to another object which
* will be used as a parent for the returned string. When all parents
* of the returned string are freed, the returned string will also be
* freed.
*
* Returns: newly allocated string or NULL if insufficient memory.
**/
static char *
marshal_struct (const void * parent,
DBusSignatureIter *iter,
const char * iter_name,
const char * name,
const char * oom_error_code,
NihList * inputs,
NihList * locals,
const char * prefix,
const char * interface_symbol,
const char * member_symbol,
const char * symbol,
NihList * structs)
{
int dbus_type;
const char * dbus_const;
nih_local char * struct_iter_name = NULL;
nih_local char * oom_error_block = NULL;
nih_local char * child_oom_error_code = NULL;
nih_local char * child_oom_error_block = NULL;
nih_local char * c_type = NULL;
TypeStruct * structure;
DBusSignatureIter subiter;
char * code = NULL;
TypeVar * struct_iter_var;
size_t count = 0;
TypeVar * var;
nih_assert (iter != NULL);
nih_assert (iter_name != NULL);
nih_assert (name != NULL);
nih_assert (oom_error_code != NULL);
nih_assert (inputs != NULL);
nih_assert (locals != NULL);
nih_assert (prefix != NULL);
nih_assert (member_symbol != NULL);
nih_assert (structs != NULL);
dbus_type = dbus_signature_iter_get_current_type (iter);
dbus_const = type_const (dbus_type);
struct_iter_name = nih_sprintf (NULL, "%s_iter", name);
if (! struct_iter_name)
return NULL;
oom_error_block = nih_strdup (NULL, oom_error_code);
if (! oom_error_block)
return NULL;
if (! indent (&oom_error_block, NULL, 1))
return NULL;
child_oom_error_code = nih_sprintf (NULL, ("dbus_message_iter_abandon_container (&%s, &%s);\n"
"%s"),
iter_name, struct_iter_name, oom_error_code);
if (! child_oom_error_code)
return NULL;
child_oom_error_block = nih_strdup (NULL, child_oom_error_code);
if (! child_oom_error_block)
return NULL;
if (! indent (&child_oom_error_block, NULL, 1))
return NULL;
/* Open the struct container, for that we need to know whether this
* is a struct or a dictionary entry even though we handle the two
* identically. We'll obviously need a local variable for the
* recursed iterator.
*/
dbus_signature_iter_recurse (iter, &subiter);
if (! nih_strcat_sprintf (&code, parent,
"/* Marshal a structure onto the message */\n"
"if (! dbus_message_iter_open_container (&%s, %s, NULL, &%s)) {\n"
"%s"
"}\n"
"\n",
iter_name, dbus_const, struct_iter_name,
oom_error_block))
return NULL;
struct_iter_var = type_var_new (code, "DBusMessageIter",
struct_iter_name);
if (! struct_iter_var) {
nih_free (code);
return NULL;
}
nih_list_add (locals, &struct_iter_var->entry);
/* FIXME there should be a way to override this to a different type
* name by annotation.
*/
c_type = symbol_typedef (NULL, prefix, interface_symbol, NULL,
member_symbol, symbol);
if (! c_type) {
nih_free (code);
return NULL;
}
structure = type_struct_new (code, c_type);
if (! structure) {
nih_free (code);
return NULL;
}
nih_list_add (structs, &structure->entry);
if (! type_to_pointer (&c_type, NULL)) {
nih_free (code);
return NULL;
}
/* Deal with each structure element individually, however we have
* to end up with just one set of locals and one block so we
* append directly onto our locals.
*/
do {
nih_local char *item_member = NULL;
nih_local char *item_name = NULL;
nih_local char *item_symbol = NULL;
NihList item_inputs;
NihList item_locals;
NihList item_structs;
nih_local char *item_code = NULL;
/* FIXME there should be a way to override the item names
* via an annotation, which would also show up in the
* structure definition itself.
*/
item_member = nih_sprintf (NULL, "item%zu", count);
if (! item_member) {
nih_free (code);
return NULL;
}
item_name = nih_sprintf (NULL, "%s_%s", name, item_member);
if (! item_name) {
nih_free (code);
return NULL;
}
item_symbol = (symbol
? nih_sprintf (NULL, "%s_%s", symbol, item_member)
: nih_strdup (NULL, item_member));
if (! item_symbol) {
nih_free (code);
return NULL;
}
/* Get the code to do the marshalling of this item */
nih_list_init (&item_inputs);
nih_list_init (&item_locals);
nih_list_init (&item_structs);
item_code = marshal (NULL, &subiter,
struct_iter_name, item_name,
child_oom_error_code,
&item_inputs,
&item_locals,
prefix, interface_symbol,
member_symbol, item_symbol,
structs);
if (! item_code) {
nih_free (code);
return NULL;
}
/* Append the item locals onto our locals list, we have
* to reference these as we go.
*/
NIH_LIST_FOREACH_SAFE (&item_locals, iter) {
TypeVar *local_var = (TypeVar *)iter;
nih_list_add (locals, &local_var->entry);
nih_ref (local_var, code);
}
/* Instead of mucking around with pointers and structure
* members, each of the marshalling code inputs is appended
* onto the local list (and made const) and we copy the
* value from the array into this variable.
*/
NIH_LIST_FOREACH_SAFE (&item_inputs, iter) {
TypeVar * input_var = (TypeVar *)iter;
char * suffix;
nih_local char *member_name = NULL;
TypeVar * member_var;
nih_assert (! strncmp (input_var->name, item_name,
strlen (item_name)));
suffix = input_var->name + strlen (item_name);
/* Create the structure member entry */
member_name = nih_sprintf (NULL, "%s%s",
item_member, suffix);
if (! member_name) {
nih_free (code);
return NULL;
}
member_var = type_var_new (structure,
input_var->type,
member_name);
if (! member_var) {
nih_free (code);
return NULL;
}
nih_list_add (&structure->members, &member_var->entry);
/* Add code to copy into local variable */
if (! nih_strcat_sprintf (&code, parent,
"%s = %s->%s;\n",
input_var->name, name,
member_name)) {
nih_free (code);
return NULL;
}
/* Make the input variable const and add to locals */
if (! type_to_const (&input_var->type, input_var)) {
nih_free (code);
return NULL;
}
nih_list_add (locals, &input_var->entry);
nih_ref (input_var, code);
}
NIH_LIST_FOREACH_SAFE (&item_structs, iter) {
TypeStruct *structure = (TypeStruct *)iter;
nih_ref (structure, code);
nih_list_add (structs, &structure->entry);
}
/* Append item marshalling code block */
if (! nih_strcat_sprintf (&code, parent,
"\n"
"%s"
"\n",
item_code)) {
nih_free (code);
return NULL;
}
nih_assert (++count > 0);
} while (dbus_signature_iter_next (&subiter));
/* Close the container again */
if (! nih_strcat_sprintf (&code, parent,
"if (! dbus_message_iter_close_container (&%s, &%s)) {\n"
"%s"
"}\n",
iter_name, struct_iter_name,
oom_error_block)) {
nih_free (code);
return NULL;
}
/* Append our required input variable */
var = type_var_new (code, c_type, name);
if (! var) {
nih_free (code);
return NULL;
}
nih_list_add (inputs, &var->entry);
return code;
}