aboutsummaryrefslogtreecommitdiffstats
path: root/src/mds-kbdc/callables.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/mds-kbdc/callables.c188
1 files changed, 188 insertions, 0 deletions
diff --git a/src/mds-kbdc/callables.c b/src/mds-kbdc/callables.c
new file mode 100644
index 0000000..4a87fd2
--- /dev/null
+++ b/src/mds-kbdc/callables.c
@@ -0,0 +1,188 @@
+/**
+ * mds — A micro-display server
+ * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "callables.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+
+
+/**
+ * Map, by index, from argument count, to list of callable's names
+ */
+static char*** restrict names = NULL;
+
+/**
+ * If `callable_list[callabes[i][j]]` and `callable_include_stack_list[callabes[i][j]]`
+ * describe the callable named by `named[i][j]` with either `i` parameters, or the
+ * number of parameters specified by the suffix in `named[i][j]`
+ */
+static size_t** restrict callables = NULL;
+
+/**
+ * Map the the number of elements in the, by index, corresponding element in `names`
+ */
+static size_t* restrict bucket_sizes = NULL;
+
+/**
+ * List of callables
+ */
+static mds_kbdc_tree_t** restrict callable_list = NULL;
+
+/**
+ * List of callables' include-stacks
+ */
+static mds_kbdc_include_stack_t** restrict callable_include_stack_list = NULL;
+
+/**
+ * The number of buckets in `names` and `bucket_sizes`
+ */
+static size_t buckets = 0;
+
+/**
+ * The index of the next item in `callable_list` and `callable_include_stack_list`
+ */
+static size_t list_ptr = 0;
+
+
+
+/**
+ * Destroy the callable storage
+ */
+void callables_terminate(void)
+{
+ size_t i, j, n;
+ char** bucket;
+ for (i = 0; i < list_ptr; i++)
+ {
+ bucket = names[i];
+ for (j = 0, n = bucket_sizes[i]; j < n; j++)
+ free(bucket[j]);
+ free(bucket);
+ }
+ for (i = 0; i < list_ptr; i++)
+ mds_kbdc_include_stack_free(callable_include_stack_list[i]);
+ free(names), names = NULL;
+ free(bucket_sizes), bucket_sizes = NULL;
+ free(callable_list), callable_list = NULL;
+ free(callable_include_stack_list), callable_include_stack_list = NULL;
+ buckets = list_ptr = 0;
+}
+
+
+/**
+ * Store a callable
+ *
+ * @param name The name of the callable
+ * @param arg_count The number of arguments the callable takes
+ * if `name` is suffixless, otherwise zero
+ * @param callable The callable
+ * @param callable_include_stack The include-stack for the callable
+ * @return Zero on success, -1 on error
+ */
+int callables_set(const char* restrict name, size_t arg_count, mds_kbdc_tree_t* restrict callable,
+ mds_kbdc_include_stack_t* restrict callable_include_stack)
+{
+#define yrealloc(var, elements, type) \
+ (new_##var = realloc(var, (elements) * sizeof(type)), \
+ (new_##var == NULL) ? -1 : (var = new_##var, new_##var = NULL, 0))
+
+ char* dupname = NULL;
+ char*** new_names = NULL;
+ size_t** new_callables = NULL;
+ size_t* new_bucket_sizes = NULL;
+ char** old_names = NULL;
+ size_t* old_callables = NULL;
+ mds_kbdc_tree_t** new_callable_list = NULL;
+ mds_kbdc_include_stack_t** new_callable_include_stack_list = NULL;
+ int saved_errno;
+
+ fail_if ((dupname = strdup(name), dupname == NULL));
+
+ if (arg_count >= buckets)
+ {
+ fail_if (yrealloc(names, arg_count + 1, char**));
+ fail_if (yrealloc(callables, arg_count + 1, size_t*));
+ fail_if (yrealloc(bucket_sizes, arg_count + 1, size_t));
+ memset(names, 0, (arg_count + 1 - buckets) * sizeof(char**));
+ memset(callables, 0, (arg_count + 1 - buckets) * sizeof(size_t*));
+ memset(bucket_sizes, 0, (arg_count + 1 - buckets) * sizeof(size_t));
+ buckets = arg_count + 1;
+ }
+
+ fail_if (xxrealloc(old_names, names[arg_count], bucket_sizes[arg_count] + 1, char*));
+ fail_if (xxrealloc(old_callables, callables[arg_count], bucket_sizes[arg_count] + 1, size_t));
+
+ names[arg_count][bucket_sizes[arg_count]] = dupname, dupname = NULL;;
+ callables[arg_count][bucket_sizes[arg_count]] = list_ptr;
+ bucket_sizes[arg_count]++;
+
+ fail_if (yrealloc(callable_list, list_ptr + 1, mds_kbdc_tree_t*));
+ fail_if (yrealloc(callable_include_stack_list, list_ptr + 1, mds_kbdc_include_stack_t*));
+
+ callable_list[list_ptr] = callable;
+ callable_include_stack_list[list_ptr] = callable_include_stack;
+ list_ptr++;
+
+ return 0;
+ pfail:
+ saved_errno = errno;
+ free(dupname);
+ free(new_names);
+ free(new_callables);
+ free(new_bucket_sizes);
+ free(new_callable_list);
+ free(new_callable_include_stack_list);
+ if (old_names)
+ names[arg_count] = old_names;
+ if (old_callables)
+ callables[arg_count] = old_callables;
+ return errno = saved_errno, -1;
+#undef yrealloc
+}
+
+
+/**
+ * Get a stored callable
+ *
+ * @param name The name of the callable
+ * @param arg_count The number of arguments the callable takes
+ * if `name` is suffixless, otherwise zero
+ * @param callable Output parameter for the callable, `NULL` if not found
+ * @param callable_include_stack Output parameter for the include-stack for the callable
+ */
+void callables_get(const char* restrict name, size_t arg_count, mds_kbdc_tree_t** restrict callable,
+ mds_kbdc_include_stack_t** restrict callable_include_stack)
+{
+ char** restrict names_ = names[arg_count];
+ size_t i, n = bucket_sizes[arg_count];
+
+ *callable = NULL;
+ *callable_include_stack = NULL;
+
+ for (i = 0; i < n; i++)
+ {
+ if (strcmp(names_[i], name))
+ continue;
+ i = callables[arg_count][i];
+ *callable = callable_list[i];
+ *callable_include_stack = callable_include_stack_list[i];
+ return;
+ }
+}
+