diff options
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | TODO | 1 | ||||
-rw-r--r-- | src/mds-kbdc/callables.c | 188 | ||||
-rw-r--r-- | src/mds-kbdc/callables.h | 58 | ||||
-rw-r--r-- | src/mds-kbdc/compile-layout.c | 124 | ||||
-rw-r--r-- | src/mds-kbdc/variables.h | 2 |
6 files changed, 336 insertions, 40 deletions
@@ -33,7 +33,8 @@ OBJ_mds-registry_ = mds-registry util globals reexec registry signals \ OBJ_mds-kbdc_ = mds-kbdc globals raw-data builtin-functions string \ tree make-tree parse-error simplify-tree parsed \ process-includes validate-tree eliminate-dead-code \ - paths include-stack compile-layout variables + paths include-stack compile-layout variables \ + callables OBJ_mds-server = $(foreach O,$(OBJ_mds-server_),obj/mds-server/$(O).o) OBJ_mds-registry = $(foreach O,$(OBJ_mds-registry_),obj/mds-registry/$(O).o) @@ -16,6 +16,7 @@ Extra servers: tray retro-crt kbd2rat multikey keystick posmem nest mds meta keybounce slowkey keycue + a speech-to-keyboard server some server that hides the cursor when appropriate, such as when the user starts typing 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; + } +} + diff --git a/src/mds-kbdc/callables.h b/src/mds-kbdc/callables.h new file mode 100644 index 0000000..32b5467 --- /dev/null +++ b/src/mds-kbdc/callables.h @@ -0,0 +1,58 @@ +/** + * 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/>. + */ +#ifndef MDS_MDS_KBDC_CALLABLES_H +#define MDS_MDS_KBDC_CALLABLES_H + + +#include "tree.h" +#include "include-stack.h" + + +/** + * Destroy the callable storage + */ +void callables_terminate(void); + +/** + * 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); + +/** + * 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 + * @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); + + +#endif + diff --git a/src/mds-kbdc/compile-layout.c b/src/mds-kbdc/compile-layout.c index 01eb7e2..16d93a8 100644 --- a/src/mds-kbdc/compile-layout.c +++ b/src/mds-kbdc/compile-layout.c @@ -22,6 +22,7 @@ #include "builtin-functions.h" #include "string.h" #include "variables.h" +#include "callables.h" #include <stdlib.h> #include <errno.h> @@ -193,57 +194,103 @@ static int let(size_t variable, const char32_t* restrict string, const mds_kbdc_ } -static int set_macro(const mds_kbdc_tree_macro_t* restrict macro, +/** + * Store a macro + * + * @param macro The macro + * @param macro_include_stack The include-stack for the macro + * @return Zero on success, -1 on error + */ +static int set_macro(mds_kbdc_tree_macro_t* restrict macro, mds_kbdc_include_stack_t* macro_include_stack) { - (void) macro; - (void) macro_include_stack; - mds_kbdc_include_stack_free(macro_include_stack); - return 0; /* TODO */ + return callables_set(macro->name, 0, (mds_kbdc_tree_t*)macro, macro_include_stack); } -static int get_macro_lax(const char* restrict macro_name, const mds_kbdc_tree_macro_t** restrict macro, - mds_kbdc_include_stack_t** restrict macro_include_stack) + +/** + * Get a stored macro + * + * @param name The name of the macro, with suffix + * @param macro Output parameter for the macro, `NULL` if not found + * @param macro_include_stack Output parameter for the include-stack for the macro + */ +static void get_macro_lax(const char* restrict macro_name, mds_kbdc_tree_macro_t** restrict macro, + mds_kbdc_include_stack_t** restrict macro_include_stack) { - (void) macro_name; - (void) macro; - (void) macro_include_stack; - return 0; /* TODO */ + callables_get(macro_name, 0, (mds_kbdc_tree_t**)macro, macro_include_stack); } -static int get_macro(const mds_kbdc_tree_macro_call_t* restrict macro_call, - const mds_kbdc_tree_macro_t** restrict macro, + +/** + * Get a stored macro + * + * The function is similar to `get_macro_lax`, however, this fucntion + * will report an error if the macro has not yet been defined, and it + * will pretend that it has not yet been defined if the macro contained + * an error in an earlier called to it + * + * @param macro_call The macro-call + * @param macro Output parameter for the macro, `NULL` if not found or has an error + * @param macro_include_stack Output parameter for the include-stack for the macro + * @return Zero on success, -1 on error + */ +static int get_macro(mds_kbdc_tree_macro_call_t* restrict macro_call, + mds_kbdc_tree_macro_t** restrict macro, mds_kbdc_include_stack_t** restrict macro_include_stack) { - NEW_ERROR(macro_call, ERROR, "macro ‘%s’ as not been defined yet", macro_call->name); - /* return set `*macro = NULL` if `(*macro)->processed == PROCESS_LEVEL` */ - (void) macro; - (void) macro_include_stack; - return 0; /* TODO */ + get_macro_lax(macro_call->name, macro, macro_include_stack); + if (*macro == NULL) + { + NEW_ERROR(macro_call, ERROR, "macro ‘%s’ as not been defined yet", macro_call->name); + macro_call->processed = PROCESS_LEVEL; + return 0; + } + if ((*macro)->processed == PROCESS_LEVEL) + *macro = NULL; + return 0; pfail: return -1; } -static int set_function(const mds_kbdc_tree_function_t* restrict function, + +/** + * Store a function + * + * @param function The function + * @param function_include_stack The include-stack for the function + * @return Zero on success, -1 on error + */ +static int set_function(mds_kbdc_tree_function_t* restrict function, mds_kbdc_include_stack_t* function_include_stack) { - (void) function; - (void) function_include_stack; - mds_kbdc_include_stack_free(function_include_stack); - return 0; /* TODO */ + char* suffixless = function->name; + char* suffix_start = strchr(suffixless, '/'); + size_t arg_count = (size_t)atoll(suffix_start + 1); + int r; + + *suffix_start = '\0'; + r = callables_set(suffixless, arg_count, (mds_kbdc_tree_t*)function, function_include_stack); + return *suffix_start = '/', r; } -static int get_function_lax(const char* restrict function_name, size_t arg_count, - const mds_kbdc_tree_function_t** restrict function, - mds_kbdc_include_stack_t** restrict function_include_stack) + +/** + * Get a stored function + * + * @param name The name of the function, suffixless + * @param arg_count The number of arguments the function takes + * @param function Output parameter for the function, `NULL` if not found + * @param function_include_stack Output parameter for the include-stack for the function + */ +static void get_function_lax(const char* restrict function_name, size_t arg_count, + mds_kbdc_tree_function_t** restrict function, + mds_kbdc_include_stack_t** restrict function_include_stack) { - (void) function_name; - (void) arg_count; - (void) function; - (void) function_include_stack; - return 0; /* TODO */ + callables_get(function_name, arg_count, (mds_kbdc_tree_t**)function, function_include_stack); } + static int set_return_value(char32_t* restrict value) { free(value); @@ -610,10 +657,10 @@ static int compile_have_range(mds_kbdc_tree_assumption_have_range_t* restrict tr * @param tree The tree to evaluate * @return Zero on success, -1 on error, 1 if an undefined macro is used */ -static int check_marco_calls(const mds_kbdc_tree_t* restrict tree) +static int check_marco_calls(mds_kbdc_tree_t* restrict tree) { #define t(...) if (rc |= r = (__VA_ARGS__), r < 0) return r - const mds_kbdc_tree_macro_t* _macro; + mds_kbdc_tree_macro_t* _macro; mds_kbdc_include_stack_t* _macro_include_stack; void* data; int r, rc = 0; @@ -830,7 +877,7 @@ static int check_name_suffix(struct mds_kbdc_tree_callable* restrict tree) static int compile_function(mds_kbdc_tree_function_t* restrict tree) { #define t(expr) fail_if ((r = (expr), r < 0)); if (r) tree->processed = PROCESS_LEVEL - const mds_kbdc_tree_function_t* function; + mds_kbdc_tree_function_t* function; mds_kbdc_include_stack_t* function_include_stack; mds_kbdc_include_stack_t* our_include_stack = NULL; char* suffixless; @@ -857,7 +904,7 @@ static int compile_function(mds_kbdc_tree_function_t* restrict tree) /* Check that the function is not already defined, the include-stack is used in the error-clause as well as later when we list the function as defined. */ - fail_if (get_function_lax(suffixless, arg_count, &function, &function_include_stack)); + get_function_lax(suffixless, arg_count, &function, &function_include_stack); fail_if ((our_include_stack = mds_kbdc_include_stack_save(), our_include_stack == NULL)); if (function) { @@ -899,7 +946,7 @@ static int compile_function(mds_kbdc_tree_function_t* restrict tree) static int compile_macro(mds_kbdc_tree_macro_t* restrict tree) { #define t(expr) fail_if ((r = (expr), r < 0)); if (r) tree->processed = PROCESS_LEVEL - const mds_kbdc_tree_macro_t* macro; + mds_kbdc_tree_macro_t* macro; mds_kbdc_include_stack_t* macro_include_stack; mds_kbdc_include_stack_t* our_include_stack = NULL; int r, saved_errno; @@ -911,7 +958,7 @@ static int compile_macro(mds_kbdc_tree_macro_t* restrict tree) the include-stack is used in the error-clause as well as later when we list the macro as defined. */ fail_if ((our_include_stack = mds_kbdc_include_stack_save(), our_include_stack == NULL)); - t (get_macro_lax(tree->name, ¯o, ¯o_include_stack)); + get_macro_lax(tree->name, ¯o, ¯o_include_stack); if (macro) { NEW_ERROR(tree, ERROR, "macro ‘%s’ is already defined", tree->name); @@ -1341,7 +1388,7 @@ static int compile_macro_call(mds_kbdc_tree_macro_call_t* restrict tree) { mds_kbdc_tree_t* arg = NULL; mds_kbdc_tree_t* arg_; - const mds_kbdc_tree_macro_t* macro; + mds_kbdc_tree_macro_t* macro; mds_kbdc_include_stack_t* macro_include_stack; mds_kbdc_include_stack_t* our_include_stack = NULL; size_t variable; @@ -1479,6 +1526,7 @@ int compile_layout(mds_kbdc_parsed_t* restrict result_) saved_errno = errno; mds_kbdc_include_stack_end(); variables_terminate(); + callables_terminate(); errno = saved_errno; return r; } diff --git a/src/mds-kbdc/variables.h b/src/mds-kbdc/variables.h index 26d3c72..c01c163 100644 --- a/src/mds-kbdc/variables.h +++ b/src/mds-kbdc/variables.h @@ -19,7 +19,7 @@ #define MDS_MDS_KBDC_VARIABLES_H -#include "parsed.h" +#include "tree.h" #include "string.h" |