diff --git a/daemon/dict.c b/daemon/dict.c index 5ea19889..99114229 100644 --- a/daemon/dict.c +++ b/daemon/dict.c @@ -191,4 +191,9 @@ bool ladish_dict_iterate(ladish_dict_handle dict_handle, void * context, bool (* return true; } +bool ladish_dict_is_empty(ladish_dict_handle dict_handle) +{ + return list_empty(&dict_ptr->entries); +} + #undef dict_ptr diff --git a/daemon/dict.h b/daemon/dict.h index 952d165e..4a54d00e 100644 --- a/daemon/dict.h +++ b/daemon/dict.h @@ -38,5 +38,6 @@ const char * ladish_dict_get(ladish_dict_handle dict_handle, const char * key); void ladish_dict_drop(ladish_dict_handle dict_handle, const char * key); void ladish_dict_clear(ladish_dict_handle dict_handle); bool ladish_dict_iterate(ladish_dict_handle dict_handle, void * context, bool (* callback)(void * context, const char * key, const char * value)); +bool ladish_dict_is_empty(ladish_dict_handle dict_handle); #endif /* #ifndef DICT_H__12A321F8_A361_482B_9255_66CCD4D3C31F__INCLUDED */ diff --git a/daemon/graph.c b/daemon/graph.c index 5ee6b0d0..14a0c399 100644 --- a/daemon/graph.c +++ b/daemon/graph.c @@ -805,7 +805,7 @@ ladish_graph_iterate_nodes( ladish_graph_handle graph_handle, void * callback_context, bool - (* client_callback)( + (* client_begin_callback)( void * context, ladish_client_handle client_handle, const char * client_name, @@ -819,7 +819,13 @@ ladish_graph_iterate_nodes( ladish_port_handle port_handle, const char * port_name, uint32_t port_type, - uint32_t port_flags)) + uint32_t port_flags), + bool + (* client_end_callback)( + void * context, + ladish_client_handle client_handle, + const char * client_name, + void * client_iteration_context_ptr)) { struct list_head * client_node_ptr; struct ladish_graph_client * client_ptr; @@ -830,7 +836,7 @@ ladish_graph_iterate_nodes( list_for_each(client_node_ptr, &graph_ptr->clients) { client_ptr = list_entry(client_node_ptr, struct ladish_graph_client, siblings); - if (!client_callback(callback_context, client_ptr->client, client_ptr->name, &client_context)) + if (!client_begin_callback(callback_context, client_ptr->client, client_ptr->name, &client_context)) { return false; } @@ -852,6 +858,11 @@ ladish_graph_iterate_nodes( return false; } } + + if (!client_end_callback(callback_context, client_ptr->client, client_ptr->name, &client_context)) + { + return false; + } } return true; diff --git a/daemon/graph.h b/daemon/graph.h index 3bc1aa38..d69c82c3 100644 --- a/daemon/graph.h +++ b/daemon/graph.h @@ -72,7 +72,7 @@ ladish_graph_iterate_nodes( ladish_graph_handle graph_handle, void * callback_context, bool - (* client_callback)( + (* client_begin_callback)( void * context, ladish_client_handle client_handle, const char * client_name, @@ -86,7 +86,13 @@ ladish_graph_iterate_nodes( ladish_port_handle port_handle, const char * port_name, uint32_t port_type, - uint32_t port_flags)); + uint32_t port_flags), + bool + (* client_end_callback)( + void * context, + ladish_client_handle client_handle, + const char * client_name, + void * client_iteration_context_ptr)); extern const struct dbus_interface_descriptor g_interface_patchbay; diff --git a/daemon/port.c b/daemon/port.c index 81425062..b4f0cfd8 100644 --- a/daemon/port.c +++ b/daemon/port.c @@ -105,6 +105,11 @@ ladish_dict_handle ladish_port_get_dict(ladish_port_handle port_handle) return port_ptr->dict; } +void ladish_port_get_uuid(ladish_port_handle port_handle, uuid_t uuid) +{ + uuid_copy(uuid, port_ptr->uuid); +} + void ladish_port_set_jack_id(ladish_port_handle port_handle, uint64_t jack_id) { port_ptr->jack_id = jack_id; diff --git a/daemon/port.h b/daemon/port.h index 5b7ee19a..a013a1aa 100644 --- a/daemon/port.h +++ b/daemon/port.h @@ -34,7 +34,7 @@ typedef struct ladish_port_tag { int unused; } * ladish_port_handle; bool ladish_port_create(uuid_t uuid_ptr, ladish_port_handle * port_handle_ptr); void ladish_port_destroy(ladish_port_handle port_handle); ladish_dict_handle ladish_port_get_dict(ladish_port_handle port_handle); - +void ladish_port_get_uuid(ladish_port_handle port_handle, uuid_t uuid); void ladish_port_set_jack_id(ladish_port_handle port_handle, uint64_t jack_id); uint64_t ladish_port_get_jack_id(ladish_port_handle port_handle); diff --git a/daemon/studio_load.c b/daemon/studio_load.c index 50afe4b9..e5baa607 100644 --- a/daemon/studio_load.c +++ b/daemon/studio_load.c @@ -36,11 +36,17 @@ #include "escape.h" #include "studio_internal.h" -#define PARSE_CONTEXT_ROOT 0 -#define PARSE_CONTEXT_STUDIO 1 -#define PARSE_CONTEXT_JACK 2 -#define PARSE_CONTEXT_CONF 3 -#define PARSE_CONTEXT_PARAMETER 4 +#define PARSE_CONTEXT_ROOT 0 +#define PARSE_CONTEXT_STUDIO 1 +#define PARSE_CONTEXT_JACK 2 +#define PARSE_CONTEXT_CONF 3 +#define PARSE_CONTEXT_PARAMETER 4 +#define PARSE_CONTEXT_CLIENTS 5 +#define PARSE_CONTEXT_CLIENT 6 +#define PARSE_CONTEXT_PORTS 7 +#define PARSE_CONTEXT_PORT 8 +#define PARSE_CONTEXT_DICT 9 +#define PARSE_CONTEXT_KEY 10 #define MAX_STACK_DEPTH 10 #define MAX_DATA_SIZE 1024 @@ -137,6 +143,48 @@ static void callback_elstart(void * data, const char * el, const char ** attr) return; } + if (strcmp(el, "clients") == 0) + { + //log_info(""); + context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_CLIENTS; + return; + } + + if (strcmp(el, "client") == 0) + { + //log_info(""); + context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_CLIENT; + return; + } + + if (strcmp(el, "ports") == 0) + { + //log_info(""); + context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_PORTS; + return; + } + + if (strcmp(el, "port") == 0) + { + //log_info(""); + context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_PORT; + return; + } + + if (strcmp(el, "dict") == 0) + { + //log_info(""); + context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_DICT; + return; + } + + if (strcmp(el, "key") == 0) + { + //log_info(""); + context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_KEY; + return; + } + lash_dbus_error(context_ptr->call_ptr, LASH_DBUS_ERROR_GENERIC, "unknown element \"%s\"", el); context_ptr->error = XML_TRUE; } diff --git a/daemon/studio_save.c b/daemon/studio_save.c index 9a131c55..b25bb1d0 100644 --- a/daemon/studio_save.c +++ b/daemon/studio_save.c @@ -35,6 +35,13 @@ #include "escape.h" #include "studio_internal.h" +struct save_context +{ + int fd; + void * call_ptr; + const char * indent; +}; + #define STUDIO_HEADER_TEXT BASE_NAME " Studio configuration.\n" bool @@ -142,21 +149,168 @@ write_jack_parameter( return true; } +static bool -save_jack_client( +write_dict_entry( + void * context, + const char * key, + const char * value); + +bool +write_dict( + int fd, + const char * indent, + ladish_dict_handle dict, + void * call_ptr) +{ + struct save_context context; + + if (ladish_dict_is_empty(dict)) + { + return true; + } + + if (!write_string(fd, indent, call_ptr)) + { + return false; + } + + context.fd = fd; + context.call_ptr = call_ptr; + context.indent = indent; + + if (!write_string(fd, "\n", call_ptr)) + { + return false; + } + + if (!ladish_dict_iterate(dict, &context, write_dict_entry)) + { + return false; + } + + if (!write_string(fd, indent, call_ptr)) + { + return false; + } + + if (!write_string(fd, "\n", call_ptr)) + { + return false; + } + + return true; +} + +#define fd (((struct save_context *)context)->fd) +#define call_ptr (((struct save_context *)context)->call_ptr) +#define indent (((struct save_context *)context)->indent) + +static +bool +write_dict_entry( + void * context, + const char * key, + const char * value) +{ + if (!write_string(fd, indent, call_ptr)) + { + return false; + } + + if (!write_string(fd, " ", call_ptr)) + { + return false; + } + + if (!write_string(fd, value, call_ptr)) + { + return false; + } + + if (!write_string(fd, "\n", call_ptr)) + { + return false; + } + + return true; +} + +bool +save_jack_client_begin( void * context, ladish_client_handle client_handle, const char * client_name, void ** client_iteration_context_ptr_ptr) { -#if 0 uuid_t uuid; char str[37]; ladish_client_get_uuid(client_handle, uuid); uuid_unparse(uuid, str); -#endif - log_info("saving jack client '%s'", client_name); + + log_info("saving jack client '%s' (%s)", client_name, str); + + if (!write_string(fd, " \n", call_ptr)) + { + return false; + } + + if (!write_string(fd, " \n", call_ptr)) + { + return false; + } + + return true; +} + +bool +save_jack_client_end( + void * context, + ladish_client_handle client_handle, + const char * client_name, + void * client_iteration_context_ptr) +{ + if (!write_string(fd, " \n", call_ptr)) + { + return false; + } + + if (!write_string(fd, " \n", call_ptr)) + { + return false; + } + return true; } @@ -171,25 +325,112 @@ save_jack_port( uint32_t port_type, uint32_t port_flags) { - log_info("saving jack port '%s':'%s'", client_name, port_name); + uuid_t uuid; + char str[37]; + + ladish_port_get_uuid(port_handle, uuid); + uuid_unparse(uuid, str); + + log_info("saving jack port '%s':'%s' (%s)", client_name, port_name, str); + + if (!write_string(fd, " \n", call_ptr)) + { + return false; + } + return true; } bool -save_studio_client( +save_studio_client_begin( void * context, ladish_client_handle client_handle, const char * client_name, void ** client_iteration_context_ptr_ptr) { -#if 0 uuid_t uuid; char str[37]; ladish_client_get_uuid(client_handle, uuid); uuid_unparse(uuid, str); -#endif - log_info("saving studio client '%s'", client_name); + + log_info("saving studio client '%s' (%s)", client_name, str); + + if (!write_string(fd, " \n", call_ptr)) + { + return false; + } + + if (!write_string(fd, " \n", call_ptr)) + { + return false; + } + + return true; +} + +bool +save_studio_client_end( + void * context, + ladish_client_handle client_handle, + const char * client_name, + void * client_iteration_context_ptr) +{ + if (!write_string(fd, " \n", call_ptr)) + { + return false; + } + + if (!write_dict(fd, " ", ladish_client_get_dict(client_handle), call_ptr)) + { + return false; + } + + if (!write_string(fd, " \n", call_ptr)) + { + return false; + } + return true; } @@ -204,10 +445,68 @@ save_studio_port( uint32_t port_type, uint32_t port_flags) { - log_info("saving studio port '%s':'%s'", client_name, port_name); + uuid_t uuid; + char str[37]; + ladish_dict_handle dict; + + ladish_port_get_uuid(port_handle, uuid); + uuid_unparse(uuid, str); + + log_info("saving studio port '%s':'%s' (%s)", client_name, port_name, str); + + if (!write_string(fd, " \n", call_ptr)) + { + return false; + } + } + else + { + if (!write_string(fd, "\">\n", call_ptr)) + { + return false; + } + + if (!write_dict(fd, " ", dict, call_ptr)) + { + return false; + } + + if (!write_string(fd, " \n", call_ptr)) + { + return false; + } + } + return true; } +#undef indent +#undef fd +#undef call_ptr + bool studio_save(void * call_ptr) { struct list_head * node_ptr; @@ -220,6 +519,7 @@ bool studio_save(void * call_ptr) char * bak_filename; /* filename of the backup file */ char * old_filename; /* filename where studio was persisted before save */ struct stat st; + struct save_context context; time(×tamp); ctime_r(×tamp, timestamp_str); @@ -357,7 +657,10 @@ bool studio_save(void * call_ptr) goto close; } - if (!ladish_graph_iterate_nodes(g_studio.jack_graph, call_ptr, save_jack_client, save_jack_port)) + context.fd = fd; + context.call_ptr = call_ptr; + + if (!ladish_graph_iterate_nodes(g_studio.jack_graph, &context, save_jack_client_begin, save_jack_port, save_jack_client_end)) { log_error("ladish_graph_iterate_nodes() failed"); goto close; @@ -378,7 +681,7 @@ bool studio_save(void * call_ptr) goto close; } - if (!ladish_graph_iterate_nodes(g_studio.studio_graph, call_ptr, save_studio_client, save_studio_port)) + if (!ladish_graph_iterate_nodes(g_studio.studio_graph, &context, save_studio_client_begin, save_studio_port, save_studio_client_end)) { log_error("ladish_graph_iterate_nodes() failed"); goto close; @@ -389,6 +692,11 @@ bool studio_save(void * call_ptr) goto close; } + if (!write_dict(fd, " ", ladish_graph_get_dict(g_studio.studio_graph), call_ptr)) + { + return false; + } + if (!write_string(fd, "\n", call_ptr)) { goto close;