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 guint
cbox_uuid_hash(gconstpointer v
);
29 static gboolean
cbox_uuid_equal(gconstpointer v1
, gconstpointer v2
);
31 static GHashTable
*class_name_hash
= NULL
;
33 struct cbox_class_per_document
40 GHashTable
*classes_per_document
;
41 GHashTable
*services_per_document
;
42 GHashTable
*uuids_per_document
;
43 struct cbox_command_target cmd_target
;
47 ////////////////////////////////////////////////////////////////////////////////////////
51 class_name_hash
= g_hash_table_new(g_str_hash
, g_str_equal
);
56 g_hash_table_destroy(class_name_hash
);
59 ////////////////////////////////////////////////////////////////////////////////////////
61 struct cbox_class
*cbox_class_find_by_name(const char *name
)
63 assert(class_name_hash
!= NULL
);
64 return g_hash_table_lookup(class_name_hash
, name
);
67 void cbox_class_register(struct cbox_class
*class_ptr
)
69 assert(class_name_hash
!= NULL
);
70 g_hash_table_insert(class_name_hash
, (gpointer
)class_ptr
->name
, class_ptr
);
73 static struct cbox_class_per_document
*get_cpd_for_class(struct cbox_document
*doc
, struct cbox_class
*class_ptr
)
75 struct cbox_class_per_document
*p
= g_hash_table_lookup(doc
->classes_per_document
, class_ptr
);
78 p
= malloc(sizeof(struct cbox_class_per_document
));
80 g_hash_table_insert(doc
->classes_per_document
, class_ptr
, p
);
84 ////////////////////////////////////////////////////////////////////////////////////////
86 guint
cbox_uuid_hash(gconstpointer v
)
89 uuid_unparse_lower(((struct cbox_uuid
*)v
)->uuid
, buf
);
90 return g_str_hash(buf
);
93 gboolean
cbox_uuid_equal(gconstpointer v1
, gconstpointer v2
)
95 const struct cbox_uuid
*p1
= v1
;
96 const struct cbox_uuid
*p2
= v2
;
98 return !uuid_compare(p1
->uuid
, p2
->uuid
);
101 ////////////////////////////////////////////////////////////////////////////////////////
103 void cbox_object_register_instance(struct cbox_document
*doc
, struct cbox_objhdr
*obj
)
107 struct cbox_class_per_document
*cpd
= get_cpd_for_class(doc
, obj
->class_ptr
);
108 cpd
->instances
= g_list_prepend(cpd
->instances
, obj
);
110 obj
->link_in_document
= cpd
->instances
;
111 g_hash_table_insert(obj
->owner
->uuids_per_document
, &obj
->instance_uuid
, obj
);
114 struct cbox_command_target
*cbox_object_get_cmd_target(struct cbox_objhdr
*hdr_ptr
)
116 if (!hdr_ptr
->class_ptr
->getcmdtargetfunc
)
118 return hdr_ptr
->class_ptr
->getcmdtargetfunc(hdr_ptr
);
121 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
)
123 // XXXKF this assumes objhdr ptr == object ptr - needs to add the header offset in cmd target?
124 struct cbox_objhdr
*obj
= ct
->user_data
;
125 if (!strcmp(subcmd
, "/status") && !strcmp(cmd
->arg_types
, ""))
127 if (!cbox_object_default_status(obj
, fb
, error
))
134 if (!strcmp(subcmd
, "/delete") && !strcmp(cmd
->arg_types
, ""))
136 cbox_object_destroy(obj
);
140 if (!strcmp(subcmd
, "/get_uuid") && !strcmp(cmd
->arg_types
, ""))
142 if (!cbox_check_fb_channel(fb
, cmd
->command
, error
))
149 uuid_unparse(obj
->instance_uuid
.uuid
, buf
);
150 *result
= cbox_execute_on(fb
, NULL
, "/uuid", "s", error
, buf
);
153 if (!strcmp(subcmd
, "/get_class_name") && !strcmp(cmd
->arg_types
, ""))
155 if (!cbox_check_fb_channel(fb
, cmd
->command
, error
))
160 *result
= cbox_execute_on(fb
, NULL
, "/class_name", "s", error
, obj
->class_ptr
->name
);
166 gboolean
cbox_object_default_process_cmd(struct cbox_command_target
*ct
, struct cbox_command_target
*fb
, struct cbox_osc_command
*cmd
, GError
**error
)
168 gboolean result
= FALSE
;
169 if (cbox_object_try_default_process_cmd(ct
, fb
, cmd
, cmd
->command
, &result
, error
))
171 struct cbox_objhdr
*obj
= ct
->user_data
;
172 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
);
176 gboolean
cbox_object_default_status(struct cbox_objhdr
*objhdr
, struct cbox_command_target
*fb
, GError
**error
)
179 uuid_unparse(objhdr
->instance_uuid
.uuid
, buf
);
180 return cbox_execute_on(fb
, NULL
, "/uuid", "s", error
, buf
);
183 void cbox_object_destroy(struct cbox_objhdr
*hdr_ptr
)
185 struct cbox_class_per_document
*cpd
= get_cpd_for_class(hdr_ptr
->owner
, hdr_ptr
->class_ptr
);
186 cpd
->instances
= g_list_remove_link(cpd
->instances
, hdr_ptr
->link_in_document
);
187 hdr_ptr
->link_in_document
= NULL
;
188 g_hash_table_remove(hdr_ptr
->owner
->uuids_per_document
, &hdr_ptr
->instance_uuid
);
190 hdr_ptr
->class_ptr
->destroyfunc(hdr_ptr
);
193 ////////////////////////////////////////////////////////////////////////////////////////
195 static gboolean
document_process_cmd(struct cbox_command_target
*ct
, struct cbox_command_target
*fb
, struct cbox_osc_command
*cmd
, GError
**error
)
198 const char *subcommand
;
199 if (!strcmp(cmd
->command
, "/dump") && !strcmp(cmd
->arg_types
, ""))
201 struct cbox_document
*doc
= ct
->user_data
;
202 cbox_document_dump(doc
);
205 if (cbox_parse_path_part_str(cmd
, "/uuid/", &subcommand
, &uuid
, error
))
207 struct cbox_document
*doc
= ct
->user_data
;
210 struct cbox_objhdr
*obj
= cbox_document_get_object_by_text_uuid(doc
, uuid
, NULL
, error
);
214 struct cbox_command_target
*ct2
= cbox_object_get_cmd_target(obj
);
215 return cbox_execute_sub(ct2
, fb
, cmd
, subcommand
, error
);
217 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
);
221 struct cbox_document
*cbox_document_new()
223 struct cbox_document
*res
= malloc(sizeof(struct cbox_document
));
224 res
->classes_per_document
= g_hash_table_new(NULL
, NULL
);
225 res
->services_per_document
= g_hash_table_new_full(g_str_hash
, g_str_equal
, g_free
, NULL
);
226 res
->uuids_per_document
= g_hash_table_new(cbox_uuid_hash
, cbox_uuid_equal
);
227 res
->cmd_target
.process_cmd
= document_process_cmd
;
228 res
->cmd_target
.user_data
= res
;
234 struct cbox_command_target
*cbox_document_get_cmd_target(struct cbox_document
*doc
)
236 return &doc
->cmd_target
;
239 struct cbox_objhdr
*cbox_document_get_service(struct cbox_document
*document
, const char *name
)
241 return g_hash_table_lookup(document
->services_per_document
, name
);
244 void cbox_document_set_service(struct cbox_document
*document
, const char *name
, struct cbox_objhdr
*obj
)
246 g_hash_table_insert(document
->services_per_document
, g_strdup(name
), obj
);
249 struct cbox_objhdr
*cbox_document_get_object_by_uuid(struct cbox_document
*doc
, const struct cbox_uuid
*uuid
)
251 return g_hash_table_lookup(doc
->uuids_per_document
, uuid
);
254 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
)
256 struct cbox_uuid uuidv
;
257 if (uuid_parse(uuid
, uuidv
.uuid
))
259 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Malformed UUID: '%s'", uuid
);
262 struct cbox_objhdr
*obj
= cbox_document_get_object_by_uuid(doc
, &uuidv
);
265 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "UUID not found: '%s'", uuid
);
268 if (class_ptr
&& !cbox_class_is_a(obj
->class_ptr
, class_ptr
))
270 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
);
276 static void iter_func(gpointer key
, gpointer value
, gpointer doc_
)
278 struct cbox_document
*doc
= (struct cbox_document
*)doc_
;
279 struct cbox_class
*class_ptr
= key
;
280 struct cbox_class_per_document
*cpd
= value
;
282 printf("Class %s: ", class_ptr
->name
);
283 GList
*l
= cpd
->instances
;
287 printf("%p", l
->data
);
289 struct cbox_objhdr
*hdr
= (struct cbox_objhdr
*)l
->data
;
291 uuid_unparse(hdr
->instance_uuid
.uuid
, buf
);
294 assert(cbox_document_get_object_by_uuid(doc
, &hdr
->instance_uuid
));
299 printf("<no instances>");
303 static void iter_func2(gpointer key
, gpointer value
, gpointer document
)
305 struct cbox_objhdr
*oh
= value
;
307 uuid_unparse(oh
->instance_uuid
.uuid
, buf
);
309 printf("Service %s: %p", (const char *)key
, value
);
313 printf(" (%s)\n", oh
->class_ptr
->name
);
316 void cbox_document_dump(struct cbox_document
*document
)
318 g_hash_table_foreach(document
->classes_per_document
, iter_func
, document
);
319 g_hash_table_foreach(document
->services_per_document
, iter_func2
, document
);
322 void cbox_document_destroy(struct cbox_document
*document
)
324 g_hash_table_destroy(document
->classes_per_document
);
325 g_hash_table_destroy(document
->services_per_document
);
326 g_hash_table_destroy(document
->uuids_per_document
);