summaryrefslogtreecommitdiff
path: root/src/waffle/core/wcore_attrib_list.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/waffle/core/wcore_attrib_list.c')
-rw-r--r--src/waffle/core/wcore_attrib_list.c237
1 files changed, 190 insertions, 47 deletions
diff --git a/src/waffle/core/wcore_attrib_list.c b/src/waffle/core/wcore_attrib_list.c
index 48d4b33..985e13a 100644
--- a/src/waffle/core/wcore_attrib_list.c
+++ b/src/waffle/core/wcore_attrib_list.c
@@ -28,76 +28,219 @@
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
+#include <string.h>
-int32_t
-wcore_attrib_list_length(const int32_t attrib_list[])
-{
- const int32_t *i = attrib_list;
+#include "wcore_error.h"
+#include "wcore_util.h"
+
+#define WCORE_ATTRIB_LIST_COMMON_FUNCS(T, \
+ length_func, \
+ get_func, \
+ get_with_default_func, \
+ update_func) \
+ \
+ size_t \
+ length_func(const T attrib_list[]) \
+ { \
+ const T *i = attrib_list; \
+ \
+ if (!attrib_list) { \
+ return 0; \
+ } \
+ \
+ while (*i) { \
+ i += 2; \
+ } \
+ \
+ return (i - attrib_list) / 2; \
+ } \
+ \
+ bool \
+ get_func(const T *attrib_list, \
+ T key, \
+ T *value) \
+ { \
+ if (!attrib_list) { \
+ return false; \
+ } \
+ \
+ for (size_t i = 0; attrib_list[i] != 0; i += 2) { \
+ if (attrib_list[i] == key) { \
+ *value = attrib_list[i + 1]; \
+ return true; \
+ } \
+ } \
+ \
+ return false; \
+ } \
+ \
+ bool \
+ get_with_default_func( \
+ const T attrib_list[], \
+ T key, \
+ T *value, \
+ T default_value) \
+ { \
+ if (get_func(attrib_list, key, value)) { \
+ return true; \
+ } else { \
+ *value = default_value; \
+ return false; \
+ } \
+ } \
+ \
+ bool \
+ update_func(T *attrib_list, \
+ T key, \
+ T value) \
+ { \
+ T *i = attrib_list; \
+ \
+ if (attrib_list == NULL) { \
+ return false; \
+ } \
+ \
+ while (*i != 0 && *i != key) { \
+ i += 2; \
+ } \
+ \
+ if (*i == key) { \
+ i[1] = value; \
+ return true; \
+ } else { \
+ return false; \
+ } \
+ }
+
+WCORE_ATTRIB_LIST_COMMON_FUNCS(int32_t,
+ wcore_attrib_list32_length,
+ wcore_attrib_list32_get,
+ wcore_attrib_list32_get_with_default,
+ wcore_attrib_list32_update)
- if (attrib_list == NULL)
- return 0;
+WCORE_ATTRIB_LIST_COMMON_FUNCS(intptr_t,
+ wcore_attrib_list_length,
+ wcore_attrib_list_get,
+ wcore_attrib_list_get_with_default,
+ wcore_attrib_list_update)
- while (*i != 0)
- i += 2;
+/// Given length of attribute list, calculate its size in bytes. Return false
+/// on arithemtic overflow.
+static bool
+wcore_attrib_list_get_size(size_t *size, size_t len) {
+ bool ok;
- return (int32_t) (i - attrib_list) / 2;
+ ok = wcore_mul_size(size, 2, len);
+ ok &= wcore_iadd_size(size, 1);
+ ok &= wcore_imul_size(size, sizeof(intptr_t));
+
+ return ok;
}
-bool
-wcore_attrib_list_get(
- const int32_t *attrib_list,
- int32_t key,
- int32_t *value)
+intptr_t*
+wcore_attrib_list_from_int32(const int32_t attrib_list32[])
{
- if (attrib_list == NULL)
- return false;
+ size_t len = 0;
+ size_t size = 0;
+ intptr_t *attrib_list = NULL;
- for (int i = 0; attrib_list[i] != 0; i += 2) {
- if (attrib_list[i] != key)
- continue;
+ len = wcore_attrib_list32_length(attrib_list32);
- *value = attrib_list[i + 1];
- return true;
+ if (!wcore_attrib_list_get_size(&size, len)) {
+ // Arithmetic overflow occurred, therefore we can't allocate the
+ // memory.
+ wcore_error(WAFFLE_ERROR_BAD_ALLOC);
+ return NULL;
}
- return false;
+ attrib_list = wcore_malloc(size);
+ if (!attrib_list) {
+ return NULL;
+ }
+
+ // Copy all key/value pairs.
+ for (size_t i = 0; i < 2 * len; ++i) {
+ attrib_list[i] = attrib_list32[i];
+ }
+
+ // Add terminal null.
+ attrib_list[2 * len] = 0;
+
+ return attrib_list;
}
-bool
-wcore_attrib_list_get_with_default(
- const int32_t attrib_list[],
- int32_t key,
- int32_t *value,
- int32_t default_value)
+intptr_t*
+wcore_attrib_list_copy(const intptr_t attrib_list[])
{
- if (wcore_attrib_list_get(attrib_list, key, value)) {
- return true;
- }
- else {
- *value = default_value;
- return false;
+ intptr_t *copy = NULL;
+
+ if (attrib_list) {
+ size_t len;
+ size_t size = 0;
+
+ len = wcore_attrib_list_length(attrib_list);
+
+ if (!wcore_attrib_list_get_size(&size, len)) {
+ // Arithmetic overflow occurred, therefore we can't allocate the
+ // memory.
+ wcore_error(WAFFLE_ERROR_BAD_ALLOC);
+ return NULL;
+ }
+
+ copy = wcore_malloc(size);
+ if (!copy) {
+ return NULL;
+ }
+
+ memcpy(copy, attrib_list, size);
+ } else {
+ copy = wcore_malloc(sizeof(intptr_t));
+ if (!copy) {
+ return NULL;
+ }
+
+ copy[0] = 0;
}
+
+ return copy;
}
bool
-wcore_attrib_list_update(
- int32_t *attrib_list,
- int32_t key,
- int32_t value)
+wcore_attrib_list_pop(
+ intptr_t attrib_list[],
+ intptr_t key,
+ intptr_t *value)
{
- int32_t *i = attrib_list;
+ // Address of key in attrib_list.
+ intptr_t *key_addr = NULL;
- if (attrib_list == NULL)
- return false;
+ // Address of the terminal zero in attrib_list.
+ intptr_t *end_addr = NULL;
- while (*i != 0 && *i != key)
- i += 2;
+ if (attrib_list == NULL) {
+ return false;
+ }
- if (*i == key) {
- i[1] = value;
- return true;
+ for (intptr_t *i = attrib_list; *i != 0; i += 2) {
+ if (i[0] == key) {
+ key_addr = i;
+ *value = i[1];
+ break;
+ }
}
- else {
+
+ if (!key_addr) {
return false;
}
+
+ end_addr = key_addr + 2; // Step to next pair.
+ while (*end_addr != 0) {
+ end_addr += 2; // Step to next pair.
+ }
+
+ // Move all key/value pairs located at or above (key_addr + 2), and
+ // move the terminal null too.
+ memmove(key_addr, key_addr + 2,
+ sizeof(intptr_t) * (end_addr - key_addr - 1));
+ return true;
}