summaryrefslogtreecommitdiffstats
path: root/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'common.c')
-rw-r--r--common.c323
1 files changed, 323 insertions, 0 deletions
diff --git a/common.c b/common.c
new file mode 100644
index 0000000..9ae9d8e
--- /dev/null
+++ b/common.c
@@ -0,0 +1,323 @@
+#include "canberra.h"
+#include "common.h"
+
+int ca_context_create(ca_context_t **c) {
+ ca_return_val_if_fail(c, CA_ERROR_INVALID);
+
+ if (!(*c = ca_new0(ca_context_t, 1)))
+ return CA_ERROR_OOM;
+
+ return CA_SUCCESS;
+}
+
+int ca_context_destroy(ca_context_t *c) {
+ int ret;
+ unsigned i;
+ ca_prop *p, *n;
+
+ ca_return_val_if_fail(c, CA_ERROR_INVALID);
+
+ ret = driver_destroy(c);
+
+ for (p = c->first_item; p; p = n) {
+ n = p->next_item;
+ ca_free(p);
+ }
+
+ ca_free(c);
+
+ return ret;
+}
+
+int ca_context_open(ca_context_t *c) {
+ int ret;
+
+ ca_return_val_if_fail(c, CA_ERROR_INVALID);
+ ca_return_val_if_fail(!c->opened, CA_ERROR_STATE);
+
+ if ((ret = driver_open(c)) == 0)
+ c->opened = TRUE;
+
+ return ret;
+}
+
+int ca_context_sets(ca_context_t *c, ...) {
+ va_list ap;
+ int ret = CA_SUCCESS;
+
+ ca_return_val_if_fail(c, CA_ERROR_INVALID);
+
+ va_start(ap, c);
+
+ for (;;) {
+ const char *key, *value;
+ int ret;
+
+ if (!(key = v_arg(ap, const char*)))
+ break;
+
+ if (!(value = v_arg(ap, const char *))) {
+ ret = CA_ERROR_INVALID;
+ break;
+ }
+
+ if ((ret = ca_context_set(c, key, value, strlen(value)+1)) < 0)
+ break;
+ }
+
+ va_end(ap);
+
+ return ret;
+}
+
+static int _unset(ca_context_t *c, const char *key) {
+ ca_prop *p, *np;
+ unsigned i;
+
+ ca_return_val_if_fail(c, CA_ERROR_INVALID);
+ ca_return_val_if_fail(key, CA_ERROR_INVALID);
+
+ i = calc_hash(key) % N_HASHTABLE;
+
+ np = NULL;
+ for (p = c->props[i]; p; np = p, p = p->next_in_slot)
+ if (strcmp(p->key, key) == 0)
+ break;
+
+ if (p) {
+ if (np)
+ np->next_in_slot = p->next_in_slot;
+ else
+ c->props[i] = p->next_in_slot;
+
+ if (p->prev_item)
+ p->prev_item->next_item = p->next_item;
+ else
+ c->first_item = p->next_item;
+
+ if (p->next_item)
+ p->next_item->prev_item = p->prev_item;
+
+ ca_free(p);
+ }
+}
+
+int ca_context_set(ca_context_t *c, const char *key, const void *data, size_t nbytes) {
+ int ret;
+ ca_prop *p;
+ char *k;
+
+ ca_return_val_if_fail(c, CA_ERROR_INVALID);
+ ca_return_val_if_fail(key, CA_ERROR_INVALID);
+ ca_return_val_if_fail(!nbytes || data, CA_ERROR_INVALID);
+
+ if (!(k = ca_strdup(key)))
+ return CA_ERROR_OOM;
+
+ if (!(p = ca_malloc(CA_ALIGN(sizeof(ca_prop)) + nbytes))) {
+ ca_free(k);
+ return CA_ERROR_OOM;
+ }
+
+ if ((ret = _unset(c, key)) < 0) {
+ ca_free(p);
+ ca_free(k);
+ return ret;
+ }
+
+ p->key = k;
+ p->nbytes = nbytes;
+ memcpy(CA_PROP_DATA(p), data, nbytes);
+
+ i = calc_hash(key) % N_HASHTABLE;
+
+ p->next_in_slot = c->props[i];
+ c->props[i] = p;
+
+ p->prev_item = NULL;
+ p->next_item = c->first_item;
+ c->first_item = p;
+
+ if (c->opened)
+ if ((ret = driver_set(c, key, data, nbytes)) < 0)
+ return ret;
+
+ return CA_SUCCESS;
+}
+
+int ca_context_unset(ca_context *c, ...) {
+ int ret = CA_SUCCESS;
+ va_list ap;
+
+ ca_return_val_if_fail(c, CA_ERROR_INVALID);
+ ca_return_val_if_fail(key, CA_ERROR_INVALID);
+
+ va_start(ap, c);
+
+ for (;;) {
+ const char *key;
+
+ if (!(key = v_arg(ap, const char*)))
+ break;
+
+ if (c->opened) {
+ if ((ret = driver_unset(c, key)) < 0)
+ break;
+ }
+
+ if ((ret = _unset(c, key)) < 0)
+ break;
+ }
+
+ va_end(ap);
+
+ return ret;
+}
+
+/* Not exported */
+ca_prop* ca_context_get(ca_context *c, const char *key) {
+ ca_prop *p;
+ unsigned i;
+
+ ca_return_val_if_fail(c, NULL);
+ ca_return_val_if_fail(key, NULL);
+
+ i = calc_hash(key) % N_HASHTABLE;
+
+ for (p = c->props[i]; p; p = p->next_in_slot)
+ if (strcmp(p->key, key) == 0)
+ return p;
+
+ return NULL;
+}
+
+/* Not exported */
+const char* ca_context_gets(ca_context *c, const char *key) {
+ ca_prop *p;
+
+ ca_return_val_if_fail(c, NULL);
+ ca_return_val_if_fail(key, NULL);
+
+ if (!(p = ca_context_get(c, key)))
+ return NULL;
+
+ if (memchr(CA_PROP_DATA(p), 0, p->nbytes))
+ return CA_PROP_DATA(p);
+
+ return NULL;
+}
+
+int ca_context_play(ca_context_t *c, uint32_t id, ...) {
+ int ret;
+ va_list ap;
+
+ ca_return_val_if_fail(c, CA_ERROR_INVALID);
+ ca_return_val_if_fail(key, CA_ERROR_INVALID);
+
+ if (!c->opened)
+ if ((ret = ca_context_open(c)) < 0)
+ return ret;
+
+ ca_assert(c->opened);
+
+ /* make sure event.id is set */
+
+ va_start(ap, c);
+ for (;;) {
+ const char *key, *value;
+
+ if (!(key = va_arg(ap, const char *)))
+ break;
+
+ if (!(value = va_arg(ap, const char *))) {
+ va_end(ap);
+ return CA_ERROR_INVALID;
+ }
+
+ found = found || strcmp(key, CA_PROP_EVENT_ID) == 0;
+ }
+ va_end(ap);
+
+ found = found || ca_context_gets(c, CA_PROP_EVENT_ID);
+
+ if (!found)
+ return CA_ERROR_INVALID;
+
+ va_start(ap, id);
+ ret = driver_play(c, id, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+int ca_context_cancel(ca_context_t *c, uint32_ id) {
+
+ ca_return_val_if_fail(c, CA_ERROR_INVALID);
+ ca_return_val_if_fail(c->opened, CA_ERROR_STATE);
+
+ return driver_cancel(c, id);
+}
+
+int ca_context_cache(ca_context_t *c, ...) {
+ int ret;
+ va_list ap;
+ ca_bool_t found = FALSE;
+
+ ca_return_val_if_fail(c, CA_ERROR_INVALID);
+
+ if (!c->opened)
+ if ((ret = ca_context_open(c)) < 0)
+ return ret;
+
+ ca_assert(c->opened);
+
+ /* make sure event.id is set */
+
+ va_start(ap, c);
+ for (;;) {
+ const char *key, *value;
+
+ if (!(key = va_arg(ap, const char *)))
+ break;
+
+ if (!(value = va_arg(ap, const char *))) {
+ va_end(ap);
+ return CA_ERROR_INVALID;
+ }
+
+ found = found || strcmp(key, CA_PROP_EVENT_ID) == 0;
+ }
+ va_end(ap);
+
+ found = found || ca_context_gets(c, CA_PROP_EVENT_ID);
+
+ if (!found)
+ return CA_ERROR_INVALID;
+
+ va_start(ap, c);
+ ret = driver_cache(c, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+/** Return a human readable error */
+const char *ca_strerror(int code) {
+
+ const char * const error_table[-_CA_ERROR_MAX] = {
+ [-CA_SUCCESS] = "Success",
+ [-CA_ERROR_NOT_SUPPORTED] = "Operation not supported",
+ [-CA_ERROR_INVALID] = "Invalid argument",
+ [-CA_ERROR_STATE] = "Invalid state",
+ [-CA_ERROR_OOM] = "Out of memory",
+ [-CA_ERROR_NO_DRIVER] = "No such driver",
+ [-CA_ERROR_SYSTEM] = "System error"
+ };
+
+ ca_return_val_if_fail(code <= 0, NULL);
+ ca_return_val_if_fail(code > _SA_ERROR_MAX, NULL);
+
+ return error_table[-code];
+}
+
+#endif