2 Calf Box, an open source musical instrument.
3 Copyright (C) 2012 Krzysztof Foltman
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
28 static GHashTable
*class_name_hash
= NULL
;
30 struct cbox_class_per_document
37 GHashTable
*classes_per_document
;
38 GHashTable
*services_per_document
;
39 GHashTable
*uuids_per_document
;
40 struct cbox_command_target cmd_target
;
44 ////////////////////////////////////////////////////////////////////////////////////////
48 class_name_hash
= g_hash_table_new(g_str_hash
, g_str_equal
);
53 g_hash_table_destroy(class_name_hash
);
56 ////////////////////////////////////////////////////////////////////////////////////////
58 struct cbox_class
*cbox_class_find_by_name(const char *name
)
60 assert(class_name_hash
!= NULL
);
61 return g_hash_table_lookup(class_name_hash
, name
);
64 void cbox_class_register(struct cbox_class
*class_ptr
)
66 assert(class_name_hash
!= NULL
);
67 g_hash_table_insert(class_name_hash
, (gpointer
)class_ptr
->name
, class_ptr
);
70 static struct cbox_class_per_document
*get_cpd_for_class(struct cbox_document
*doc
, struct cbox_class
*class_ptr
)
72 struct cbox_class_per_document
*p
= g_hash_table_lookup(doc
->classes_per_document
, class_ptr
);
75 p
= malloc(sizeof(struct cbox_class_per_document
));
77 g_hash_table_insert(doc
->classes_per_document
, class_ptr
, p
);
81 ////////////////////////////////////////////////////////////////////////////////////////
83 guint
cbox_uuid_hash(gconstpointer v
)
86 uuid_unparse_lower(((struct cbox_uuid
*)v
)->uuid
, buf
);
87 return g_str_hash(buf
);
90 gboolean
cbox_uuid_equal(gconstpointer v1
, gconstpointer v2
)
92 const struct cbox_uuid
*p1
= v1
;
93 const struct cbox_uuid
*p2
= v2
;
95 return !uuid_compare(p1
->uuid
, p2
->uuid
);
98 gboolean
cbox_uuid_report_as(struct cbox_uuid
*uuid
, const char *cmd
, struct cbox_command_target
*fb
, GError
**error
)
102 return cbox_execute_on(fb
, NULL
, cmd
, "u", error
, uuid
->uuid
);
105 gboolean
cbox_uuid_report(struct cbox_uuid
*uuid
, struct cbox_command_target
*fb
, GError
**error
)
107 return cbox_uuid_report_as(uuid
, "/uuid", fb
, error
);
110 gboolean
cbox_uuid_fromstring(struct cbox_uuid
*uuid
, const char *str
, GError
**error
)
112 if (uuid_parse(str
, uuid
->uuid
))
114 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Malformed UUID: '%s'", str
);
120 void cbox_uuid_tostring(struct cbox_uuid
*uuid
, char str
[40])
122 uuid_unparse(uuid
->uuid
, str
);
125 void cbox_uuid_generate(struct cbox_uuid
*uuid
)
127 uuid_generate(uuid
->uuid
);
130 ////////////////////////////////////////////////////////////////////////////////////////
132 void cbox_object_register_instance(struct cbox_document
*doc
, struct cbox_objhdr
*obj
)
136 struct cbox_class_per_document
*cpd
= get_cpd_for_class(doc
, obj
->class_ptr
);
137 cpd
->instances
= g_list_prepend(cpd
->instances
, obj
);
139 obj
->link_in_document
= cpd
->instances
;
140 g_hash_table_insert(obj
->owner
->uuids_per_document
, &obj
->instance_uuid
, obj
);
143 struct cbox_command_target
*cbox_object_get_cmd_target(struct cbox_objhdr
*hdr_ptr
)
145 if (!hdr_ptr
->class_ptr
->getcmdtargetfunc
)
147 return hdr_ptr
->class_ptr
->getcmdtargetfunc(hdr_ptr
);
150 gboolean
cbox_object_try_default_process_cmd(struct cbox_command_target
*ct
, struct cbox_command_target
*fb
, struct cbox_osc_command
*cmd
, const char *subcmd
, gboolean
*result
, GError
**error
)
152 // XXXKF this assumes objhdr ptr == object ptr - needs to add the header offset in cmd target?
153 struct cbox_objhdr
*obj
= ct
->user_data
;
154 if (!strcmp(subcmd
, "/status") && !strcmp(cmd
->arg_types
, ""))
156 if (!cbox_object_default_status(obj
, fb
, error
))
163 if (!strcmp(subcmd
, "/delete") && !strcmp(cmd
->arg_types
, ""))
165 cbox_object_destroy(obj
);
169 if (!strcmp(subcmd
, "/get_uuid") && !strcmp(cmd
->arg_types
, ""))
171 if (!cbox_check_fb_channel(fb
, cmd
->command
, error
))
177 *result
= cbox_uuid_report(&obj
->instance_uuid
, fb
, error
);
180 if (!strcmp(subcmd
, "/get_class_name") && !strcmp(cmd
->arg_types
, ""))
182 if (!cbox_check_fb_channel(fb
, cmd
->command
, error
))
187 *result
= cbox_execute_on(fb
, NULL
, "/class_name", "s", error
, obj
->class_ptr
->name
);
193 gboolean
cbox_object_default_process_cmd(struct cbox_command_target
*ct
, struct cbox_command_target
*fb
, struct cbox_osc_command
*cmd
, GError
**error
)
195 gboolean result
= FALSE
;
196 if (cbox_object_try_default_process_cmd(ct
, fb
, cmd
, cmd
->command
, &result
, error
))
198 struct cbox_objhdr
*obj
= ct
->user_data
;
199 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Unknown combination of target path and argument: '%s', '%s' for object class '%s'", cmd
->command
, cmd
->arg_types
, obj
->class_ptr
->name
);
203 gboolean
cbox_object_default_status(struct cbox_objhdr
*objhdr
, struct cbox_command_target
*fb
, GError
**error
)
206 uuid_unparse(objhdr
->instance_uuid
.uuid
, buf
);
207 return cbox_execute_on(fb
, NULL
, "/uuid", "s", error
, buf
);
210 void cbox_object_destroy(struct cbox_objhdr
*hdr_ptr
)
212 struct cbox_class_per_document
*cpd
= get_cpd_for_class(hdr_ptr
->owner
, hdr_ptr
->class_ptr
);
213 cpd
->instances
= g_list_remove_link(cpd
->instances
, hdr_ptr
->link_in_document
);
214 hdr_ptr
->link_in_document
= NULL
;
215 g_hash_table_remove(hdr_ptr
->owner
->uuids_per_document
, &hdr_ptr
->instance_uuid
);
217 hdr_ptr
->class_ptr
->destroyfunc(hdr_ptr
);
220 ////////////////////////////////////////////////////////////////////////////////////////
222 static gboolean
document_process_cmd(struct cbox_command_target
*ct
, struct cbox_command_target
*fb
, struct cbox_osc_command
*cmd
, GError
**error
)
225 const char *subcommand
;
226 if (!strcmp(cmd
->command
, "/dump") && !strcmp(cmd
->arg_types
, ""))
228 struct cbox_document
*doc
= ct
->user_data
;
229 cbox_document_dump(doc
);
232 if (cbox_parse_path_part_str(cmd
, "/uuid/", &subcommand
, &uuid
, error
))
234 struct cbox_document
*doc
= ct
->user_data
;
237 struct cbox_objhdr
*obj
= cbox_document_get_object_by_text_uuid(doc
, uuid
, NULL
, error
);
241 struct cbox_command_target
*ct2
= cbox_object_get_cmd_target(obj
);
242 return cbox_execute_sub(ct2
, fb
, cmd
, subcommand
, error
);
244 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Unknown combination of target path and argument: '%s', '%s'", cmd
->command
, cmd
->arg_types
);
248 struct cbox_document
*cbox_document_new()
250 struct cbox_document
*res
= malloc(sizeof(struct cbox_document
));
251 res
->classes_per_document
= g_hash_table_new_full(NULL
, NULL
, NULL
, g_free
);
252 res
->services_per_document
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, NULL
);
253 res
->uuids_per_document
= g_hash_table_new(cbox_uuid_hash
, cbox_uuid_equal
);
254 res
->cmd_target
.process_cmd
= document_process_cmd
;
255 res
->cmd_target
.user_data
= res
;
261 struct cbox_command_target
*cbox_document_get_cmd_target(struct cbox_document
*doc
)
263 return &doc
->cmd_target
;
266 struct cbox_objhdr
*cbox_document_get_service(struct cbox_document
*document
, const char *name
)
268 return g_hash_table_lookup(document
->services_per_document
, name
);
271 void cbox_document_set_service(struct cbox_document
*document
, const char *name
, struct cbox_objhdr
*obj
)
273 g_hash_table_insert(document
->services_per_document
, g_strdup(name
), obj
);
276 struct cbox_objhdr
*cbox_document_get_object_by_uuid(struct cbox_document
*doc
, const struct cbox_uuid
*uuid
)
278 return g_hash_table_lookup(doc
->uuids_per_document
, uuid
);
281 struct cbox_objhdr
*cbox_document_get_object_by_text_uuid(struct cbox_document
*doc
, const char *uuid
, const struct cbox_class
*class_ptr
, GError
**error
)
283 struct cbox_uuid uuidv
;
284 if (!cbox_uuid_fromstring(&uuidv
, uuid
, error
))
286 struct cbox_objhdr
*obj
= cbox_document_get_object_by_uuid(doc
, &uuidv
);
289 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "UUID not found: '%s'", uuid
);
292 if (class_ptr
&& !cbox_class_is_a(obj
->class_ptr
, class_ptr
))
294 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Unexpected object type '%s' for UUID '%s' (expected '%s')", obj
->class_ptr
->name
, uuid
, class_ptr
->name
);
300 static void iter_func(gpointer key
, gpointer value
, gpointer doc_
)
303 struct cbox_document
*doc
= (struct cbox_document
*)doc_
;
305 struct cbox_class
*class_ptr
= key
;
306 struct cbox_class_per_document
*cpd
= value
;
308 printf("Class %s: ", class_ptr
->name
);
309 GList
*l
= cpd
->instances
;
313 printf("%p", l
->data
);
315 struct cbox_objhdr
*hdr
= (struct cbox_objhdr
*)l
->data
;
317 uuid_unparse(hdr
->instance_uuid
.uuid
, buf
);
320 assert(cbox_document_get_object_by_uuid(doc
, &hdr
->instance_uuid
));
325 printf("<no instances>");
329 static void iter_func2(gpointer key
, gpointer value
, gpointer document
)
331 struct cbox_objhdr
*oh
= value
;
333 uuid_unparse(oh
->instance_uuid
.uuid
, buf
);
334 printf("Service %s: %p", (const char *)key
, value
);
338 printf(" (%s)\n", oh
->class_ptr
->name
);
341 void cbox_document_dump(struct cbox_document
*document
)
343 g_hash_table_foreach(document
->classes_per_document
, iter_func
, document
);
344 g_hash_table_foreach(document
->services_per_document
, iter_func2
, document
);
347 void cbox_document_destroy(struct cbox_document
*document
)
349 g_hash_table_destroy(document
->classes_per_document
);
350 g_hash_table_destroy(document
->services_per_document
);
351 g_hash_table_destroy(document
->uuids_per_document
);