blob: 2d1bf18598f047c2a1999aebc36e4cf0f85a481e [file] [log] [blame]
/* nih-dbus-tool
*
* node.c - top-level object parsing and handling
*
* 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 <expat.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 <nih/error.h>
#include "symbol.h"
#include "indent.h"
#include "type.h"
#include "node.h"
#include "interface.h"
#include "parse.h"
#include "errors.h"
/**
* node_path_valid:
* @path: Object path to verify.
*
* Verifies whether @path matches the specification for D-Bus object paths.
*
* Returns: TRUE if valid, FALSE if not.
**/
int
node_path_valid (const char *path)
{
nih_assert (path != NULL);
/* Path must begin with a '/' character */
if (path[0] != '/')
return FALSE;
/* We can get away with just using strlen() here even through path
* is in UTF-8 because all the valid characters are ASCII.
*/
for (size_t i = 1; i < strlen (path); i++) {
/* Path components may be separated by single '/' characters,
* multiple ones are not allowed.
*/
if (path[i] == '/') {
if (path[i-1] == '/')
return FALSE;
continue;
}
/* Valid characters are [A-Za-z0-9_] */
if ( ((path[i] < 'A') || (path[i] > 'Z'))
&& ((path[i] < 'a') || (path[i] > 'z'))
&& ((path[i] < '0') || (path[i] > '9'))
&& (path[i] != '_'))
return FALSE;
}
/* Final character may not be '/' unless it's the root object. */
if ((strlen (path) > 1) && (path[strlen (path) - 1] == '/'))
return FALSE;
return TRUE;
}
/**
* node_new:
* @parent: parent object for new node,
* @path: D-Bus path of node.
*
* Allocates a new D-Bus object Node data structure, with the path optionally
* set to @path.
*
* If @parent is not NULL, it should be a pointer to another object which
* will be used as a parent for the returned node. When all parents
* of the returned node are freed, the returned node will also be
* freed.
*
* Returns: the new node or NULL if the allocation failed.
**/
Node *
node_new (const void *parent,
const char *path)
{
Node *node;
node = nih_new (parent, Node);
if (! node)
return NULL;
if (path) {
node->path = nih_strdup (node, path);
if (! node->path) {
nih_free (node);
return NULL;
}
} else {
node->path = NULL;
}
nih_list_init (&node->interfaces);
return node;
}
/**
* node_start_tag:
* @xmlp: XML parser,
* @tag: name of XML tag being parsed,
* @attr: NULL-terminated array of attribute name and value pairs.
*
* This function is called by parse_start_tag() for a "node" start
* tag, the top-level of the introspection data and defining a D-Bus
* object.
*
* If the node does not appear at the top-level a warning is emitted
* (unless directly inside another node tag) and the tag will be ignored.
*
* Nodes may have a "name" attribute containing the D-Bus object path
* of the node.
*
* Any unknown attributes result in a warning and will be ignored.
*
* A Node object will be allocated and pushed onto the stack, this is not
* saved into the context until the end tag is found.
*
* Returns: zero on success, negative value on raised error.
**/
int
node_start_tag (XML_Parser xmlp,
const char * tag,
char * const *attr)
{
ParseContext * context;
ParseStack * parent;
nih_local Node *node = NULL;
char * const * key;
char * const * value;
const char * name = NULL;
nih_assert (xmlp != NULL);
nih_assert (tag != NULL);
nih_assert (attr != NULL);
context = XML_GetUserData (xmlp);
nih_assert (context != NULL);
/* Nodes should only appear at the top-level, unless they're within
* another node in which case we just ignore them.
*/
parent = parse_stack_top (&context->stack);
if (parent) {
if (parent->type != PARSE_NODE) {
nih_warn ("%s:%zu:%zu: %s", context->filename,
(size_t)XML_GetCurrentLineNumber (xmlp),
(size_t)XML_GetCurrentColumnNumber (xmlp),
_("Ignored unexpected <node> tag"));
}
if (! parse_stack_push (NULL, &context->stack,
PARSE_IGNORED, NULL))
nih_return_system_error (-1);
return 0;
}
/* Retrieve the name from the attributes */
for (key = attr; key && *key; key += 2) {
value = key + 1;
nih_assert (value && *value);
if (! strcmp (*key, "name")) {
name = *value;
} else {
nih_warn ("%s:%zu:%zu: %s: %s", context->filename,
(size_t)XML_GetCurrentLineNumber (xmlp),
(size_t)XML_GetCurrentColumnNumber (xmlp),
_("Ignored unknown <node> attribute"),
*key);
}
}
/* If we have a name check that it's valid */
if (name && (! node_path_valid (name)))
nih_return_error (-1, NODE_INVALID_PATH,
_(NODE_INVALID_PATH_STR));
/* Allocate a Node object and push onto the stack */
node = node_new (NULL, name);
if (! node)
nih_return_system_error (-1);
if (! parse_stack_push (NULL, &context->stack, PARSE_NODE, node)) {
nih_error_raise_system ();
return -1;
}
return 0;
}
/**
* node_end_tag:
* @xmlp: XML parser,
* @tag: name of XML tag being parsed.
*
* This function is called by parse_end_tag() for a "node" end
* tag, and matches a call to node_start_tag() made at the same parsing
* level.
*
* The node is set in the context so it can be returned once the parser
* completes.
*
* Returns: zero on success, negative value on raised error.
**/
int
node_end_tag (XML_Parser xmlp,
const char *tag)
{
ParseContext *context;
ParseStack * entry;
nih_assert (xmlp != NULL);
nih_assert (tag != NULL);
context = XML_GetUserData (xmlp);
nih_assert (context != NULL);
entry = parse_stack_top (&context->stack);
nih_assert (entry != NULL);
nih_assert (entry->type == PARSE_NODE);
nih_debug ("Set parsed node to %s", entry->node->path ?: "(unknown)");
nih_assert (context->node == NULL);
context->node = entry->node;
nih_ref (entry->node, context->parent);
nih_unref (entry->node, entry);
nih_free (entry);
return 0;
}
/**
* node_lookup_interface:
* @node: node to search,
* @symbol: interface symbol to find.
*
* Finds an interface in @node's interfaces list which has the generated
* or supplied C symbol @symbol. If @symbol is NULL, the default interface
* will be returned.
*
* Returns: interface found or NULL if no interface matches.
**/
Interface *
node_lookup_interface (Node * node,
const char *symbol)
{
nih_assert (node != NULL);
NIH_LIST_FOREACH (&node->interfaces, iter) {
Interface *interface = (Interface *)iter;
if ((interface->symbol && symbol
&& (! strcmp (interface->symbol, symbol)))
|| ((! interface->symbol) && (! symbol)))
return interface;
}
return NULL;
}
/**
* node_interfaces_array:
* @parent: parent object for new string,
* @prefix: prefix for array name,
* @node: node to generate array for,
* @object: whether array is for an object or proxy,
* @prototypes: list to append prototypes to.
*
* Generates C code to declare an array of NihDBusInterface pointers for
* the node @node, the code includes each of the NihDBusInterface structure
* definitions individually as well as the array definitions for methods,
* signals, properties and their arguments in them.
*
* If @object is TRUE, the array will be for an object definition so method
* handler function and property getter and setter function pointers will
* be filled in. If @object is FALSE, the array will be for a proxy
* definition so the signal filter function pointers will be filled in.
*
* The prototype of the returned variable declaration, and the prototypes
* of the interface structures, are returned as TypeVar objects appended
* to the @prototypes list.
*
* 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 return string will also be
* freed.
*
* Returns: newly allocated string or NULL if insufficient memory.
**/
char *
node_interfaces_array (const void *parent,
const char *prefix,
Node * node,
int object,
NihList * prototypes)
{
nih_local char *name = NULL;
nih_local char *block = NULL;
char * code = NULL;
TypeVar * var;
nih_assert (prefix != NULL);
nih_assert (node != NULL);
nih_assert (prototypes != NULL);
name = symbol_extern (NULL, prefix, NULL, NULL, "interfaces", NULL);
if (! name)
return NULL;
/* Append the address of each of the interface structures to the
* block we build, and the code to the interfaces list.
*/
NIH_LIST_FOREACH (&node->interfaces, iter) {
Interface * interface = (Interface *)iter;
NihList struct_prototypes;
nih_local char *struct_code = NULL;
nih_list_init (&struct_prototypes);
struct_code = interface_struct (NULL, prefix, interface,
object, &struct_prototypes);
if (! struct_code) {
if (code)
nih_free (code);
return NULL;
}
nih_assert (! NIH_LIST_EMPTY (&struct_prototypes));
var = (TypeVar *)struct_prototypes.next;
if (! nih_strcat_sprintf (&code, parent,
"%s\n", struct_code)) {
if (code)
nih_free (code);
return NULL;
}
if (! nih_strcat_sprintf (&block, NULL,
"&%s,\n", var->name)) {
if (code)
nih_free (code);
return NULL;
}
/* Copy the prototypes to the list we return, since we
* want to export those as well.
*/
NIH_LIST_FOREACH_SAFE (&struct_prototypes, iter) {
var = (TypeVar *)iter;
if (! type_to_extern (&var->type, var)) {
if (code)
nih_free (code);
return NULL;
}
nih_ref (var, code);
nih_list_add (prototypes, &var->entry);
}
}
/* Append the final element to the block of elements, indent and
* surround with the structure definition.
*/
if (! nih_strcat (&block, NULL, "NULL\n")) {
if (code)
nih_free (code);
return NULL;
}
if (! indent (&block, NULL, 1)) {
if (code)
nih_free (code);
return NULL;
}
if (! nih_strcat_sprintf (&code, parent,
"const NihDBusInterface *%s[] = {\n"
"%s"
"};\n",
name,
block)) {
if (code)
nih_free (code);
return NULL;
}
/* Append the prototype to the list */
var = type_var_new (code, "const NihDBusInterface *", name);
if (! var) {
nih_free (code);
return NULL;
}
var->array = TRUE;
if (! type_to_extern (&var->type, var)) {
if (code)
nih_free (code);
return NULL;
}
nih_list_add (prototypes, &var->entry);
return code;
}
/**
* node_object_functions:
* @parent: parent object for new string,
* @prefix: prefix for function names,
* @node: node to generate functions for,
* @prototypes: list to append prototypes to,
* @handlers: list to append handler prototypes to,
* @structs: list to append structure definitions to,
* @externs: list to append prototypes of extern functions to.
*
* Generates C code for all of the functions that @node would require to
* wrap existing C functions and implement the D-Bus interfaces described
* for the object.
*
* Functions in the returned code to implement method handlers and property
* getter and setters will be declared static and their prototypes returned
* as TypeFunc objects appended to the @prototypes list. You normally ensure
* that these receive a forward declaration.
*
* Those functions will call implementation functions that other code is
* expected to provide, the names and prototypes of these expected functions
* are returned as TypeFunc objects appended to the @handlers list. You
* must implement these elsewhere, and ensure that the prototype has a
* forward declaration.
*
* Functions in the returned code to implement signal emissions are part of
* a public API that your own code may call. The names and prototypes are
* returned as TypeFunc objects appended to the @externs list, you would
* normally place these in a header file.
*
* If any of the function arguments require 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 and the method,
* signal or property the function is for.
*
* 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 return string will also be
* freed.
*
* Returns: newly allocated string or NULL if insufficient memory.
**/
char *
node_object_functions (const void *parent,
const char *prefix,
Node * node,
NihList * prototypes,
NihList * handlers,
NihList * structs,
NihList * externs)
{
char *code = NULL;
int first = TRUE;
nih_assert (prefix != NULL);
nih_assert (node != NULL);
nih_assert (prototypes != NULL);
nih_assert (handlers != NULL);
nih_assert (structs != NULL);
nih_assert (externs != NULL);
code = nih_strdup (parent, "");
if (! code)
return NULL;
NIH_LIST_FOREACH (&node->interfaces, interface_iter) {
Interface *interface = (Interface *)interface_iter;
NIH_LIST_FOREACH (&interface->methods, method_iter) {
Method * method = (Method *)method_iter;
NihList method_prototypes;
NihList method_handlers;
NihList method_structs;
NihList method_externs;
nih_local char *object_func = NULL;
nih_local char *reply_func = NULL;
nih_list_init (&method_prototypes);
nih_list_init (&method_handlers);
nih_list_init (&method_structs);
nih_list_init (&method_externs);
if (! first)
if (! nih_strcat (&code, parent, "\n\n"))
goto error;
first = FALSE;
object_func = method_object_function (
NULL, prefix, interface, method,
&method_prototypes, &method_handlers,
&method_structs);
if (! object_func)
goto error;
if (! nih_strcat_sprintf (&code, parent,
"static %s",
object_func))
goto error;
if (method->async) {
reply_func = method_reply_function (
NULL, prefix, interface, method,
&method_externs, &method_structs);
if (! reply_func)
goto error;
if (! nih_strcat_sprintf (&code, parent,
"\n"
"%s",
reply_func))
goto error;
}
NIH_LIST_FOREACH_SAFE (&method_prototypes, iter) {
TypeFunc *func = (TypeFunc *)iter;
if (! type_to_static (&func->type, func))
goto error;
nih_ref (func, code);
nih_list_add (prototypes, &func->entry);
}
NIH_LIST_FOREACH_SAFE (&method_handlers, iter) {
TypeFunc *func = (TypeFunc *)iter;
if (! type_to_extern (&func->type, func))
goto error;
nih_ref (func, code);
nih_list_add (handlers, &func->entry);
}
NIH_LIST_FOREACH_SAFE (&method_structs, iter) {
TypeStruct *structure = (TypeStruct *)iter;
nih_ref (structure, code);
nih_list_add (structs, &structure->entry);
}
NIH_LIST_FOREACH_SAFE (&method_externs, iter) {
TypeFunc *func = (TypeFunc *)iter;
nih_ref (func, code);
nih_list_add (externs, &func->entry);
}
}
NIH_LIST_FOREACH (&interface->signals, signal_iter) {
Signal * signal = (Signal *)signal_iter;
NihList signal_structs;
NihList signal_externs;
nih_local char *object_func = NULL;
nih_list_init (&signal_structs);
nih_list_init (&signal_externs);
object_func = signal_object_function (
NULL, prefix, interface, signal,
&signal_externs, &signal_structs);
if (! object_func)
goto error;
if (! first)
if (! nih_strcat (&code, parent, "\n\n"))
goto error;
first = FALSE;
if (! nih_strcat (&code, parent, object_func))
goto error;
NIH_LIST_FOREACH_SAFE (&signal_structs, iter) {
TypeStruct *structure = (TypeStruct *)iter;
nih_ref (structure, code);
nih_list_add (structs, &structure->entry);
}
NIH_LIST_FOREACH_SAFE (&signal_externs, iter) {
TypeFunc *func = (TypeFunc *)iter;
nih_ref (func, code);
nih_list_add (externs, &func->entry);
}
}
NIH_LIST_FOREACH (&interface->properties, property_iter) {
Property * property = (Property *)property_iter;
NihList property_prototypes;
NihList property_handlers;
NihList property_structs;
nih_local char *get_func = NULL;
nih_local char *set_func = NULL;
nih_list_init (&property_prototypes);
nih_list_init (&property_handlers);
nih_list_init (&property_structs);
if (! first)
if (! nih_strcat (&code, parent, "\n\n"))
goto error;
first = FALSE;
if (property->access != NIH_DBUS_WRITE) {
get_func = property_object_get_function (
NULL, prefix, interface, property,
&property_prototypes, &property_handlers,
&property_structs);
if (! get_func)
goto error;
if (! nih_strcat_sprintf (&code, parent,
"static %s",
get_func))
goto error;
}
if (property->access == NIH_DBUS_READWRITE) {
if (! nih_strcat (&code, parent, "\n"))
goto error;
/* Don't duplicate structures; these will
* get freed automatically.
*/
nih_list_init (&property_structs);
}
if (property->access != NIH_DBUS_READ) {
set_func = property_object_set_function (
NULL, prefix, interface, property,
&property_prototypes, &property_handlers,
&property_structs);
if (! set_func)
goto error;
if (! nih_strcat_sprintf (&code, parent,
"static %s",
set_func))
goto error;
}
NIH_LIST_FOREACH_SAFE (&property_prototypes, iter) {
TypeFunc *func = (TypeFunc *)iter;
if (! type_to_static (&func->type, func))
goto error;
nih_ref (func, code);
nih_list_add (prototypes, &func->entry);
}
NIH_LIST_FOREACH_SAFE (&property_handlers, iter) {
TypeFunc *func = (TypeFunc *)iter;
if (! type_to_extern (&func->type, func))
goto error;
nih_ref (func, code);
nih_list_add (handlers, &func->entry);
}
NIH_LIST_FOREACH_SAFE (&property_structs, iter) {
TypeStruct *structure = (TypeStruct *)iter;
nih_ref (structure, code);
nih_list_add (structs, &structure->entry);
}
}
}
return code;
error:
nih_free (code);
return NULL;
}
/**
* node_proxy_functions:
* @parent: parent object for new string,
* @prefix: prefix for function names,
* @node: node to generate functions for,
* @prototypes: list to append prototypes to,
* @structs: list to append structure definitions to,
* @typedefs: list to append callback typedefs to,
* @externs: list to append prototypes of extern functions to.
*
* Generates C code for all of the functions that @node would require to
* provide remote object access.
*
* Functions in the returned code to implement signal filter functions
* will be declared static and their prototypes returned as TypeFunc objects
* appended to the @prototypes list. You normally ensure that these receive
* a forward declaration.
*
* Functions in the returned code to implement method and property get/set
* proxy functions are part of a public API that your own code may call.
* The names and prototypes are returned as TypeFunc objects appended to
* the @externs list, you would normally place these in a header file.
*
* Both sets of these functions will call handler and callback functions
* that other code is expected to provide, either passed directly to the
* function (for method and proxy functions) or passed to
* nih_dbus_proxy_connect() (for signal functions). The typedef for those
* functions are returned as TypeFunc objects appended to the @typedefs list.
* You would normally place these in a header file.
*
* If any of the function arguments require 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 and the method,
* signal or property the function is for.
*
* 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 return string will also be
* freed.
*
* Returns: newly allocated string or NULL if insufficient memory.
**/
char *
node_proxy_functions (const void *parent,
const char *prefix,
Node * node,
NihList * prototypes,
NihList * structs,
NihList * typedefs,
NihList * externs)
{
char *code = NULL;
int first = TRUE;
nih_assert (prefix != NULL);
nih_assert (node != NULL);
nih_assert (prototypes != NULL);
nih_assert (structs != NULL);
nih_assert (typedefs != NULL);
nih_assert (externs != NULL);
code = nih_strdup (parent, "");
if (! code)
return NULL;
NIH_LIST_FOREACH (&node->interfaces, interface_iter) {
Interface *interface = (Interface *)interface_iter;
NihList discard;
nih_list_init (&discard);
NIH_LIST_FOREACH (&interface->methods, method_iter) {
Method * method = (Method *)method_iter;
NihList method_prototypes;
NihList method_structs;
NihList method_typedefs;
NihList method_externs;
nih_local char *proxy_func = NULL;
nih_local char *notify_func = NULL;
nih_local char *sync_func = NULL;
nih_list_init (&method_prototypes);
nih_list_init (&method_structs);
nih_list_init (&method_typedefs);
nih_list_init (&method_externs);
if (! first)
if (! nih_strcat (&code, parent, "\n\n"))
goto error;
first = FALSE;
proxy_func = method_proxy_function (
NULL, prefix, interface, method,
&method_externs, &discard);
if (! proxy_func)
goto error;
notify_func = method_proxy_notify_function (
NULL, prefix, interface, method,
&method_prototypes, &method_typedefs,
&discard);
if (! notify_func)
goto error;
sync_func = method_proxy_sync_function (
NULL, prefix, interface, method,
&method_externs, &method_structs);
if (! sync_func)
goto error;
if (! nih_strcat_sprintf (&code, parent,
"%s"
"\n"
"static %s"
"\n"
"%s",
proxy_func,
notify_func,
sync_func))
goto error;
NIH_LIST_FOREACH_SAFE (&method_prototypes, iter) {
TypeFunc *func = (TypeFunc *)iter;
if (! type_to_static (&func->type, func))
goto error;
nih_ref (func, code);
nih_list_add (prototypes, &func->entry);
}
NIH_LIST_FOREACH_SAFE (&method_structs, iter) {
TypeStruct *structure = (TypeStruct *)iter;
nih_ref (structure, code);
nih_list_add (structs, &structure->entry);
}
NIH_LIST_FOREACH_SAFE (&method_typedefs, iter) {
TypeFunc *func = (TypeFunc *)iter;
nih_ref (func, code);
nih_list_add (typedefs, &func->entry);
}
NIH_LIST_FOREACH_SAFE (&method_externs, iter) {
TypeFunc *func = (TypeFunc *)iter;
nih_ref (func, code);
nih_list_add (externs, &func->entry);
}
}
NIH_LIST_FOREACH (&interface->signals, signal_iter) {
Signal * signal = (Signal *)signal_iter;
NihList signal_prototypes;
NihList signal_structs;
NihList signal_typedefs;
nih_local char *proxy_func = NULL;
nih_list_init (&signal_prototypes);
nih_list_init (&signal_structs);
nih_list_init (&signal_typedefs);
if (! first)
if (! nih_strcat (&code, parent, "\n\n"))
goto error;
first = FALSE;
proxy_func = signal_proxy_function (
NULL, prefix, interface, signal,
&signal_prototypes, &signal_typedefs,
&signal_structs);
if (! proxy_func)
goto error;
if (! nih_strcat_sprintf (&code, parent,
"static %s",
proxy_func))
goto error;
NIH_LIST_FOREACH_SAFE (&signal_prototypes, iter) {
TypeFunc *func = (TypeFunc *)iter;
if (! type_to_static (&func->type, func))
goto error;
nih_ref (func, code);
nih_list_add (prototypes, &func->entry);
}
NIH_LIST_FOREACH_SAFE (&signal_structs, iter) {
TypeStruct *structure = (TypeStruct *)iter;
nih_ref (structure, code);
nih_list_add (structs, &structure->entry);
}
NIH_LIST_FOREACH_SAFE (&signal_typedefs, iter) {
TypeFunc *func = (TypeFunc *)iter;
nih_ref (func, code);
nih_list_add (typedefs, &func->entry);
}
}
NIH_LIST_FOREACH (&interface->properties, property_iter) {
Property * property = (Property *)property_iter;
NihList property_prototypes;
NihList property_structs;
NihList property_typedefs;
NihList property_externs;
nih_local char *get_func = NULL;
nih_local char *get_notify_func = NULL;
nih_local char *get_sync_func = NULL;
nih_local char *set_func = NULL;
nih_local char *set_notify_func = NULL;
nih_local char *set_sync_func = NULL;
nih_list_init (&property_prototypes);
nih_list_init (&property_structs);
nih_list_init (&property_typedefs);
nih_list_init (&property_externs);
if (! first)
if (! nih_strcat (&code, parent, "\n\n"))
goto error;
first = FALSE;
if (property->access != NIH_DBUS_WRITE) {
get_func = property_proxy_get_function (
NULL, prefix, interface, property,
&property_externs, &discard);
if (! get_func)
goto error;
get_notify_func = property_proxy_get_notify_function (
NULL, prefix, interface, property,
&property_prototypes, &property_typedefs,
&discard);
if (! get_notify_func)
goto error;
get_sync_func = property_proxy_get_sync_function (
NULL, prefix, interface, property,
&property_externs, &discard);
if (! get_sync_func)
goto error;
if (! nih_strcat_sprintf (&code, parent,
"%s"
"\n"
"static %s"
"\n"
"%s",
get_func,
get_notify_func,
get_sync_func))
goto error;
}
if (property->access == NIH_DBUS_READWRITE)
if (! nih_strcat (&code, parent, "\n"))
goto error;
if (property->access != NIH_DBUS_READ) {
set_func = property_proxy_set_function (
NULL, prefix, interface, property,
&property_externs, &discard);
if (! set_func)
goto error;
set_notify_func = property_proxy_set_notify_function (
NULL, prefix, interface, property,
&property_prototypes, &property_typedefs,
&discard);
if (! set_notify_func)
goto error;
set_sync_func = property_proxy_set_sync_function (
NULL, prefix, interface, property,
&property_externs,
(property->access == NIH_DBUS_WRITE
? &property_structs
: &discard));
if (! set_sync_func)
goto error;
if (! nih_strcat_sprintf (&code, parent,
"%s"
"\n"
"static %s"
"\n"
"%s",
set_func,
set_notify_func,
set_sync_func))
goto error;
}
NIH_LIST_FOREACH_SAFE (&property_prototypes, iter) {
TypeFunc *func = (TypeFunc *)iter;
if (! type_to_static (&func->type, func))
goto error;
nih_ref (func, code);
nih_list_add (prototypes, &func->entry);
}
NIH_LIST_FOREACH_SAFE (&property_structs, iter) {
TypeStruct *structure = (TypeStruct *)iter;
nih_ref (structure, code);
nih_list_add (structs, &structure->entry);
}
NIH_LIST_FOREACH_SAFE (&property_typedefs, iter) {
TypeFunc *func = (TypeFunc *)iter;
nih_ref (func, code);
nih_list_add (typedefs, &func->entry);
}
NIH_LIST_FOREACH_SAFE (&property_externs, iter) {
TypeFunc *func = (TypeFunc *)iter;
nih_ref (func, code);
nih_list_add (externs, &func->entry);
}
}
/* Functions to obtain all of the properties */
if (! NIH_LIST_EMPTY (&interface->properties)) {
NihList all_prototypes;
NihList all_structs;
NihList all_typedefs;
NihList all_externs;
nih_local char *get_all_func = NULL;
nih_local char *get_all_notify_func = NULL;
nih_local char *get_all_sync_func = NULL;
nih_list_init (&all_prototypes);
nih_list_init (&all_structs);
nih_list_init (&all_typedefs);
nih_list_init (&all_externs);
if (! first)
if (! nih_strcat (&code, parent, "\n\n"))
goto error;
first = FALSE;
get_all_func = interface_proxy_get_all_function (
NULL, prefix, interface,
&all_externs, &discard);
if (! get_all_func)
goto error;
get_all_notify_func = interface_proxy_get_all_notify_function (
NULL, prefix, interface,
&all_prototypes, &all_typedefs,
&discard);
if (! get_all_notify_func)
goto error;
get_all_sync_func = interface_proxy_get_all_sync_function (
NULL, prefix, interface,
&all_externs, &all_structs);
if (! get_all_sync_func)
goto error;
if (! nih_strcat_sprintf (&code, parent,
"%s"
"\n"
"static %s"
"\n"
"%s",
get_all_func,
get_all_notify_func,
get_all_sync_func))
goto error;
NIH_LIST_FOREACH_SAFE (&all_prototypes, iter) {
TypeFunc *func = (TypeFunc *)iter;
if (! type_to_static (&func->type, func))
goto error;
nih_ref (func, code);
nih_list_add (prototypes, &func->entry);
}
NIH_LIST_FOREACH_SAFE (&all_structs, iter) {
TypeStruct *structure = (TypeStruct *)iter;
nih_ref (structure, code);
nih_list_add (structs, &structure->entry);
}
NIH_LIST_FOREACH_SAFE (&all_typedefs, iter) {
TypeFunc *func = (TypeFunc *)iter;
nih_ref (func, code);
nih_list_add (typedefs, &func->entry);
}
NIH_LIST_FOREACH_SAFE (&all_externs, iter) {
TypeFunc *func = (TypeFunc *)iter;
nih_ref (func, code);
nih_list_add (externs, &func->entry);
}
}
}
return code;
error:
nih_free (code);
return NULL;
}