diff options
Diffstat (limited to '')
-rw-r--r-- | src/mds-kbdc/callables.c | 188 |
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; + } +} + |