From 9ed21175ac00f57f6abf3da84e82098e68fa3e94 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sun, 5 Nov 2017 14:50:38 +0100 Subject: Work on changing style MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- src/libmdsserver/client-list.c | 197 +- src/libmdsserver/client-list.h | 4 +- src/libmdsserver/fd-table.c | 326 +-- src/libmdsserver/fd-table.h | 4 +- src/libmdsserver/hash-list.h | 581 +++-- src/libmdsserver/hash-table.c | 581 +++-- src/libmdsserver/linked-list.c | 532 ++--- src/libmdsserver/macros.h | 458 ++-- src/libmdsserver/mds-message.c | 727 +++--- src/libmdsserver/util.c | 867 +++---- src/mds-base.h | 6 +- src/mds-clipboard.h | 12 +- src/mds-colour.h | 5 +- src/mds-echo.c | 3 +- src/mds-echo.h | 1 - src/mds-kbdc/builtin-functions.c | 337 +-- src/mds-kbdc/builtin-functions.h | 6 +- src/mds-kbdc/call-stack.c | 180 +- src/mds-kbdc/call-stack.h | 9 +- src/mds-kbdc/callables.c | 191 +- src/mds-kbdc/callables.h | 9 +- src/mds-kbdc/compile-layout.c | 3745 +++++++++++++++---------------- src/mds-kbdc/compile-layout.h | 3 +- src/mds-kbdc/eliminate-dead-code.c | 155 +- src/mds-kbdc/eliminate-dead-code.h | 3 +- src/mds-kbdc/globals.c | 3 +- src/mds-kbdc/globals.h | 3 +- src/mds-kbdc/include-stack.c | 232 +- src/mds-kbdc/include-stack.h | 65 +- src/mds-kbdc/make-tree.c | 1705 +++++++------- src/mds-kbdc/make-tree.h | 3 +- src/mds-kbdc/mds-kbdc.c | 80 +- src/mds-kbdc/mds-kbdc.h | 1 - src/mds-kbdc/parse-error.c | 210 +- src/mds-kbdc/parse-error.h | 109 +- src/mds-kbdc/parsed.c | 168 +- src/mds-kbdc/parsed.h | 246 +- src/mds-kbdc/paths.c | 222 +- src/mds-kbdc/paths.h | 7 +- src/mds-kbdc/process-includes.c | 397 ++-- src/mds-kbdc/process-includes.h | 3 +- src/mds-kbdc/raw-data.c | 708 +++--- src/mds-kbdc/raw-data.h | 86 +- src/mds-kbdc/simplify-tree.c | 1283 ++++++----- src/mds-kbdc/simplify-tree.h | 3 +- src/mds-kbdc/string.c | 166 +- src/mds-kbdc/string.h | 12 +- src/mds-kbdc/tree.c | 731 +++--- src/mds-kbdc/tree.h | 720 +++--- src/mds-kbdc/validate-tree.c | 514 +++-- src/mds-kbdc/validate-tree.h | 3 +- src/mds-kbdc/variables.c | 247 +- src/mds-kbdc/variables.h | 12 +- src/mds-kkbd.c | 2 +- src/mds-libinput.h | 1 - src/mds-registry/mds-registry.c | 3 +- src/mds-registry/registry.c | 5 +- src/mds-registry/signals.c | 3 +- src/mds-registry/slave.h | 4 +- src/mds-registry/util.c | 6 +- src/mds-respawn.h | 5 +- src/mds-server/client.h | 4 +- src/mds-server/globals.h | 1 - src/mds-server/interception-condition.h | 4 +- src/mds-server/interceptors.h | 2 +- src/mds-server/multicast.h | 4 +- src/mds-server/queued-interception.h | 4 +- src/mds-vt.c | 2 +- src/mds.h | 7 +- 69 files changed, 8415 insertions(+), 8523 deletions(-) diff --git a/src/libmdsserver/client-list.c b/src/libmdsserver/client-list.c index 19eaf5a..02d555e 100644 --- a/src/libmdsserver/client-list.c +++ b/src/libmdsserver/client-list.c @@ -27,7 +27,7 @@ * The default initial capacity */ #ifndef CLIENT_LIST_DEFAULT_INITIAL_CAPACITY -#define CLIENT_LIST_DEFAULT_INITIAL_CAPACITY 8 +# define CLIENT_LIST_DEFAULT_INITIAL_CAPACITY 8 #endif @@ -38,19 +38,19 @@ * @param value The value to be rounded up to a power of two * @return The nearest, but not smaller, power of two */ -__attribute__((const)) -static size_t to_power_of_two(size_t value) +static size_t __attribute__((const)) +to_power_of_two(size_t value) { - value -= 1; - value |= value >> 1; - value |= value >> 2; - value |= value >> 4; - value |= value >> 8; - value |= value >> 16; + value -= 1; + value |= value >> 1; + value |= value >> 2; + value |= value >> 4; + value |= value >> 8; + value |= value >> 16; #if SIZE_MAX == UINT64_MAX - value |= value >> 32; + value |= value >> 32; #endif - return value + 1; + return value + 1; } @@ -61,21 +61,22 @@ static size_t to_power_of_two(size_t value) * @param capacity The minimum initial capacity of the client list, 0 for default * @return Non-zero on error, `errno` will have been set accordingly */ -int client_list_create(client_list_t* restrict this, size_t capacity) +int +client_list_create(client_list_t *restrict this, size_t capacity) { - /* Use default capacity of zero is specified. */ - if (capacity == 0) - capacity = CLIENT_LIST_DEFAULT_INITIAL_CAPACITY; - - /* Initialise the client list. */ - this->capacity = capacity = to_power_of_two(capacity); - this->size = 0; - this->clients = NULL; - fail_if (xmalloc(this->clients, capacity, uint64_t)); - - return 0; - fail: - return -1; + /* Use default capacity of zero is specified. */ + if (!capacity) + capacity = CLIENT_LIST_DEFAULT_INITIAL_CAPACITY; + + /* Initialise the client list. */ + this->capacity = capacity = to_power_of_two(capacity); + this->size = 0; + this->clients = NULL; + fail_if (xmalloc(this->clients, capacity, uint64_t)); + + return 0; +fail: + return -1; } @@ -85,10 +86,11 @@ int client_list_create(client_list_t* restrict this, size_t capacity) * * @param this The client list */ -void client_list_destroy(client_list_t* restrict this) +void +client_list_destroy(client_list_t *restrict this) { - free(this->clients); - this->clients = NULL; + free(this->clients); + this->clients = NULL; } @@ -99,17 +101,18 @@ void client_list_destroy(client_list_t* restrict this) * @param out Memory slot in which to store the new client list * @return Non-zero on error, `errno` will have been set accordingly */ -int client_list_clone(const client_list_t* restrict this, client_list_t* restrict out) +int +client_list_clone(const client_list_t *restrict this, client_list_t *restrict out) { - fail_if (xmemdup(out->clients, this->clients, this->capacity, uint64_t)); - - out->capacity = this->capacity; - out->size = this->size; - - return 0; - - fail: - return -1; + fail_if (xmemdup(out->clients, this->clients, this->capacity, uint64_t)); + + out->capacity = this->capacity; + out->size = this->size; + + return 0; + +fail: + return -1; } @@ -120,23 +123,23 @@ int client_list_clone(const client_list_t* restrict this, client_list_t* restric * @param client The client to add * @return Non-zero on error, `errno` will be set accordingly */ -int client_list_add(client_list_t* restrict this, uint64_t client) +int +client_list_add(client_list_t *restrict this, uint64_t client) { - if (this->size == this->capacity) - { - uint64_t* old = this->clients; - if (xrealloc(old, this->capacity <<= 1, uint64_t)) - { - this->capacity >>= 1; - this->clients = old; - fail_if (1); + uint64_t* old; + if (this->size == this->capacity) { + old = this->clients; + if (xrealloc(old, this->capacity <<= 1, uint64_t)) { + this->capacity >>= 1; + this->clients = old; + fail_if (1); + } } - } - - this->clients[this->size++] = client; - return 0; - fail: - return -1; + + this->clients[this->size++] = client; + return 0; +fail: + return -1; } @@ -146,29 +149,27 @@ int client_list_add(client_list_t* restrict this, uint64_t client) * @param this The list * @param client The client to remove */ -void client_list_remove(client_list_t* restrict this, uint64_t client) +void +client_list_remove(client_list_t *restrict this, uint64_t client) { - size_t i; - for (i = 0; i < this->size; i++) - { - if (this->clients[i] == client) - { - size_t n = (--(this->size) - i) * sizeof(uint64_t); - memmove(this->clients + i, this->clients + i + 1, n); - - if (this->size << 1 <= this->capacity) - { - uint64_t* old = this->clients; - if (xrealloc(old, this->capacity >>= 1, uint64_t)) - { - this->capacity <<= 1; - this->clients = old; + size_t i, n; + uint64_t *old; + for (i = 0; i < this->size; i++) { + if (this->clients[i] == client) { + n = (--(this->size) - i) * sizeof(uint64_t); + memmove(this->clients + i, this->clients + i + 1, n); + + if (this->size << 1 <= this->capacity) { + old = this->clients; + if (xrealloc(old, this->capacity >>= 1, uint64_t)) { + this->capacity <<= 1; + this->clients = old; + } + } + + return; } - } - - return; } - } } @@ -178,9 +179,10 @@ void client_list_remove(client_list_t* restrict this, uint64_t client) * @param this The list * @return The number of bytes to allocate to the output buffer */ -size_t client_list_marshal_size(const client_list_t* restrict this) +size_t +client_list_marshal_size(const client_list_t *restrict this) { - return 2 * sizeof(size_t) + this->size * sizeof(uint64_t) + sizeof(int); + return 2 * sizeof(size_t) + this->size * sizeof(uint64_t) + sizeof(int); } @@ -190,13 +192,14 @@ size_t client_list_marshal_size(const client_list_t* restrict this) * @param this The list * @param data Output buffer for the marshalled data */ -void client_list_marshal(const client_list_t* restrict this, char* restrict data) +void +client_list_marshal(const client_list_t *restrict this, char *restrict data) { - buf_set_next(data, int, CLIENT_LIST_T_VERSION); - buf_set_next(data, size_t, this->capacity); - buf_set_next(data, size_t, this->size); - - memcpy(data, this->clients, this->size * sizeof(uint64_t)); + buf_set_next(data, int, CLIENT_LIST_T_VERSION); + buf_set_next(data, size_t, this->capacity); + buf_set_next(data, size_t, this->size); + + memcpy(data, this->clients, this->size * sizeof(uint64_t)); } @@ -208,21 +211,21 @@ void client_list_marshal(const client_list_t* restrict this, char* restrict data * @return Non-zero on error, `errno` will be set accordingly. * Destroy the list on error. */ -int client_list_unmarshal(client_list_t* restrict this, char* restrict data) +int +client_list_unmarshal(client_list_t *restrict this, char *restrict data) { - /* buf_get(data, int, 0, CLIENT_LIST_T_VERSION); */ - buf_next(data, int, 1); - - this->clients = NULL; - - buf_get_next(data, size_t, this->capacity); - buf_get_next(data, size_t, this->size); - - fail_if (xmalloc(this->clients, this->capacity, uint64_t)); - memcpy(this->clients, data, this->size * sizeof(uint64_t)); - - return 0; - fail: - return -1; -} + /* buf_get(data, int, 0, CLIENT_LIST_T_VERSION); */ + buf_next(data, int, 1); + + this->clients = NULL; + + buf_get_next(data, size_t, this->capacity); + buf_get_next(data, size_t, this->size); + fail_if (xmalloc(this->clients, this->capacity, uint64_t)); + memcpy(this->clients, data, this->size * sizeof(uint64_t)); + + return 0; +fail: + return -1; +} diff --git a/src/libmdsserver/client-list.h b/src/libmdsserver/client-list.h index 4d2bfa7..ffe828a 100644 --- a/src/libmdsserver/client-list.h +++ b/src/libmdsserver/client-list.h @@ -30,8 +30,7 @@ /** * Dynamic array of client ID:s */ -typedef struct client_list -{ +typedef struct client_list { /** * The size of the array */ @@ -46,7 +45,6 @@ typedef struct client_list * Stored client ID:s */ uint64_t *clients; - } client_list_t; diff --git a/src/libmdsserver/fd-table.c b/src/libmdsserver/fd-table.c index 1db2d87..fafaa65 100644 --- a/src/libmdsserver/fd-table.c +++ b/src/libmdsserver/fd-table.c @@ -31,29 +31,30 @@ * @param initial_capacity The initial capacity of the table * @return Non-zero on error, `errno` will have been set accordingly */ -int fd_table_create_tuned(fd_table_t* restrict this, size_t initial_capacity) +int +fd_table_create_tuned(fd_table_t *restrict this, size_t initial_capacity) { - size_t bitcap; - - this->capacity = initial_capacity ? initial_capacity : 1; - this->size = 0; - - this->values = NULL; - this->used = NULL; - this->value_comparator = NULL; - - /* It is important that both allocations are done with calloc: - `this->used` must set all keys as unused at the initial state, - `this->values` must be initialised for marshaling and it helps - the time overhead of `fd_table_contains_value`. */ - - bitcap = (this->capacity + 63) / 64; - fail_if (xcalloc(this->used, bitcap, size_t)); - fail_if (xcalloc(this->values, this->capacity, size_t)); - - return 0; - fail: - return -1; + size_t bitcap; + + this->capacity = initial_capacity ? initial_capacity : 1; + this->size = 0; + + this->values = NULL; + this->used = NULL; + this->value_comparator = NULL; + + /* It is important that both allocations are done with calloc: + `this->used` must set all keys as unused at the initial state, + `this->values` must be initialised for marshaling and it helps + the time overhead of `fd_table_contains_value`. */ + + bitcap = (this->capacity + 63) / 64; + fail_if (xcalloc(this->used, bitcap, size_t)); + fail_if (xcalloc(this->values, this->capacity, size_t)); + + return 0; +fail: + return -1; } @@ -65,20 +66,20 @@ int fd_table_create_tuned(fd_table_t* restrict this, size_t initial_capacity) * @param keys_freer Function that frees a key, `NULL` if keys should not be freed * @param values_freer Function that frees a value, `NULL` if value should not be freed */ -void fd_table_destroy(fd_table_t* restrict this, free_func* key_freer, free_func* value_freer) +void +fd_table_destroy(fd_table_t *restrict this, free_func *key_freer, free_func *value_freer) { - if (((key_freer != NULL) || (value_freer != NULL)) && (this->used != NULL) && (this->values != NULL)) - { - size_t i; - for (i = 0; i < this->capacity; i++) - if (this->used[i / 64] & ((uint64_t)1 << (i % 64))) - { - if (key_freer != NULL) key_freer(i); - if (value_freer != NULL) value_freer(this->values[i]); - } - } - free(this->values); - free(this->used); + size_t i; + if ((key_freer || value_freer) && this->used && this->values) { + for (i = 0; i < this->capacity; i++) { + if (this->used[i / 64] & ((uint64_t)1 << (i % 64))) { + if (key_freer) key_freer(i); + if (value_freer) value_freer(this->values[i]); + } + } + } + free(this->values); + free(this->used); } @@ -89,24 +90,22 @@ void fd_table_destroy(fd_table_t* restrict this, free_func* key_freer, free_func * @param value The value * @return Whether the value is stored in the table */ -int fd_table_contains_value(const fd_table_t* restrict this, size_t value) +int +fd_table_contains_value(const fd_table_t *restrict this, size_t value) { - size_t i; - if (this->value_comparator == NULL) - { - for (i = 0; i < this->capacity; i++) - if (this->values[i] == value) - if (this->used[i / 64] & ((uint64_t)1 << (i % 64))) - return 1; - } - else - { - for (i = 0; i < this->capacity; i++) - if (this->used[i / 64] & ((uint64_t)1 << (i % 64))) - if (this->value_comparator(this->values[i], value)) - return 1; - } - return 0; + size_t i; + if (!this->value_comparator) { + for (i = 0; i < this->capacity; i++) + if (this->values[i] == value) + if (this->used[i / 64] & ((uint64_t)1 << (i % 64))) + return 1; + } else { + for (i = 0; i < this->capacity; i++) + if (this->used[i / 64] & ((uint64_t)1 << (i % 64))) + if (this->value_comparator(this->values[i], value)) + return 1; + } + return 0; } @@ -117,9 +116,10 @@ int fd_table_contains_value(const fd_table_t* restrict this, size_t value) * @param key The key * @return Whether the key is used */ -int fd_table_contains_key(const fd_table_t* restrict this, int key) +int +fd_table_contains_key(const fd_table_t *restrict this, int key) { - return ((size_t)key < this->capacity) && (this->used[key / 64] & ((uint64_t)1 << (key % 64))); + return (size_t)key < this->capacity && (this->used[key / 64] & ((uint64_t)1 << (key % 64))); } @@ -130,11 +130,10 @@ int fd_table_contains_key(const fd_table_t* restrict this, int key) * @param key The key associated with the value * @return The value associated with the key, 0 if the key was not used */ -size_t fd_table_get(const fd_table_t* restrict this, int key) +size_t +fd_table_get(const fd_table_t *restrict this, int key) { - if (fd_table_contains_key(this, key) == 0) - return 0; - return this->values[key]; + return fd_table_contains_key(this, key) ? this->values[key] : 0; } @@ -147,55 +146,53 @@ size_t fd_table_get(const fd_table_t* restrict this, int key) * @return The previous value associated with the key, 0 if the key was not used. * 0 will also be returned on error, check the `errno` variable. */ -size_t fd_table_put(fd_table_t* restrict this, int key, size_t value) +size_t +fd_table_put(fd_table_t *restrict this, int key, size_t value) { - /* Override current value if the key is already used. */ - if (fd_table_contains_key(this, key)) - { - size_t rc = fd_table_get(this, key); - this->values[key] = value; - return rc; - } - - /* Grow the table if it is too small. */ - errno = 0; - if ((size_t)key >= this->capacity) - { - size_t* old_values = this->values; - size_t old_bitcap, new_bitcap; - if (xrealloc(this->values, this->capacity << 1, size_t)) - { - this->values = old_values; - fail_if (1); + size_t rc, old_bitcap, new_bitcap, *old_values; + uint64_t *old_used; + + /* Override current value if the key is already used. */ + if (fd_table_contains_key(this, key)) { + rc = fd_table_get(this, key); + this->values[key] = value; + return rc; } + + /* Grow the table if it is too small. */ + errno = 0; + if ((size_t)key >= this->capacity) { + old_values = this->values; + if (xrealloc(this->values, this->capacity << 1, size_t)) { + this->values = old_values; + fail_if (1); + } + + memset(this->values + this->capacity, 0, this->capacity * sizeof(size_t)); - memset(this->values + this->capacity, 0, this->capacity * sizeof(size_t)); - - old_bitcap = (this->capacity + 63) / 64; - this->capacity <<= 1; - new_bitcap = (this->capacity + 63) / 64; - - if (new_bitcap > old_bitcap) - { - uint64_t* old_used = this->used; - if (xrealloc(this->used, new_bitcap, size_t)) - { - this->used = old_used; - this->capacity >>= 1; - fail_if (1); - } - - memset(this->used + old_bitcap, 0, (new_bitcap - old_bitcap) * sizeof(uint64_t)); + old_bitcap = (this->capacity + 63) / 64; + this->capacity <<= 1; + new_bitcap = (this->capacity + 63) / 64; + + if (new_bitcap > old_bitcap) { + old_used = this->used; + if (xrealloc(this->used, new_bitcap, size_t)) { + this->used = old_used; + this->capacity >>= 1; + fail_if (1); + } + + memset(this->used + old_bitcap, 0, (new_bitcap - old_bitcap) * sizeof(uint64_t)); + } } - } - - /* Store the entry. */ - this->used[key / 64] |= (uint64_t)1 << (key % 64); - this->values[key] = value; - this->size++; - return 0; - fail: - return 0; + + /* Store the entry. */ + this->used[key / 64] |= (uint64_t)1 << (key % 64); + this->values[key] = value; + this->size++; + return 0; +fail: + return 0; } @@ -206,15 +203,15 @@ size_t fd_table_put(fd_table_t* restrict this, int key, size_t value) * @param key The key of the entry to remove * @return The previous value associated with the key, 0 if the key was not used */ -size_t fd_table_remove(fd_table_t* restrict this, int key) +size_t +fd_table_remove(fd_table_t *restrict this, int key) { - size_t rc = fd_table_get(this, key); - if (rc && fd_table_contains_key(this, key)) - { - this->used[key / 64] &= ~((uint64_t)1 << (key % 64)); - this->size--; - } - return rc; + size_t rc = fd_table_get(this, key); + if (rc && fd_table_contains_key(this, key)) { + this->used[key / 64] &= ~((uint64_t)1 << (key % 64)); + this->size--; + } + return rc; } @@ -223,12 +220,13 @@ size_t fd_table_remove(fd_table_t* restrict this, int key) * * @param this The fd table */ -void fd_table_clear(fd_table_t* restrict this) +void +fd_table_clear(fd_table_t *restrict this) { - size_t bitcap; - this->size = 0; - bitcap = (this->capacity + 63) / 64; - memset(this->used, 0, bitcap * sizeof(uint64_t)); + size_t bitcap; + this->size = 0; + bitcap = (this->capacity + 63) / 64; + memset(this->used, 0, bitcap * sizeof(uint64_t)); } @@ -238,10 +236,11 @@ void fd_table_clear(fd_table_t* restrict this) * @param this The fd table * @return The number of bytes to allocate to the output buffer */ -size_t fd_table_marshal_size(const fd_table_t* restrict this) +size_t +fd_table_marshal_size(const fd_table_t *restrict this) { - size_t bitcap = (this->capacity + 63) / 64; - return (this->capacity + 2) * sizeof(size_t) + bitcap * sizeof(uint64_t) + sizeof(int); + size_t bitcap = (this->capacity + 63) / 64; + return (this->capacity + 2) * sizeof(size_t) + bitcap * sizeof(uint64_t) + sizeof(int); } @@ -251,18 +250,19 @@ size_t fd_table_marshal_size(const fd_table_t* restrict this) * @param this The fd table * @param data Output buffer for the marshalled data */ -void fd_table_marshal(const fd_table_t* restrict this, char* restrict data) +void +fd_table_marshal(const fd_table_t *restrict this, char *restrict data) { - size_t bitcap = (this->capacity + 63) / 64; - - buf_set_next(data, int, FD_TABLE_T_VERSION); - buf_set_next(data, size_t, this->capacity); - buf_set_next(data, size_t, this->size); - - memcpy(data, this->values, this->capacity * sizeof(size_t)); - buf_next(data, size_t, this->capacity); - - memcpy(data, this->used, bitcap * sizeof(uint64_t)); + size_t bitcap = (this->capacity + 63) / 64; + + buf_set_next(data, int, FD_TABLE_T_VERSION); + buf_set_next(data, size_t, this->capacity); + buf_set_next(data, size_t, this->size); + + memcpy(data, this->values, this->capacity * sizeof(size_t)); + buf_next(data, size_t, this->capacity); + + memcpy(data, this->used, bitcap * sizeof(uint64_t)); } @@ -275,38 +275,38 @@ void fd_table_marshal(const fd_table_t* restrict this, char* restrict data) * @return Non-zero on error, `errno` will be set accordingly. * Destroy the table on error. */ -int fd_table_unmarshal(fd_table_t* restrict this, char* restrict data, remap_func* remapper) +int +fd_table_unmarshal(fd_table_t *restrict this, char *restrict data, remap_func *remapper) { - size_t bitcap; - size_t i; - - /* buf_get(data, int, 0, FD_TABLE_T_VERSION) */ - buf_next(data, int, 1); - - buf_get_next(data, size_t, this->capacity); - buf_get_next(data, size_t, this->size); - - this->values = NULL; - this->used = NULL; - this->value_comparator = NULL; - - fail_if (xmalloc(this->values, this->capacity, size_t)); - - bitcap = (this->capacity + 63) / 64; - fail_if (xmalloc(this->used, bitcap, size_t)); - - memcpy(this->values, data, this->capacity * sizeof(size_t)); - buf_next(data, size_t, this->capacity); - - memcpy(this->used, data, bitcap * sizeof(uint64_t)); - - if (remapper != NULL) - for (i = 0; i < this->capacity; i++) - if (this->used[i / 64] & ((uint64_t)1 << (i % 64))) - this->values[i] = remapper(this->values[i]); - - return 0; - fail: - return -1; -} + size_t bitcap; + size_t i; + + /* buf_get(data, int, 0, FD_TABLE_T_VERSION) */ + buf_next(data, int, 1); + + buf_get_next(data, size_t, this->capacity); + buf_get_next(data, size_t, this->size); + this->values = NULL; + this->used = NULL; + this->value_comparator = NULL; + + fail_if (xmalloc(this->values, this->capacity, size_t)); + + bitcap = (this->capacity + 63) / 64; + fail_if (xmalloc(this->used, bitcap, size_t)); + + memcpy(this->values, data, this->capacity * sizeof(size_t)); + buf_next(data, size_t, this->capacity); + + memcpy(this->used, data, bitcap * sizeof(uint64_t)); + + if (remapper) + for (i = 0; i < this->capacity; i++) + if (this->used[i / 64] & ((uint64_t)1 << (i % 64))) + this->values[i] = remapper(this->values[i]); + + return 0; +fail: + return -1; +} diff --git a/src/libmdsserver/fd-table.h b/src/libmdsserver/fd-table.h index e0b3a09..e484937 100644 --- a/src/libmdsserver/fd-table.h +++ b/src/libmdsserver/fd-table.h @@ -30,8 +30,7 @@ /** * Value lookup table optimised for file descriptors as keys */ -typedef struct fd_table -{ +typedef struct fd_table { /** * The table's capacity, i.e. how many entries that can be stored, * in total, before its internal table needs to grow @@ -61,7 +60,6 @@ typedef struct fd_table * Be aware, this variable cannot be marshalled */ compare_func *value_comparator; - } fd_table_t; diff --git a/src/libmdsserver/hash-list.h b/src/libmdsserver/hash-list.h index abcbb74..2087bce 100644 --- a/src/libmdsserver/hash-list.h +++ b/src/libmdsserver/hash-list.h @@ -34,7 +34,7 @@ * The default initial capacity */ #ifndef HASH_LIST_DEFAULT_INITIAL_CAPACITY -# define HASH_LIST_DEFAULT_INITIAL_CAPACITY 128 +# define HASH_LIST_DEFAULT_INITIAL_CAPACITY 128 #endif /** @@ -61,15 +61,15 @@ * that is, have the value `__VA_ARGS__`. */ #ifndef HASH_LIST_EXPECTED -# define HASH_LIST_EXPECTED(...) __builtin_expect((__VA_ARGS__), 1) +# define HASH_LIST_EXPECTED(...) __builtin_expect((__VA_ARGS__), 1) #endif -#define HASH_LIST_HASH(key) (this->hasher != NULL ? this->hasher(key) : (size_t)key) +#define HASH_LIST_HASH(key) (this->hasher ? this->hasher(key) : (size_t)key) -#define HASH_LIST_T_VERSION 0 +#define HASH_LIST_T_VERSION 0 /** @@ -105,7 +105,7 @@ typedef VALUE_T T##_value_t;\ * * @param entry The entry, will never be `NULL`, any only used entries will be passed */\ -typedef void T##_entry_free_func(struct T##_entry* entry);\ +typedef void T##_entry_free_func(struct T##_entry *entry);\ \ /** * Function-type for the function responsible for hashing keys @@ -134,7 +134,7 @@ static inline int T##_key_comparer(CKEY_T key_a, CKEY_T key_b);\ * @return The marshal-size of the entry's key and value */\ __attribute__((pure, nonnull))\ -static inline size_t T##_submarshal_size(const struct T##_entry* entry);\ +static inline size_t T##_submarshal_size(const struct T##_entry *entry);\ \ /** * Marshal an entry's key and value @@ -144,7 +144,7 @@ static inline size_t T##_submarshal_size(const struct T##_entry* entry);\ * @return The marshal-size of the entry's key and value */\ __attribute__((pure, nonnull))\ -static inline size_t T##_submarshal(const struct T##_entry* entry, char* restrict data);\ +static inline size_t T##_submarshal(const struct T##_entry *entry, char *restrict data);\ \ /** * Unmarshal an entry's key and value @@ -154,7 +154,7 @@ static inline size_t T##_submarshal(const struct T##_entry* entry, char* restric * @return The number of read bytes, zero on error */\ __attribute__((pure, nonnull))\ -static inline size_t T##_subunmarshal(struct T##_entry* entry, char* restrict data);\ +static inline size_t T##_subunmarshal(struct T##_entry *entry, char *restrict data);\ \ \ \ @@ -163,21 +163,21 @@ static inline size_t T##_subunmarshal(struct T##_entry* entry, char* restrict da */\ typedef struct T##_entry\ {\ - /** - * The key of the entry, `NULL` if the slot is unused - */\ - KEY_T key;\ - \ - /** - * Hash of `key`, undefined but initialised if the slot is unused - */\ - size_t key_hash;\ - \ - /** - * The value of the entry - */\ - T##_value_t value;\ - \ + /** + * The key of the entry, `NULL` if the slot is unused + */\ + KEY_T key;\ + \ + /** + * Hash of `key`, undefined but initialised if the slot is unused + */\ + size_t key_hash;\ + \ + /** + * The value of the entry + */\ + T##_value_t value;\ + \ } T##_entry_t;\ \ \ @@ -186,55 +186,55 @@ typedef struct T##_entry\ */\ typedef struct T\ {\ - /** - * The number of allocated slots - */\ - size_t allocated;\ - \ - /** - * The number of unused slot that - * has previously be used - */\ - size_t unused;\ - \ - /** - * The number of slots that have - * been used, even if no longer used - */\ - size_t used;\ - \ - /** - * This variable is used for optimisation, any - * time `hash_list_get` finds an element, its - * will be stored, and it will be the first - * inspected element by `hash_list_put` and - * `hash_list_remove` - */\ - size_t last;\ - \ - /** - * The slots - */\ - T##_entry_t* slots;\ - \ - /** - * Function used to free keys and values of entries - * - * The freeing is not used if this function pointer is `NULL` - * - * Be aware, this variable cannot be marshalled - */\ - T##_entry_free_func* freer;\ - \ - /** - * Function used to calculate the hash of a key - * - * If this function pointer is `NULL`, the identity hash is used - * - * Be aware, this variable cannot be marshalled - */\ - T##_key_hash_func* hasher;\ - \ + /** + * The number of allocated slots + */\ + size_t allocated;\ + \ + /** + * The number of unused slot that + * has previously be used + */\ + size_t unused;\ + \ + /** + * The number of slots that have + * been used, even if no longer used + */\ + size_t used;\ + \ + /** + * This variable is used for optimisation, any + * time `hash_list_get` finds an element, its + * will be stored, and it will be the first + * inspected element by `hash_list_put` and + * `hash_list_remove` + */\ + size_t last;\ + \ + /** + * The slots + */\ + T##_entry_t *slots;\ + \ + /** + * Function used to free keys and values of entries + * + * The freeing is not used if this function pointer is `NULL` + * + * Be aware, this variable cannot be marshalled + */\ + T##_entry_free_func *freer;\ + \ + /** + * Function used to calculate the hash of a key + * + * If this function pointer is `NULL`, the identity hash is used + * + * Be aware, this variable cannot be marshalled + */\ + T##_key_hash_func *hasher;\ + \ } T##_t;\ \ \ @@ -247,24 +247,24 @@ typedef struct T\ * @return Non-zero on error, `errno` will have been set accordingly */\ static inline int __attribute__((unused, nonnull))\ -T##_create(T##_t* restrict this, size_t capacity)\ +T##_create(T##_t *restrict this, size_t capacity)\ {\ - if (capacity == 0)\ - capacity = HASH_LIST_DEFAULT_INITIAL_CAPACITY;\ - \ - this->freer = NULL;\ - this->hasher = NULL;\ - this->allocated = 0;\ - this->unused = 0;\ - this->used = 0;\ - this->last = 0;\ - \ - this->slots = malloc(capacity * sizeof(T##_t));\ - if (this->slots == NULL)\ - return -1;\ - \ - this->allocated = capacity;\ - return 0;\ + if (!capacity)\ + capacity = HASH_LIST_DEFAULT_INITIAL_CAPACITY;\ + \ + this->freer = NULL;\ + this->hasher = NULL;\ + this->allocated = 0;\ + this->unused = 0;\ + this->used = 0;\ + this->last = 0;\ + \ + this->slots = malloc(capacity * sizeof(T##_t));\ + if (!this->slots)\ + return -1;\ + \ + this->allocated = capacity;\ + return 0;\ }\ \ \ @@ -274,19 +274,19 @@ T##_create(T##_t* restrict this, size_t capacity)\ * @param this The hash list */\ static inline void __attribute__((unused, nonnull))\ -T##_destroy(T##_t* restrict this)\ +T##_destroy(T##_t *restrict this)\ {\ - size_t i, n;\ - if (this->freer != NULL)\ - for (i = 0, n = this->used; i < n; i++)\ - if (this->slots[i].key)\ - this->freer(this->slots + i);\ - this->used = 0;\ - this->unused = 0;\ - this->allocated = 0;\ - this->last = 0;\ - free(this->slots);\ - this->slots = NULL;\ + size_t i, n;\ + if (this->freer)\ + for (i = 0, n = this->used; i < n; i++)\ + if (this->slots[i].key)\ + this->freer(this->slots + i);\ + this->used = 0;\ + this->unused = 0;\ + this->allocated = 0;\ + this->last = 0;\ + free(this->slots);\ + this->slots = NULL;\ }\ \ \ @@ -298,14 +298,14 @@ T##_destroy(T##_t* restrict this)\ * @return Non-zero on error, `errno` will have been set accordingly */\ static inline int __attribute__((unused, nonnull))\ -T##_clone(const T##_t* restrict this, T##_t* restrict out)\ +T##_clone(const T##_t *restrict this, T##_t *restrict out)\ {\ - if (T##_create(out, this->allocated) < 0)\ - return -1;\ - out->used = this->used;\ - out->unused = this->unused;\ - out->last = this->last;\ - memcpy(out->slots, this->slots, this->used * sizeof(T##_entry_t));\ + if (T##_create(out, this->allocated) < 0)\ + return -1;\ + out->used = this->used;\ + out->unused = this->unused;\ + out->last = this->last;\ + memcpy(out->slots, this->slots, this->used * sizeof(T##_entry_t));\ }\ \ \ @@ -321,32 +321,30 @@ T##_clone(const T##_t* restrict this, T##_t* restrict out)\ * been set accordingly. Errors are non-fatal. */\ static inline int __attribute__((unused, nonnull))\ -T##_pack(T##_t* restrict this)\ +T##_pack(T##_t *restrict this)\ {\ - size_t i, j, n;\ - T##_entry_t* slots = this->slots;\ - \ - if (this->unused > 0)\ - {\ - for (i = 0, j = 0, n = this->used; i < n; i++)\ - if (slots[i].key != NULL)\ - slots[j++] = slots[i];\ - \ - this->used -= this->unused;\ - this->unused = 0;\ - this->last = 0;\ - }\ - \ - if (this->used < this->allocated)\ - {\ - slots = realloc(slots, this->used * sizeof(T##_entry_t));\ - if (slots == NULL)\ - return -1;\ - this->slots = slots;\ - this->allocated = this->used;\ - }\ - \ - return 0;\ + size_t i, j, n;\ + T##_entry_t *slots = this->slots;\ + \ + if (this->unused > 0) {\ + for (i = 0, j = 0, n = this->used; i < n; i++)\ + if (slots[i].key)\ + slots[j++] = slots[i];\ + \ + this->used -= this->unused;\ + this->unused = 0;\ + this->last = 0;\ + }\ + \ + if (this->used < this->allocated) {\ + slots = realloc(slots, this->used * sizeof(T##_entry_t));\ + if (!slots)\ + return -1;\ + this->slots = slots;\ + this->allocated = this->used;\ + }\ + \ + return 0;\ }\ \ \ @@ -359,14 +357,14 @@ T##_pack(T##_t* restrict this)\ * @return Whether the key was found, error is impossible */\ static inline int __attribute__((unused, nonnull))\ -T##_get(T##_t* restrict this, CKEY_T key, T##_value_t* restrict value)\ +T##_get(T##_t *restrict this, CKEY_T key, T##_value_t *restrict value)\ {\ - size_t i, n, hash = HASH_LIST_HASH(key);\ - for (i = 0, n = this->used; i < n; i++)\ - if ((this->slots[i].key_hash == hash) && this->slots[i].key)\ - if (T##_key_comparer(this->slots[i].key, key))\ - return *value = this->slots[this->last = i].value, 1;\ - return this->last = 0, 0;\ + size_t i, n, hash = HASH_LIST_HASH(key);\ + for (i = 0, n = this->used; i < n; i++)\ + if (this->slots[i].key_hash == hash && this->slots[i].key)\ + if (T##_key_comparer(this->slots[i].key, key))\ + return *value = this->slots[this->last = i].value, 1;\ + return this->last = 0, 0;\ }\ \ \ @@ -377,39 +375,39 @@ T##_get(T##_t* restrict this, CKEY_T key, T##_value_t* restrict value)\ * @param key The key of the entry to remove, must not be `NULL` */\ static inline void __attribute__((unused, nonnull))\ -T##_remove(T##_t* restrict this, CKEY_T key)\ +T##_remove(T##_t *restrict this, CKEY_T key)\ {\ - size_t i = this->last, n, hash = HASH_LIST_HASH(key);\ - T##_entry_t* slots = this->slots;\ - \ - /* First, try cached index. */\ - if (HASH_LIST_EXPECTED(i && (slots[i].key_hash == hash) && (slots[i].key != NULL)))\ - if (HASH_LIST_EXPECTED(T##_key_comparer(slots[i].key, key)))\ - goto do_remove;\ - /* It is discouraged to use put or remove without - * doing a get before it, otherwise you do not know - * what is happening. So we do not expect to get - * get to the next line. However, if do not expect to - * run get before put or remove, you should modify the - * `HASH_LIST_EXPECTED` macro. However, this is single - * case where will will get to the next line, when the - * index of the item is zero. */\ - \ - /* Then, search. */\ - for (i = 0, n = this->used; i < n; i++)\ - if ((slots[i].key_hash == hash) && (slots[i].key != NULL))\ - if (T##_key_comparer(slots[i].key, key))\ - goto do_remove;\ - \ - return;\ - do_remove:\ - if (this->freer != NULL)\ - this->freer(slots + i);\ - slots[i].key = NULL;\ - this->unused++;\ - if ((this->unused >> 1) >= this->used)\ - T##_pack(this);\ - this->last = 0;\ + size_t i = this->last, n, hash = HASH_LIST_HASH(key);\ + T##_entry_t *slots = this->slots;\ + \ + /* First, try cached index. */\ + if (HASH_LIST_EXPECTED(i && slots[i].key_hash == hash && slots[i].key))\ + if (HASH_LIST_EXPECTED(T##_key_comparer(slots[i].key, key)))\ + goto do_remove;\ + /* It is discouraged to use put or remove without + * doing a get before it, otherwise you do not know + * what is happening. So we do not expect to get + * get to the next line. However, if do not expect to + * run get before put or remove, you should modify the + * `HASH_LIST_EXPECTED` macro. However, this is single + * case where will will get to the next line, when the + * index of the item is zero. */\ + \ + /* Then, search. */\ + for (i = 0, n = this->used; i < n; i++)\ + if (slots[i].key_hash == hash && slots[i].key)\ + if (T##_key_comparer(slots[i].key, key))\ + goto do_remove;\ + \ + return;\ +do_remove:\ + if (this->freer)\ + this->freer(slots + i);\ + slots[i].key = NULL;\ + this->unused++;\ + if (this->unused >> 1 >= this->used)\ + T##_pack(this);\ + this->last = 0;\ }\ \ \ @@ -423,66 +421,66 @@ T##_remove(T##_t* restrict this, CKEY_T key)\ * @return Non-zero on error, `errno` will have been set accordingly */\ static inline int __attribute__((unused, nonnull(1, 2)))\ -T##_put(T##_t* restrict this, KEY_T key, const T##_value_t* restrict value)\ +T##_put(T##_t *restrict this, KEY_T key, const T##_value_t *restrict value)\ {\ - size_t i = this->last, n, empty = this->used, hash;\ - T##_entry_t* slots = this->slots;\ - \ - /* Remove entry if no value is passed. */\ - if (value == NULL)\ - {\ - T##_remove(this, key);\ - return 0;\ - }\ - \ - /* Hash the input key. */\ - hash = HASH_LIST_HASH(key);\ - \ - /* Try cached index. */\ - if (HASH_LIST_EXPECTED(i && (slots[i].key != NULL)))\ - if (HASH_LIST_EXPECTED(slots[i].key_hash == hash))\ - if (HASH_LIST_EXPECTED(T##_key_comparer(slots[i].key, key)))\ - goto put;\ - /* It is discouraged to use put or remove without - * doing a get before it, otherwise you do not know - * what is happening. So we do not expect to get - * get to the next line. However, if do not expect to - * run get before put or remove, you should modify the - * `HASH_LIST_EXPECTED` macro. However, this is single - * case where will will get to the next line, when the - * index of the item is zero. */\ - \ - /* Find an unused slot or the current slot. */\ - for (i = 0, n = this->used; i < n; i++)\ - if (slots[i].key == NULL)\ - empty = i;\ - else if (slots[i].key_hash == hash)\ - if (T##_key_comparer(slots[i].key, key))\ - goto put;\ - \ - /* Grow slot allocation is required. */\ - if (empty == this->allocated)\ - {\ - if (empty >= SIZE_MAX >> 1)\ - return errno = ENOMEM, -1;\ - slots = realloc(slots, (empty << 1) * sizeof(T##_entry_t));\ - if (slots == NULL)\ - return -1;\ - this->slots = slots;\ - this->allocated <<= 1;\ - }\ - \ - /* Store entry. */\ - i = empty;\ - goto put_no_free;\ - put:\ - if (this->freer != NULL)\ - this->freer(slots + i);\ - put_no_free:\ - slots[i].key = key;\ - slots[i].key_hash = hash;\ - slots[i].value = *value;\ - return 0;\ + size_t i = this->last, n, empty = this->used, hash;\ + T##_entry_t* slots = this->slots;\ + \ + /* Remove entry if no value is passed. */\ + if (!value) {\ + T##_remove(this, key);\ + return 0;\ + }\ + \ + /* Hash the input key. */\ + hash = HASH_LIST_HASH(key);\ + \ + /* Try cached index. */\ + if (HASH_LIST_EXPECTED(i && slots[i].key))\ + if (HASH_LIST_EXPECTED(slots[i].key_hash == hash))\ + if (HASH_LIST_EXPECTED(T##_key_comparer(slots[i].key, key)))\ + goto put;\ + /* It is discouraged to use put or remove without + * doing a get before it, otherwise you do not know + * what is happening. So we do not expect to get + * get to the next line. However, if do not expect to + * run get before put or remove, you should modify the + * `HASH_LIST_EXPECTED` macro. However, this is single + * case where will will get to the next line, when the + * index of the item is zero. */\ + \ + /* Find an unused slot or the current slot. */\ + for (i = 0, n = this->used; i < n; i++) {\ + if (!slots[i].key) {\ + empty = i;\ + } else if (slots[i].key_hash == hash) {\ + if (T##_key_comparer(slots[i].key, key))\ + goto put;\ + }\ + }\ + \ + /* Grow slot allocation is required. */\ + if (empty == this->allocated) {\ + if (empty >= SIZE_MAX >> 1)\ + return errno = ENOMEM, -1;\ + slots = realloc(slots, (empty << 1) * sizeof(T##_entry_t));\ + if (!slots)\ + return -1;\ + this->slots = slots;\ + this->allocated <<= 1;\ + }\ + \ + /* Store entry. */\ + i = empty;\ + goto put_no_free;\ +put:\ + if (this->freer)\ + this->freer(slots + i);\ +put_no_free:\ + slots[i].key = key;\ + slots[i].key_hash = hash;\ + slots[i].value = *value;\ + return 0;\ }\ \ \ @@ -493,14 +491,14 @@ T##_put(T##_t* restrict this, KEY_T key, const T##_value_t* restrict value)\ * @return The number of bytes to allocate to the output buffer */\ static inline size_t __attribute__((unused, pure, nonnull))\ -T##_marshal_size(const T##_t* restrict this)\ +T##_marshal_size(const T##_t *restrict this)\ {\ - size_t i, n = this->used;\ - size_t rc = sizeof(int) + 4 * sizeof(size_t);\ - for (i = 0; i < n; i++)\ - if (this->slots[i].key != NULL)\ - rc += T##_submarshal_size(this->slots + i);\ - return rc + n * sizeof(char) + (n - this->unused) * sizeof(size_t);\ + size_t i, n = this->used;\ + size_t rc = sizeof(int) + 4 * sizeof(size_t);\ + for (i = 0; i < n; i++)\ + if (this->slots[i].key)\ + rc += T##_submarshal_size(this->slots + i);\ + return rc + n * sizeof(char) + (n - this->unused) * sizeof(size_t);\ }\ \ \ @@ -511,26 +509,26 @@ T##_marshal_size(const T##_t* restrict this)\ * @param data Output buffer for the marshalled data */\ static inline void __attribute__((unused, nonnull))\ -T##_marshal(const T##_t* restrict this, char* restrict data)\ +T##_marshal(const T##_t *restrict this, char *restrict data)\ {\ - size_t wrote, i, n = this->used;\ - \ - buf_set_next(data, int, HASH_LIST_T_VERSION);\ - buf_set_next(data, size_t, this->allocated);\ - buf_set_next(data, size_t, this->unused);\ - buf_set_next(data, size_t, this->used);\ - buf_set_next(data, size_t, this->last);\ - \ - for (i = 0; i < n; i++)\ - if (this->slots[i].key != NULL)\ - {\ - buf_set_next(data, char, 1);\ - buf_set_next(data, size_t, this->slots[i].key_hash);\ - wrote = T##_submarshal(this->slots + i, data);\ - data += wrote / sizeof(char);\ - }\ - else\ - buf_set_next(data, char, 0);\ + size_t wrote, i, n = this->used;\ + \ + buf_set_next(data, int, HASH_LIST_T_VERSION);\ + buf_set_next(data, size_t, this->allocated);\ + buf_set_next(data, size_t, this->unused);\ + buf_set_next(data, size_t, this->used);\ + buf_set_next(data, size_t, this->last);\ + \ + for (i = 0; i < n; i++) {\ + if (this->slots[i].key) {\ + buf_set_next(data, char, 1);\ + buf_set_next(data, size_t, this->slots[i].key_hash);\ + wrote = T##_submarshal(this->slots + i, data);\ + data += wrote / sizeof(char);\ + } else {\ + buf_set_next(data, char, 0);\ + }\ + }\ }\ \ \ @@ -543,39 +541,38 @@ T##_marshal(const T##_t* restrict this, char* restrict data)\ * Destroy the table on error. */\ static inline int __attribute__((unused, nonnull))\ -T##_unmarshal(T##_t* restrict this, char* restrict data)\ +T##_unmarshal(T##_t *restrict this, char *restrict data)\ {\ - size_t i, n, got;\ - char used;\ - \ - this->freer = NULL;\ - this->hasher = NULL;\ - \ - /* buf_get(data, int, 0, HASH_LIST_T_VERSION); */\ - buf_next(data, int, 1);\ - \ - buf_get_next(data, size_t, this->allocated);\ - buf_get_next(data, size_t, this->unused);\ - buf_get_next(data, size_t, this->used);\ - buf_get_next(data, size_t, this->last);\ - \ - this->slots = calloc(this->allocated, sizeof(T##_entry_t));\ - if (this->slots == NULL)\ - return -1;\ - \ - for (i = 0, n = this->used; i < n; i++)\ - {\ - buf_get_next(data, char, used);\ - if (used == 0)\ - continue;\ - buf_set_next(data, size_t, this->slots[i].key_hash);\ - got = T##_subunmarshal(this->slots + i, data);\ - if (got == 0)\ - return -1;\ - data += got / sizeof(char);\ - }\ - \ - return 0;\ + size_t i, n, got;\ + char used;\ + \ + this->freer = NULL;\ + this->hasher = NULL;\ + \ + /* buf_get(data, int, 0, HASH_LIST_T_VERSION); */\ + buf_next(data, int, 1);\ + \ + buf_get_next(data, size_t, this->allocated);\ + buf_get_next(data, size_t, this->unused);\ + buf_get_next(data, size_t, this->used);\ + buf_get_next(data, size_t, this->last);\ + \ + this->slots = calloc(this->allocated, sizeof(T##_entry_t));\ + if (!this->slots)\ + return -1;\ + \ + for (i = 0, n = this->used; i < n; i++) {\ + buf_get_next(data, char, used);\ + if (!used)\ + continue;\ + buf_set_next(data, size_t, this->slots[i].key_hash);\ + got = T##_subunmarshal(this->slots + i, data);\ + if (!got)\ + return -1;\ + data += got / sizeof(char);\ + }\ + \ + return 0;\ } @@ -586,9 +583,9 @@ T##_unmarshal(T##_t* restrict this, char* restrict data)\ * @param i:size_t The variable to store the buckey index in at each iteration * @param entry:hash_list_enty_t* The variable to store the entry in at each iteration */ -#define foreach_hash_list_entry(this, i, entry) \ - for (i = 0; i < (this).used; i++) \ - if (entry = (this).slots, entry->key != NULL) +#define foreach_hash_list_entry(this, i, entry)\ + for (i = 0; i < (this).used; i++)\ + if ((entry = (this).slots)->key) #endif diff --git a/src/libmdsserver/hash-table.c b/src/libmdsserver/hash-table.c index 000bd20..2a7bc3c 100644 --- a/src/libmdsserver/hash-table.c +++ b/src/libmdsserver/hash-table.c @@ -31,8 +31,8 @@ * @param K The key * @param H The hash of the key */ -#define TEST_KEY(T, B, K, H) \ - ((B->key == K) || (T->key_comparator && (B->hash == H) && T->key_comparator(B->key, K))) +#define TEST_KEY(T, B, K, H)\ + ((B)->key == (K) || ((T)->key_comparator && (B)->hash == (H) && (T)->key_comparator((B)->key, (K)))) /** @@ -42,10 +42,10 @@ * @param key The key to hash * @return The hash of the key */ -__attribute__((pure, nonnull)) -static inline size_t hash(const hash_table_t* restrict this, size_t key) +static inline size_t __attribute__((pure, nonnull)) +hash(const hash_table_t *restrict this, size_t key) { - return this->hasher ? this->hasher(key) : key; + return this->hasher ? this->hasher(key) : key; } @@ -56,10 +56,10 @@ static inline size_t hash(const hash_table_t* restrict this, size_t key) * @param key The key to hash * @return A non-negative value less the the table's capacity */ -__attribute__((pure, nonnull)) -static inline size_t truncate_hash(const hash_table_t* restrict this, size_t hash) +static inline size_t __attribute__((pure, nonnull)) +truncate_hash(const hash_table_t *restrict this, size_t hash) { - return hash % this->capacity; + return hash % this->capacity; } @@ -69,49 +69,42 @@ static inline size_t truncate_hash(const hash_table_t* restrict this, size_t has * @param this The hash table * @return Non-zero on error, `errno` will be set accordingly */ -__attribute__((nonnull)) -static int rehash(hash_table_t* restrict this) +static int __attribute__((nonnull)) +rehash(hash_table_t *restrict this) { - hash_entry_t** old_buckets = this->buckets; - size_t old_capacity = this->capacity; - size_t i = old_capacity, index; - hash_entry_t* bucket; - hash_entry_t* destination; - hash_entry_t* next; - - fail_if (xcalloc(this->buckets, old_capacity * 2 + 1, hash_entry_t*)); - this->capacity = old_capacity * 2 + 1; - this->threshold = (size_t)((float)(this->capacity) * this->load_factor); - - while (i) - { - bucket = this->buckets[--i]; - while (bucket) - { - index = truncate_hash(this, bucket->hash); - if ((destination = this->buckets[index])) - { - next = destination->next; - while (next) - { - destination = next; - next = destination->next; + hash_entry_t **old_buckets = this->buckets; + size_t old_capacity = this->capacity; + size_t i = old_capacity, index; + hash_entry_t *bucket; + hash_entry_t *destination; + hash_entry_t *next; + + fail_if (xcalloc(this->buckets, old_capacity * 2 + 1, hash_entry_t*)); + this->capacity = old_capacity * 2 + 1; + this->threshold = (size_t)((float)(this->capacity) * this->load_factor); + + while (i--) { + bucket = this->buckets[i]; + while (bucket) { + index = truncate_hash(this, bucket->hash); + if ((destination = this->buckets[index])) { + while ((next = destination->next)) + destination = next; + destination->next = bucket; + } else { + this->buckets[index] = bucket; + } + + next = bucket->next; + bucket->next = NULL; + bucket = next; } - destination->next = bucket; - } - else - this->buckets[index] = bucket; - - next = bucket->next; - bucket->next = NULL; - bucket = next; } - } - - free(old_buckets); - return 0; - fail: - return -1; + + free(old_buckets); + return 0; +fail: + return -1; } @@ -123,22 +116,23 @@ static int rehash(hash_table_t* restrict this) * @param load_factor The load factor of the table, i.e. when to grow the table * @return Non-zero on error, `errno` will have been set accordingly */ -int hash_table_create_fine_tuned(hash_table_t* restrict this, size_t initial_capacity, float load_factor) +int +hash_table_create_fine_tuned(hash_table_t *restrict this, size_t initial_capacity, float load_factor) { - this->buckets = NULL; - - this->capacity = initial_capacity ? initial_capacity : 1; - fail_if (xcalloc(this->buckets, this->capacity, hash_entry_t*)); - this->load_factor = load_factor; - this->threshold = (size_t)((float)(this->capacity) * load_factor); - this->size = 0; - this->value_comparator = NULL; - this->key_comparator = NULL; - this->hasher = NULL; - - return 0; - fail: - return -1; + this->buckets = NULL; + + this->capacity = initial_capacity ? initial_capacity : 1; + fail_if (xcalloc(this->buckets, this->capacity, hash_entry_t*)); + this->load_factor = load_factor; + this->threshold = (size_t)((float)(this->capacity) * load_factor); + this->size = 0; + this->value_comparator = NULL; + this->key_comparator = NULL; + this->hasher = NULL; + + return 0; +fail: + return -1; } @@ -150,27 +144,24 @@ int hash_table_create_fine_tuned(hash_table_t* restrict this, size_t initial_cap * @param keys_freer Function that frees a key, `NULL` if keys should not be freed * @param values_freer Function that frees a value, `NULL` if value should not be freed */ -void hash_table_destroy(hash_table_t* restrict this, free_func* key_freer, free_func* value_freer) +void +hash_table_destroy(hash_table_t *restrict this, free_func *key_freer, free_func *value_freer) { - size_t i = this->capacity; - hash_entry_t* bucket; - hash_entry_t* last; - - if (this->buckets != NULL) - { - while (i) - { - bucket = this->buckets[--i]; - while (bucket) - { - if (key_freer != NULL) key_freer(bucket->key); - if (value_freer != NULL) value_freer(bucket->value); - bucket = (last = bucket)->next; - free(last); - } + size_t i = this->capacity; + hash_entry_t *bucket, *last; + + if (this->buckets) { + while (i) { + bucket = this->buckets[--i]; + while (bucket) { + if (key_freer) key_freer(bucket->key); + if (value_freer) value_freer(bucket->value); + bucket = (last = bucket)->next; + free(last); + } + } + free(this->buckets); } - free(this->buckets); - } } @@ -181,25 +172,24 @@ void hash_table_destroy(hash_table_t* restrict this, free_func* key_freer, free_ * @param value The value * @return Whether the value is stored in the table */ -int hash_table_contains_value(const hash_table_t* restrict this, size_t value) +int +hash_table_contains_value(const hash_table_t *restrict this, size_t value) { - size_t i = this->capacity; - hash_entry_t* restrict bucket; - - while (i) - { - bucket = this->buckets[--i]; - while (bucket != NULL) - { - if (bucket->value == value) - return 1; - if (this->value_comparator && this->value_comparator(bucket->value, value)) - return 1; - bucket = bucket->next; + size_t i = this->capacity; + hash_entry_t *restrict bucket; + + while (i--) { + bucket = this->buckets[i]; + while (bucket) { + if (bucket->value == value) + return 1; + if (this->value_comparator && this->value_comparator(bucket->value, value)) + return 1; + bucket = bucket->next; + } } - } - - return 0; + + return 0; } @@ -210,20 +200,20 @@ int hash_table_contains_value(const hash_table_t* restrict this, size_t value) * @param key The key * @return Whether the key is used */ -int hash_table_contains_key(const hash_table_t* restrict this, size_t key) +int +hash_table_contains_key(const hash_table_t *restrict this, size_t key) { - size_t key_hash = hash(this, key); - size_t index = truncate_hash(this, key_hash); - hash_entry_t* restrict bucket = this->buckets[index]; - - while (bucket) - { - if (TEST_KEY(this, bucket, key, key_hash)) - return 1; - bucket = bucket->next; - } - - return 0; + size_t key_hash = hash(this, key); + size_t index = truncate_hash(this, key_hash); + hash_entry_t *restrict bucket = this->buckets[index]; + + while (bucket) { + if (TEST_KEY(this, bucket, key, key_hash)) + return 1; + bucket = bucket->next; + } + + return 0; } @@ -234,20 +224,20 @@ int hash_table_contains_key(const hash_table_t* restrict this, size_t key) * @param key The key associated with the value * @return The value associated with the key, 0 if the key was not used */ -size_t hash_table_get(const hash_table_t* restrict this, size_t key) +size_t +hash_table_get(const hash_table_t *restrict this, size_t key) { - size_t key_hash = hash(this, key); - size_t index = truncate_hash(this, key_hash); - hash_entry_t* restrict bucket = this->buckets[index]; - - while (bucket) - { - if (TEST_KEY(this, bucket, key, key_hash)) - return bucket->value; - bucket = bucket->next; - } - - return 0; + size_t key_hash = hash(this, key); + size_t index = truncate_hash(this, key_hash); + hash_entry_t *restrict bucket = this->buckets[index]; + + while (bucket) { + if (TEST_KEY(this, bucket, key, key_hash)) + return bucket->value; + bucket = bucket->next; + } + + return 0; } @@ -258,20 +248,20 @@ size_t hash_table_get(const hash_table_t* restrict this, size_t key) * @param key The key associated with the value * @return The entry associated with the key, `NULL` if the key was not used */ -hash_entry_t* hash_table_get_entry(const hash_table_t* restrict this, size_t key) +hash_entry_t * +hash_table_get_entry(const hash_table_t *restrict this, size_t key) { - size_t key_hash = hash(this, key); - size_t index = truncate_hash(this, key_hash); - hash_entry_t* restrict bucket = this->buckets[index]; - - while (bucket) - { - if (TEST_KEY(this, bucket, key, key_hash)) - return bucket; - bucket = bucket->next; - } - - return NULL; + size_t key_hash = hash(this, key); + size_t index = truncate_hash(this, key_hash); + hash_entry_t *restrict bucket = this->buckets[index]; + + while (bucket) { + if (TEST_KEY(this, bucket, key, key_hash)) + return bucket; + bucket = bucket->next; + } + + return NULL; } @@ -284,41 +274,41 @@ hash_entry_t* hash_table_get_entry(const hash_table_t* restrict this, size_t key * @return The previous value associated with the key, 0 if the key was not used. * 0 will also be returned on error, check the `errno` variable. */ -size_t hash_table_put(hash_table_t* restrict this, size_t key, size_t value) +size_t +hash_table_put(hash_table_t *restrict this, size_t key, size_t value) { - size_t key_hash = hash(this, key); - size_t index = truncate_hash(this, key_hash); - hash_entry_t* restrict bucket = this->buckets[index]; - size_t rc; - - while (bucket) - if (TEST_KEY(this, bucket, key, key_hash)) - { - rc = bucket->value; + size_t key_hash = hash(this, key); + size_t index = truncate_hash(this, key_hash); + hash_entry_t *restrict bucket = this->buckets[index]; + size_t rc; + + while (bucket) { + if (TEST_KEY(this, bucket, key, key_hash)) { + rc = bucket->value; + bucket->value = value; + return rc; + } else { + bucket = bucket->next; + } + } + + if (++(this->size) > this->threshold) { + errno = 0; + fail_if (rehash(this)); + index = truncate_hash(this, key_hash); + } + + errno = 0; + fail_if (xmalloc(bucket, 1, hash_entry_t)); bucket->value = value; - return rc; - } - else - bucket = bucket->next; - - if (++(this->size) > this->threshold) - { - errno = 0; - fail_if (rehash(this)); - index = truncate_hash(this, key_hash); - } - - errno = 0; - fail_if (xmalloc(bucket, 1, hash_entry_t)); - bucket->value = value; - bucket->key = key; - bucket->hash = key_hash; - bucket->next = this->buckets[index]; - this->buckets[index] = bucket; - - return 0; - fail: - return 0; + bucket->key = key; + bucket->hash = key_hash; + bucket->next = this->buckets[index]; + this->buckets[index] = bucket; + + return 0; +fail: + return 0; } @@ -329,32 +319,31 @@ size_t hash_table_put(hash_table_t* restrict this, size_t key, size_t value) * @param key The key of the entry to remove * @return The previous value associated with the key, 0 if the key was not used */ -size_t hash_table_remove(hash_table_t* restrict this, size_t key) +size_t +hash_table_remove(hash_table_t *restrict this, size_t key) { - size_t key_hash = hash(this, key); - size_t index = truncate_hash(this, key_hash); - hash_entry_t* bucket = this->buckets[index]; - hash_entry_t* last = NULL; - size_t rc; - - while (bucket) - { - if (TEST_KEY(this, bucket, key, key_hash)) - { - if (last == NULL) - this->buckets[index] = bucket->next; - else - last->next = bucket->next; - this->size--; - rc = bucket->value; - free(bucket); - return rc; + size_t key_hash = hash(this, key); + size_t index = truncate_hash(this, key_hash); + hash_entry_t *bucket = this->buckets[index]; + hash_entry_t *last = NULL; + size_t rc; + + while (bucket) { + if (TEST_KEY(this, bucket, key, key_hash)) { + if (!last) + this->buckets[index] = bucket->next; + else + last->next = bucket->next; + this->size--; + rc = bucket->value; + free(bucket); + return rc; + } + last = bucket; + bucket = bucket->next; } - last = bucket; - bucket = bucket->next; - } - - return 0; + + return 0; } @@ -363,32 +352,29 @@ size_t hash_table_remove(hash_table_t* restrict this, size_t key) * * @param this The hash table */ -void hash_table_clear(hash_table_t* restrict this) +void +hash_table_clear(hash_table_t *restrict this) { - hash_entry_t** buf; - hash_entry_t* bucket; - size_t i, ptr; - - if (this->size) - { - buf = alloca((this->size + 1) * sizeof(hash_entry_t*)); - i = this->capacity; - while (i) - { - bucket = this->buckets[--i]; - ptr = 0; - buf[ptr++] = bucket; - while (bucket) - { - bucket = bucket->next; - buf[ptr++] = bucket; - } - while (ptr) - free(buf[--ptr]); - this->buckets[i] = NULL; + hash_entry_t **buf, *bucket; + size_t i, ptr; + + if (this->size) { + buf = alloca((this->size + 1) * sizeof(hash_entry_t*)); + i = this->capacity; + while (i--) { + bucket = this->buckets[i]; + ptr = 0; + buf[ptr++] = bucket; + while (bucket) { + bucket = bucket->next; + buf[ptr++] = bucket; + } + while (ptr) + free(buf[--ptr]); + this->buckets[i] = NULL; + } + this->size = 0; } - this->size = 0; - } } @@ -398,23 +384,23 @@ void hash_table_clear(hash_table_t* restrict this) * @param this The hash table * @return The number of bytes to allocate to the output buffer */ -size_t hash_table_marshal_size(const hash_table_t* restrict this) +size_t +hash_table_marshal_size(const hash_table_t *restrict this) { - size_t n = this->capacity; - size_t rc = 3 * sizeof(size_t) + sizeof(float) + n * sizeof(size_t); - size_t i, m = 0; - - for (i = 0; i < n; i++) - { - hash_entry_t* restrict bucket = this->buckets[i]; - while (bucket != NULL) - { - bucket = bucket->next; - m++; + size_t n = this->capacity; + size_t rc = 3 * sizeof(size_t) + sizeof(float) + n * sizeof(size_t); + size_t i, m = 0; + hash_entry_t *restrict bucket; + + for (i = 0; i < n; i++) { + bucket = this->buckets[i]; + while (bucket) { + bucket = bucket->next; + m++; + } } - } - - return rc + m * 3 * sizeof(size_t) + sizeof(int); + + return rc + m * 3 * sizeof(size_t) + sizeof(int); } @@ -424,31 +410,31 @@ size_t hash_table_marshal_size(const hash_table_t* restrict this) * @param this The hash table * @param data Output buffer for the marshalled data */ -void hash_table_marshal(const hash_table_t* restrict this, char* restrict data) +void +hash_table_marshal(const hash_table_t *restrict this, char *restrict data) { - size_t i, n = this->capacity; - - buf_set_next(data, int, HASH_TABLE_T_VERSION); - buf_set_next(data, size_t, this->capacity); - buf_set_next(data, float, this->load_factor); - buf_set_next(data, size_t, this->threshold); - buf_set_next(data, size_t, this->size); - - for (i = 0; i < n; i++) - { - hash_entry_t* restrict bucket = this->buckets[i]; - size_t m = 0; - while (bucket != NULL) - { - buf_set(data, size_t, 1 + m * 3 + 0, bucket->key); - buf_set(data, size_t, 1 + m * 3 + 1, bucket->value); - buf_set(data, size_t, 1 + m * 3 + 2, bucket->hash); - bucket = bucket->next; - m++; + size_t i, n = this->capacity, m; + hash_entry_t *restrict bucket; + + buf_set_next(data, int, HASH_TABLE_T_VERSION); + buf_set_next(data, size_t, this->capacity); + buf_set_next(data, float, this->load_factor); + buf_set_next(data, size_t, this->threshold); + buf_set_next(data, size_t, this->size); + + for (i = 0; i < n; i++) { + bucket = this->buckets[i]; + m = 0; + while (bucket) { + buf_set(data, size_t, 1 + m * 3 + 0, bucket->key); + buf_set(data, size_t, 1 + m * 3 + 1, bucket->value); + buf_set(data, size_t, 1 + m * 3 + 2, bucket->hash); + bucket = bucket->next; + m++; + } + buf_set(data, size_t, 0, m); + buf_next(data, size_t, 1 + m * 3); } - buf_set(data, size_t, 0, m); - buf_next(data, size_t, 1 + m * 3); - } } @@ -461,48 +447,45 @@ void hash_table_marshal(const hash_table_t* restrict this, char* restrict data) * @return Non-zero on error, `errno` will be set accordingly. * Destroy the table on error. */ -int hash_table_unmarshal(hash_table_t* restrict this, char* restrict data, remap_func* remapper) +int +hash_table_unmarshal(hash_table_t *restrict this, char *restrict data, remap_func *remapper) { - size_t i, n; - - /* buf_get(data, int, 0, HASH_TABLE_T_VERSION); */ - buf_next(data, int, 1); - - this->value_comparator = NULL; - this->key_comparator = NULL; - this->hasher = NULL; - - buf_get_next(data, size_t, this->capacity = n); - buf_get_next(data, float, this->load_factor); - buf_get_next(data, size_t, this->threshold); - buf_get_next(data, size_t, this->size); - - fail_if (xcalloc(this->buckets, this->capacity, hash_entry_t*)); - - for (i = 0; i < n; i++) - { - size_t m; - hash_entry_t* restrict bucket; - buf_get_next(data, size_t, m); - - fail_if (xmalloc(this->buckets[i] = bucket, 1, hash_entry_t)); - - while (m--) - { - if (m == 0) - bucket->next = NULL; - else - fail_if (xmalloc(bucket->next, 1, hash_entry_t)); - buf_get_next(data, size_t, bucket->key); - buf_get_next(data, size_t, bucket->value); - if (remapper != NULL) - bucket->value = remapper(bucket->value); - buf_get_next(data, size_t, bucket->hash); + size_t i, n, m; + hash_entry_t *restrict bucket; + + /* buf_get(data, int, 0, HASH_TABLE_T_VERSION); */ + buf_next(data, int, 1); + + this->value_comparator = NULL; + this->key_comparator = NULL; + this->hasher = NULL; + + buf_get_next(data, size_t, this->capacity = n); + buf_get_next(data, float, this->load_factor); + buf_get_next(data, size_t, this->threshold); + buf_get_next(data, size_t, this->size); + + fail_if (xcalloc(this->buckets, this->capacity, hash_entry_t*)); + + for (i = 0; i < n; i++) { + buf_get_next(data, size_t, m); + + fail_if (xmalloc(this->buckets[i] = bucket, 1, hash_entry_t)); + + while (m--) { + if (!m) + bucket->next = NULL; + else + fail_if (xmalloc(bucket->next, 1, hash_entry_t)); + buf_get_next(data, size_t, bucket->key); + buf_get_next(data, size_t, bucket->value); + if (remapper) + bucket->value = remapper(bucket->value); + buf_get_next(data, size_t, bucket->hash); + } } - } - - return 0; - fail: - return -1; -} + return 0; +fail: + return -1; +} diff --git a/src/libmdsserver/linked-list.c b/src/libmdsserver/linked-list.c index 401a726..954c6fe 100644 --- a/src/libmdsserver/linked-list.c +++ b/src/libmdsserver/linked-list.c @@ -27,7 +27,7 @@ * The default initial capacity */ #ifndef LINKED_LIST_DEFAULT_INITIAL_CAPACITY -# define LINKED_LIST_DEFAULT_INITIAL_CAPACITY 128 +# define LINKED_LIST_DEFAULT_INITIAL_CAPACITY 128 #endif @@ -38,19 +38,19 @@ * @param value The value to be rounded up to a power of two * @return The nearest, but not smaller, power of two */ -__attribute__((const)) -static size_t to_power_of_two(size_t value) +static size_t __attribute__((const)) +to_power_of_two(size_t value) { - value -= 1; - value |= value >> 1; - value |= value >> 2; - value |= value >> 4; - value |= value >> 8; - value |= value >> 16; + value -= 1; + value |= value >> 1; + value |= value >> 2; + value |= value >> 4; + value |= value >> 8; + value |= value >> 16; #if SIZE_MAX == UINT64_MAX - value |= value >> 32; + value |= value >> 32; #endif - return value + 1; + return value + 1; } @@ -61,32 +61,33 @@ static size_t to_power_of_two(size_t value) * @param capacity The minimum initial capacity of the linked list, 0 for default * @return Non-zero on error, `errno` will have been set accordingly */ -int linked_list_create(linked_list_t* restrict this, size_t capacity) +int +linked_list_create(linked_list_t *restrict this, size_t capacity) { - /* Use default capacity of zero is specified. */ - if (capacity == 0) - capacity = LINKED_LIST_DEFAULT_INITIAL_CAPACITY; - - /* Initialise the linked list. */ - this->capacity = capacity = to_power_of_two(capacity); - this->edge = 0; - this->end = 1; - this->reuse_head = 0; - this->reusable = NULL; - this->values = NULL; - this->next = NULL; - this->previous = NULL; - fail_if (xmalloc(this->reusable, capacity, ssize_t)); - fail_if (xmalloc(this->values, capacity, size_t)); - fail_if (xmalloc(this->next, capacity, ssize_t)); - fail_if (xmalloc(this->previous, capacity, ssize_t)); - this->values[this->edge] = 0; - this->next[this->edge] = this->edge; - this->previous[this->edge] = this->edge; - - return 0; - fail: - return -1; + /* Use default capacity of zero is specified. */ + if (!capacity) + capacity = LINKED_LIST_DEFAULT_INITIAL_CAPACITY; + + /* Initialise the linked list. */ + this->capacity = capacity = to_power_of_two(capacity); + this->edge = 0; + this->end = 1; + this->reuse_head = 0; + this->reusable = NULL; + this->values = NULL; + this->next = NULL; + this->previous = NULL; + fail_if (xmalloc(this->reusable, capacity, ssize_t)); + fail_if (xmalloc(this->values, capacity, size_t)); + fail_if (xmalloc(this->next, capacity, ssize_t)); + fail_if (xmalloc(this->previous, capacity, ssize_t)); + this->values[this->edge] = 0; + this->next[this->edge] = this->edge; + this->previous[this->edge] = this->edge; + + return 0; +fail: + return -1; } @@ -96,12 +97,13 @@ int linked_list_create(linked_list_t* restrict this, size_t capacity) * * @param this The linked list */ -void linked_list_destroy(linked_list_t* restrict this) +void +linked_list_destroy(linked_list_t *restrict this) { - free(this->reusable), this->reusable = NULL; - free(this->values), this->values = NULL; - free(this->next), this->next = NULL; - free(this->previous), this->previous = NULL; + free(this->reusable), this->reusable = NULL; + free(this->values), this->values = NULL; + free(this->next), this->next = NULL; + free(this->previous), this->previous = NULL; } @@ -112,22 +114,23 @@ void linked_list_destroy(linked_list_t* restrict this) * @param out Memory slot in which to store the new linked list * @return Non-zero on error, `errno` will have been set accordingly */ -int linked_list_clone(const linked_list_t* restrict this, linked_list_t* restrict out) +int +linked_list_clone(const linked_list_t *restrict this, linked_list_t *restrict out) { - fail_if (xmemdup(out->values, this->values, this->capacity, size_t)); - fail_if (xmemdup(out->next, this->next, this->capacity, ssize_t)); - fail_if (xmemdup(out->previous, this->previous, this->capacity, ssize_t)); - fail_if (xmemdup(out->reusable, this->reusable, this->capacity, ssize_t)); - - out->capacity = this->capacity; - out->end = this->end; - out->reuse_head = this->reuse_head; - out->edge = this->edge; - - return 0; - - fail: - return -1; + fail_if (xmemdup(out->values, this->values, this->capacity, size_t)); + fail_if (xmemdup(out->next, this->next, this->capacity, ssize_t)); + fail_if (xmemdup(out->previous, this->previous, this->capacity, ssize_t)); + fail_if (xmemdup(out->reusable, this->reusable, this->capacity, ssize_t)); + + out->capacity = this->capacity; + out->end = this->end; + out->reuse_head = this->reuse_head; + out->edge = this->edge; + + return 0; + +fail: + return -1; } @@ -145,64 +148,64 @@ int linked_list_clone(const linked_list_t* restrict this, linked_list_t* restric * @param this The list * @return Non-zero on error, `errno` will have been set accordingly */ -int linked_list_pack(linked_list_t* restrict this) +int +linked_list_pack(linked_list_t *restrict this) { - ssize_t* restrict new_next = NULL; - ssize_t* restrict new_previous = NULL; - ssize_t* restrict new_reusable = NULL; - size_t size = this->end - this->reuse_head; - size_t cap = to_power_of_two(size); - ssize_t head = 0; - size_t i = 0; - ssize_t node; - size_t* restrict vals; - int saved_errno; - - fail_if (xmalloc(vals, cap, size_t)); - while (((size_t)head != this->end) && (this->next[head] == LINKED_LIST_UNUSED)) - head++; - if ((size_t)head != this->end) - for (node = head; (node != head) || (i == 0); i++) - { - vals[i] = this->values[node]; - node = this->next[node]; - } - - if (cap != this->capacity) - { - fail_if (xmalloc(new_next, cap, ssize_t)); - fail_if (xmalloc(new_previous, cap, ssize_t)); - fail_if (xmalloc(new_reusable, cap, ssize_t)); - - free(this->next); - free(this->previous); - free(this->reusable); - - this->next = new_next; - this->previous = new_previous; - this->reusable = new_reusable; - } - - for (i = 0; i < size; i++) - this->next[i] = (ssize_t)(i + 1); - this->next[size - 1] = 0; - - for (i = 1; i < size; i++) - this->previous[i] = (ssize_t)(i - 1); - this->previous[0] = (ssize_t)(size - 1); - - this->values = vals; - this->end = size; - this->reuse_head = 0; - - return 0; - - fail: - saved_errno = errno; - free(vals); - free(new_next); - free(new_previous); - return errno = saved_errno, -1; + ssize_t *restrict new_next = NULL; + ssize_t *restrict new_previous = NULL; + ssize_t *restrict new_reusable = NULL; + size_t size = this->end - this->reuse_head; + size_t cap = to_power_of_two(size); + ssize_t head = 0; + size_t i = 0; + ssize_t node; + size_t *restrict vals; + int saved_errno; + + fail_if (xmalloc(vals, cap, size_t)); + while ((size_t)head != this->end && this->next[head] == LINKED_LIST_UNUSED) + head++; + if ((size_t)head != this->end) { + for (node = head; (node != head) || (i == 0); i++) { + vals[i] = this->values[node]; + node = this->next[node]; + } + } + + if (cap != this->capacity) { + fail_if (xmalloc(new_next, cap, ssize_t)); + fail_if (xmalloc(new_previous, cap, ssize_t)); + fail_if (xmalloc(new_reusable, cap, ssize_t)); + + free(this->next); + free(this->previous); + free(this->reusable); + + this->next = new_next; + this->previous = new_previous; + this->reusable = new_reusable; + } + + for (i = 0; i < size; i++) + this->next[i] = (ssize_t)(i + 1); + this->next[size - 1] = 0; + + for (i = 1; i < size; i++) + this->previous[i] = (ssize_t)(i - 1); + this->previous[0] = (ssize_t)(size - 1); + + this->values = vals; + this->end = size; + this->reuse_head = 0; + + return 0; + +fail: + saved_errno = errno; + free(vals); + free(new_next); + free(new_previous); + return errno = saved_errno, -1; } @@ -215,29 +218,28 @@ int linked_list_pack(linked_list_t* restrict this) * @return The next free position, * `LINKED_LIST_UNUSED` on error, `errno` will be set accordingly */ -__attribute__((nonnull)) -static ssize_t linked_list_get_next(linked_list_t* restrict this) +static ssize_t __attribute__((nonnull)) +linked_list_get_next(linked_list_t *restrict this) { - size_t* tmp_values; - ssize_t* tmp; - - if (this->reuse_head > 0) - return this->reusable[--(this->reuse_head)]; - if (this->end == this->capacity) - { - if ((ssize_t)(this->end) < 0) - fail_if ((errno = ENOMEM)); - - this->capacity <<= 1; - - fail_if (yrealloc(tmp_values, this->values, this->capacity, size_t)); - fail_if (yrealloc(tmp, this->next, this->capacity, ssize_t)); - fail_if (yrealloc(tmp, this->previous, this->capacity, ssize_t)); - fail_if (yrealloc(tmp, this->reusable, this->capacity, ssize_t)); - } - return (ssize_t)(this->end++); - fail: - return LINKED_LIST_UNUSED; + size_t *tmp_values; + ssize_t *tmp; + + if (this->reuse_head > 0) + return this->reusable[--(this->reuse_head)]; + if (this->end == this->capacity) { + if ((ssize_t)(this->end) < 0) + fail_if ((errno = ENOMEM)); + + this->capacity <<= 1; + + fail_if (yrealloc(tmp_values, this->values, this->capacity, size_t)); + fail_if (yrealloc(tmp, this->next, this->capacity, ssize_t)); + fail_if (yrealloc(tmp, this->previous, this->capacity, ssize_t)); + fail_if (yrealloc(tmp, this->reusable, this->capacity, ssize_t)); + } + return (ssize_t)(this->end++); +fail: + return LINKED_LIST_UNUSED; } @@ -248,15 +250,15 @@ static ssize_t linked_list_get_next(linked_list_t* restrict this) * @param node The position * @return The position */ -__attribute__((nonnull)) -static ssize_t linked_list_unuse(linked_list_t* restrict this, ssize_t node) +static ssize_t __attribute__((nonnull)) +linked_list_unuse(linked_list_t *restrict this, ssize_t node) { - if (node < 0) - return node; - this->reusable[this->reuse_head++] = node; - this->next[node] = LINKED_LIST_UNUSED; - this->previous[node] = LINKED_LIST_UNUSED; - return node; + if (node < 0) + return node; + this->reusable[this->reuse_head++] = node; + this->next[node] = LINKED_LIST_UNUSED; + this->previous[node] = LINKED_LIST_UNUSED; + return node; } @@ -269,18 +271,19 @@ static ssize_t linked_list_unuse(linked_list_t* restrict this, ssize_t node) * @return The node that has been created and inserted, * `LINKED_LIST_UNUSED` on error, `errno` will be set accordingly */ -ssize_t linked_list_insert_after(linked_list_t* this, size_t value, ssize_t predecessor) +ssize_t +linked_list_insert_after(linked_list_t *this, size_t value, ssize_t predecessor) { - ssize_t node = linked_list_get_next(this); - fail_if (node == LINKED_LIST_UNUSED); - this->values[node] = value; - this->next[node] = this->next[predecessor]; - this->next[predecessor] = node; - this->previous[node] = predecessor; - this->previous[this->next[node]] = node; - return node; - fail: - return LINKED_LIST_UNUSED; + ssize_t node = linked_list_get_next(this); + fail_if (node == LINKED_LIST_UNUSED); + this->values[node] = value; + this->next[node] = this->next[predecessor]; + this->next[predecessor] = node; + this->previous[node] = predecessor; + this->previous[this->next[node]] = node; + return node; +fail: + return LINKED_LIST_UNUSED; } @@ -291,12 +294,13 @@ ssize_t linked_list_insert_after(linked_list_t* this, size_t value, ssize_t pred * @param predecessor The reference node * @return The node that has been removed */ -ssize_t linked_list_remove_after(linked_list_t* restrict this, ssize_t predecessor) +ssize_t +linked_list_remove_after(linked_list_t *restrict this, ssize_t predecessor) { - ssize_t node = this->next[predecessor]; - this->next[predecessor] = this->next[node]; - this->previous[this->next[node]] = predecessor; - return linked_list_unuse(this, node); + ssize_t node = this->next[predecessor]; + this->next[predecessor] = this->next[node]; + this->previous[this->next[node]] = predecessor; + return linked_list_unuse(this, node); } @@ -309,18 +313,19 @@ ssize_t linked_list_remove_after(linked_list_t* restrict this, ssize_t predecess * @return The node that has been created and inserted, * `LINKED_LIST_UNUSED` on error, `errno` will be set accordingly */ -ssize_t linked_list_insert_before(linked_list_t* restrict this, size_t value, ssize_t successor) +ssize_t +linked_list_insert_before(linked_list_t *restrict this, size_t value, ssize_t successor) { - ssize_t node = linked_list_get_next(this); - fail_if (node == LINKED_LIST_UNUSED); - this->values[node] = value; - this->previous[node] = this->previous[successor]; - this->previous[successor] = node; - this->next[node] = successor; - this->next[this->previous[node]] = node; - return node; - fail: - return LINKED_LIST_UNUSED; + ssize_t node = linked_list_get_next(this); + fail_if (node == LINKED_LIST_UNUSED); + this->values[node] = value; + this->previous[node] = this->previous[successor]; + this->previous[successor] = node; + this->next[node] = successor; + this->next[this->previous[node]] = node; + return node; +fail: + return LINKED_LIST_UNUSED; } @@ -331,12 +336,13 @@ ssize_t linked_list_insert_before(linked_list_t* restrict this, size_t value, ss * @param successor The reference node * @return The node that has been removed */ -ssize_t linked_list_remove_before(linked_list_t* restrict this, ssize_t successor) +ssize_t +linked_list_remove_before(linked_list_t *restrict this, ssize_t successor) { - ssize_t node = this->previous[successor]; - this->previous[successor] = this->previous[node]; - this->next[this->previous[node]] = successor; - return linked_list_unuse(this, node); + ssize_t node = this->previous[successor]; + this->previous[successor] = this->previous[node]; + this->next[this->previous[node]] = successor; + return linked_list_unuse(this, node); } @@ -346,11 +352,12 @@ ssize_t linked_list_remove_before(linked_list_t* restrict this, ssize_t successo * @param this The list * @param node The node to remove */ -void linked_list_remove(linked_list_t* restrict this, ssize_t node) +void +linked_list_remove(linked_list_t *restrict this, ssize_t node) { - this->next[this->previous[node]] = this->next[node]; - this->previous[this->next[node]] = this->previous[node]; - linked_list_unuse(this, node); + this->next[this->previous[node]] = this->next[node]; + this->previous[this->next[node]] = this->previous[node]; + linked_list_unuse(this, node); } @@ -360,9 +367,10 @@ void linked_list_remove(linked_list_t* restrict this, ssize_t node) * @param this The list * @return The number of bytes to allocate to the output buffer */ -size_t linked_list_marshal_size(const linked_list_t* restrict this) +size_t +linked_list_marshal_size(const linked_list_t *restrict this) { - return sizeof(size_t) * (4 + this->reuse_head + 3 * this->end) + sizeof(int); + return sizeof(size_t) * (4 + this->reuse_head + 3 * this->end) + sizeof(int); } @@ -372,27 +380,28 @@ size_t linked_list_marshal_size(const linked_list_t* restrict this) * @param this The list * @param data Output buffer for the marshalled data */ -void linked_list_marshal(const linked_list_t* restrict this, char* restrict data) +void +linked_list_marshal(const linked_list_t *restrict this, char *restrict data) { - buf_set(data, int, 0, LINKED_LIST_T_VERSION); - buf_next(data, int, 1); - - buf_set(data, size_t, 0, this->capacity); - buf_set(data, size_t, 1, this->end); - buf_set(data, size_t, 2, this->reuse_head); - buf_set(data, ssize_t, 3, this->edge); - buf_next(data, size_t, 4); - - memcpy(data, this->reusable, this->reuse_head * sizeof(ssize_t)); - buf_next(data, ssize_t, this->reuse_head); - - memcpy(data, this->values, this->end * sizeof(size_t)); - buf_next(data, size_t, this->end); - - memcpy(data, this->next, this->end * sizeof(ssize_t)); - buf_next(data, ssize_t, this->end); - - memcpy(data, this->previous, this->end * sizeof(ssize_t)); + buf_set(data, int, 0, LINKED_LIST_T_VERSION); + buf_next(data, int, 1); + + buf_set(data, size_t, 0, this->capacity); + buf_set(data, size_t, 1, this->end); + buf_set(data, size_t, 2, this->reuse_head); + buf_set(data, ssize_t, 3, this->edge); + buf_next(data, size_t, 4); + + memcpy(data, this->reusable, this->reuse_head * sizeof(ssize_t)); + buf_next(data, ssize_t, this->reuse_head); + + memcpy(data, this->values, this->end * sizeof(size_t)); + buf_next(data, size_t, this->end); + + memcpy(data, this->next, this->end * sizeof(ssize_t)); + buf_next(data, ssize_t, this->end); + + memcpy(data, this->previous, this->end * sizeof(ssize_t)); } @@ -404,41 +413,42 @@ void linked_list_marshal(const linked_list_t* restrict this, char* restrict data * @return Non-zero on error, `errno` will be set accordingly. * Destroy the list on error. */ -int linked_list_unmarshal(linked_list_t* restrict this, char* restrict data) +int +linked_list_unmarshal(linked_list_t *restrict this, char *restrict data) { - /* buf_get(data, int, 0, LINKED_LIST_T_VERSION); */ - buf_next(data, int, 1); - - this->reusable = NULL; - this->values = NULL; - this->next = NULL; - this->previous = NULL; - - buf_get(data, size_t, 0, this->capacity); - buf_get(data, size_t, 1, this->end); - buf_get(data, size_t, 2, this->reuse_head); - buf_get(data, ssize_t, 3, this->edge); - buf_next(data, size_t, 4); - - fail_if (xmalloc(this->reusable, this->capacity, size_t)); - fail_if (xmalloc(this->values, this->capacity, size_t)); - fail_if (xmalloc(this->next, this->capacity, size_t)); - fail_if (xmalloc(this->previous, this->capacity, size_t)); - - memcpy(this->reusable, data, this->reuse_head * sizeof(ssize_t)); - buf_next(data, ssize_t, this->reuse_head); - - memcpy(this->values, data, this->end * sizeof(size_t)); - buf_next(data, size_t, this->end); - - memcpy(this->next, data, this->end * sizeof(ssize_t)); - buf_next(data, ssize_t, this->end); - - memcpy(this->previous, data, this->end * sizeof(ssize_t)); - - return 0; - fail: - return -1; + /* buf_get(data, int, 0, LINKED_LIST_T_VERSION); */ + buf_next(data, int, 1); + + this->reusable = NULL; + this->values = NULL; + this->next = NULL; + this->previous = NULL; + + buf_get(data, size_t, 0, this->capacity); + buf_get(data, size_t, 1, this->end); + buf_get(data, size_t, 2, this->reuse_head); + buf_get(data, ssize_t, 3, this->edge); + buf_next(data, size_t, 4); + + fail_if (xmalloc(this->reusable, this->capacity, size_t)); + fail_if (xmalloc(this->values, this->capacity, size_t)); + fail_if (xmalloc(this->next, this->capacity, size_t)); + fail_if (xmalloc(this->previous, this->capacity, size_t)); + + memcpy(this->reusable, data, this->reuse_head * sizeof(ssize_t)); + buf_next(data, ssize_t, this->reuse_head); + + memcpy(this->values, data, this->end * sizeof(size_t)); + buf_next(data, size_t, this->end); + + memcpy(this->next, data, this->end * sizeof(ssize_t)); + buf_next(data, ssize_t, this->end); + + memcpy(this->previous, data, this->end * sizeof(ssize_t)); + + return 0; +fail: + return -1; } @@ -448,31 +458,31 @@ int linked_list_unmarshal(linked_list_t* restrict this, char* restrict data) * @param this The list * @param output Output file */ -void linked_list_dump(linked_list_t* restrict this, FILE* restrict output) +void +linked_list_dump(linked_list_t *restrict this, FILE *restrict output) { - ssize_t i; - size_t j; - fprintf(output, "======= LINKED LIST DUMP =======\n"); - fprintf(output, "Capacity: %zu\n", this->capacity); - fprintf(output, "End: %zu\n", this->end); - fprintf(output, "Reuse head: %zu\n", this->reuse_head); - fprintf(output, "Edge: %zi\n", this->edge); - fprintf(output, "--------------------------------\n"); - fprintf(output, "Node table (Next, Prev, Value):\n"); - i = this->edge; - fprintf(output, " %zi: %zi, %zi, %zu\n", i, this->next[i], this->previous[i], this->values[i]); - foreach_linked_list_node((*this), i) - fprintf(output, " %zi: %zi, %zi, %zu\n", i, this->next[i], this->previous[i], this->values[i]); - i = this->edge; - fprintf(output, " %zi: %zi, %zi, %zu\n", i, this->next[i], this->previous[i], this->values[i]); - fprintf(output, "--------------------------------\n"); - fprintf(output, "Raw node table:\n"); - for (j = 0; j < this->end; j++) - fprintf(output, " %zu: %zi, %zi, %zu\n", i, this->next[i], this->previous[i], this->values[i]); - fprintf(output, "--------------------------------\n"); - fprintf(output, "Reuse stack:\n"); - for (j = 0; j < this->reuse_head; j++) - fprintf(output, " %zu: %zi\n", j, this->reusable[j]); - fprintf(output, "================================\n"); + ssize_t i; + size_t j; + fprintf(output, "======= LINKED LIST DUMP =======\n"); + fprintf(output, "Capacity: %zu\n", this->capacity); + fprintf(output, "End: %zu\n", this->end); + fprintf(output, "Reuse head: %zu\n", this->reuse_head); + fprintf(output, "Edge: %zi\n", this->edge); + fprintf(output, "--------------------------------\n"); + fprintf(output, "Node table (Next, Prev, Value):\n"); + i = this->edge; + fprintf(output, " %zi: %zi, %zi, %zu\n", i, this->next[i], this->previous[i], this->values[i]); + foreach_linked_list_node((*this), i) + fprintf(output, " %zi: %zi, %zi, %zu\n", i, this->next[i], this->previous[i], this->values[i]); + i = this->edge; + fprintf(output, " %zi: %zi, %zi, %zu\n", i, this->next[i], this->previous[i], this->values[i]); + fprintf(output, "--------------------------------\n"); + fprintf(output, "Raw node table:\n"); + for (j = 0; j < this->end; j++) + fprintf(output, " %zu: %zi, %zi, %zu\n", i, this->next[i], this->previous[i], this->values[i]); + fprintf(output, "--------------------------------\n"); + fprintf(output, "Reuse stack:\n"); + for (j = 0; j < this->reuse_head; j++) + fprintf(output, " %zu: %zi\n", j, this->reusable[j]); + fprintf(output, "================================\n"); } - diff --git a/src/libmdsserver/macros.h b/src/libmdsserver/macros.h index d4d588c..45412b9 100644 --- a/src/libmdsserver/macros.h +++ b/src/libmdsserver/macros.h @@ -44,24 +44,22 @@ /* CLOCK_MONOTONIC_RAW is a Linux-specific bug-fix */ #ifndef CLOCK_MONOTONIC_RAW -# define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC +# define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC #endif /* Define TEMP_FAILURE_RETRY if not defined, however * this version does not return a value, it will hoever * clear `errno` if no error occurs. */ #ifndef TEMP_FAILURE_RETRY -# define TEMP_FAILURE_RETRY(expression) \ - do \ - { \ - ssize_t __result; \ - do \ - __result = (ssize_t)(expression); \ - while ((__result < 0) && (errno == EINTR)); \ - if (__result >= 0) \ - errno = 0; \ - } \ - while (0) +# define TEMP_FAILURE_RETRY(expression)\ + do {\ + ssize_t __result;\ + do\ + __result = (ssize_t)(expression);\ + while (__result < 0 && errno == EINTR);\ + if (__result >= 0)\ + errno = 0;\ + } while (0) # define MDS_LIBMDSSERVER_MACROS_DEFINED_TEMP_FAILURE_RETRY #endif @@ -118,16 +116,16 @@ * @param ...:const char*, ... The format string and arguments * @return :int Zero on success, -1 on error */ -#define xasprintf(VAR, ...) \ - (asprintf(&(VAR), __VA_ARGS__) < 0 ? (VAR = NULL, -1) : 0) +#define xasprintf(VAR, ...)\ + (asprintf(&(VAR), __VA_ARGS__) < 0 ? (VAR = NULL, -1) : 0) /* -#define xasprintf(VAR, ...) \ - ({ \ - int _x_rc = (asprintf(&(VAR), __VA_ARGS__) < 0 ? (VAR = NULL, -1) : 0); \ - fprintf(stderr, "xasprintf(%s, %s)(=%zu) @ %s:%i\n", \ - #VAR, #__VA_ARGS__, _x_rc ? 0 : (strlen(VAR) + 1), __FILE__, __LINE__); \ - _x_rc; \ - }) +#define xasprintf(VAR, ...)\ + ({\ + int _x_rc = (asprintf(&(VAR), __VA_ARGS__) < 0 ? (VAR = NULL, -1) : 0);\ + fprintf(stderr, "xasprintf(%s, %s)(=%zu) @ %s:%i\n",\ + #VAR, #__VA_ARGS__, _x_rc ? 0 : (strlen(VAR) + 1), __FILE__, __LINE__);\ + _x_rc;\ + }) */ @@ -138,8 +136,8 @@ * @param ...:const char*, ... The format string and arguments * @return :int The number of bytes written, including the NUL-termination, negative on error */ -#define xsnprintf(buffer, ...) \ - snprintf(buffer, sizeof(buffer) / sizeof(char), __VA_ARGS__) +#define xsnprintf(buffer, ...)\ + snprintf(buffer, sizeof(buffer) / sizeof(char), __VA_ARGS__) /** @@ -149,8 +147,8 @@ * @param format:const char* The format * @return :int The number of bytes written, including the NUL-termination, negative on error */ -#define eprint(format) \ - fprintf(stderr, "%s: " format "\n", *argv) +#define eprint(format)\ + fprintf(stderr, "%s: " format "\n", *argv) /** @@ -161,8 +159,8 @@ * @param ... The arguments * @return :int The number of bytes written, including the NUL-termination, negative on error */ -#define eprintf(format, ...) \ - fprintf(stderr, "%s: " format "\n", *argv, __VA_ARGS__) +#define eprintf(format, ...)\ + fprintf(stderr, "%s: " format "\n", *argv, __VA_ARGS__) /** @@ -174,8 +172,8 @@ * @param format:const char* The format * @return :int The number of bytes written, including the NUL-termination, negative on error */ -#define iprint(format) \ - fprintf(stderr, "%s: info: " format "\n", *argv) +#define iprint(format)\ + fprintf(stderr, "%s: info: " format "\n", *argv) /** @@ -188,8 +186,8 @@ * @param ... The arguments * @return :int The number of bytes written, including the NUL-termination, negative on error */ -#define iprintf(format, ...) \ - fprintf(stderr, "%s: info: " format "\n", *argv, __VA_ARGS__) +#define iprintf(format, ...)\ + fprintf(stderr, "%s: info: " format "\n", *argv, __VA_ARGS__) /** @@ -198,18 +196,14 @@ * @param mutex:pthread_mutex_t The mutex * @param instructions The instructions to run while the mutex is locked */ -#define with_mutex(mutex, instructions) \ - do \ - { \ - errno = pthread_mutex_lock(&(mutex)); \ - do \ - { \ - instructions ; \ - } \ - while (0); \ - errno = pthread_mutex_unlock(&(mutex)); \ - } \ - while (0) +#define with_mutex(mutex, instructions)\ + do {\ + errno = pthread_mutex_lock(&mutex);\ + do {\ + instructions;\ + } while (0);\ + errno = pthread_mutex_unlock(&mutex);\ + } while (0) /** * Wrapper for `pthread_mutex_lock` and `pthread_mutex_unlock` with an embedded if-statement @@ -218,19 +212,14 @@ * @parma condition The condition to test * @param instructions The instructions to run while the mutex is locked */ -#define with_mutex_if(mutex, condition, instructions) \ - do \ - { \ - errno = pthread_mutex_lock(&(mutex)); \ - if (condition) \ - do \ - { \ - instructions ; \ - } \ - while (0); \ - errno = pthread_mutex_unlock(&(mutex)); \ - } \ - while (0) +#define with_mutex_if(mutex, condition, instructions)\ + do {\ + errno = pthread_mutex_lock(&mutex);\ + if (condition) {\ + instructions;\ + }\ + errno = pthread_mutex_unlock(&mutex);\ + } while (0) /** @@ -240,8 +229,8 @@ * @param b The other one of the values * @return The maximum value */ -#define max(a, b) \ - (a < b ? b : a) +#define max(a, b)\ + ((a) < (b) ? (b) : (a)) /** @@ -251,8 +240,8 @@ * @param b The other one of the values * @return The minimum value */ -#define min(a, b) \ - (a < b ? a : b) +#define min(a, b)\ + ((a) < (b) ? (a) : (b)) /** @@ -263,8 +252,8 @@ * @param index:size_t The index of the element to address * @return [type] A slot that can be set or get */ -#define buf_cast(buffer, type, index) \ - (((type*)(buffer))[index]) +#define buf_cast(buffer, type, index)\ + (((type *)(buffer))[index]) /** @@ -276,8 +265,8 @@ * @param variable:type The new value of the element * @return variable: The new value of the element */ -#define buf_set(buffer, type, index, variable) \ - (((type*)(buffer))[index] = (variable)) +#define buf_set(buffer, type, index, variable)\ + (((type *)(buffer))[index] = (variable)) /** @@ -289,8 +278,8 @@ * @param variable:type Slot to set with the value of the element * @return variable: The value of the element */ -#define buf_get(buffer, type, index, variable) \ - (variable = ((const type*)(buffer))[index]) +#define buf_get(buffer, type, index, variable)\ + (variable = ((const type*)(buffer))[index]) /** @@ -301,8 +290,8 @@ * @param count:size_t The number elements of the data type `type` to increase the pointer with * @return buffer: The buffer */ -#define buf_next(buffer, type, count) \ - (buffer += (count) * sizeof(type) / sizeof(char)) +#define buf_next(buffer, type, count)\ + (buffer += (count) * sizeof(type) / sizeof(char)) /** @@ -313,8 +302,8 @@ * @param count:size_t The number elements of the data type `type` to decrease the pointer with * @return buffer: The buffer */ -#define buf_prev(buffer, type, count) \ - (buffer -= (count) * sizeof(type) / sizeof(char)) +#define buf_prev(buffer, type, count)\ + (buffer -= (count) * sizeof(type) / sizeof(char)) /** @@ -326,9 +315,9 @@ * @param variable:type The new value of the element * @return variable: The new value of the element */ -#define buf_set_next(buffer, type, variable) \ - (buf_set(buffer, type, 0, variable), \ - buf_next(buffer, type, 1)) +#define buf_set_next(buffer, type, variable)\ + (buf_set(buffer, type, 0, variable),\ + buf_next(buffer, type, 1)) /** @@ -340,9 +329,9 @@ * @param variable:type Slot to set with the value of the element * @return variable: The value of the element */ -#define buf_get_next(buffer, type, variable) \ - (buf_get(buffer, type, 0, variable), \ - buf_next(buffer, type, 1)) +#define buf_get_next(buffer, type, variable)\ + (buf_get(buffer, type, 0, variable),\ + buf_next(buffer, type, 1)) /** @@ -352,8 +341,8 @@ * @param b:const char* The other of the strings * @return :int Whether the strings are equal */ -#define strequals(a, b) \ - (strcmp(a, b) == 0) +#define strequals(a, b)\ + (!strcmp(a, b)) /** @@ -363,8 +352,8 @@ * @param needle:const char* The string `haystack` should start with * @return :int Whether `haystack` starts with `needle` */ -#define startswith(haystack, needle) \ - (strstr(haystack, needle) == haystack) +#define startswith(haystack, needle)\ + (strstr(haystack, needle) == haystack) /** @@ -374,9 +363,9 @@ * * @return :int Non-zero on error */ -#define drop_privileges() \ - ((getegid() == getgid() ? 0 : setegid(getgid())) || \ - (geteuid() == getuid() ? 0 : seteuid(getuid()))) +#define drop_privileges()\ + ((getegid() == getgid() ? 0 : setegid(getgid())) ||\ + (geteuid() == getuid() ? 0 : seteuid(getuid()))) /** @@ -386,8 +375,8 @@ * @param time_slot:struct timespec* Pointer to the variable in which to store the time * @return :int Zero on success, -1 on error */ -#define monotone(time_slot) \ - clock_gettime(CLOCK_MONOTONIC_RAW, time_slot) +#define monotone(time_slot)\ + clock_gettime(CLOCK_MONOTONIC_RAW, time_slot) /** @@ -397,15 +386,15 @@ * @param fd:int The file descriptor */ #if 1 /* For kernels that ensure that close(2) always closes valid file descriptors. */ -# define xclose(fd) \ - close(fd) +# define xclose(fd)\ + close(fd) #else /* For kernels that ensure that close(2) never closes valid file descriptors on interruption. */ # ifdef MDS_LIBMDSSERVER_MACROS_DEFINED_TEMP_FAILURE_RETRY -# define xclose(fd) \ - TEMP_FAILURE_RETRY(close(fd)) +# define xclose(fd)\ + TEMP_FAILURE_RETRY(close(fd)) # else -# define xclose(fd) \ - (TEMP_FAILURE_RETRY(close(fd)) < 0 ? 0 : (errno = 0)) +# define xclose(fd)\ + (TEMP_FAILURE_RETRY(close(fd)) < 0 ? 0 : (errno = 0)) # endif #endif @@ -417,15 +406,15 @@ * @param f:FILE* The stream */ #if 1 /* For kernels that ensure that close(2) always closes valid file descriptors. */ -# define xfclose(f) \ - fclose(f) +# define xfclose(f)\ + fclose(f) #else /* For kernels that ensure that close(2) never closes valid file descriptors on interruption. */ # ifdef MDS_LIBMDSSERVER_MACROS_DEFINED_TEMP_FAILURE_RETRY -# define xfclose(f) \ - TEMP_FAILURE_RETRY(fclose(f)) +# define xfclose(f)\ + TEMP_FAILURE_RETRY(fclose(f)) # else -# define xfclose(f) \ - (TEMP_FAILURE_RETRY(fclose(f)) < 0 ? 0 : (errno = 0)) +# define xfclose(f)\ + (TEMP_FAILURE_RETRY(fclose(f)) < 0 ? 0 : (errno = 0)) # endif #endif @@ -435,29 +424,27 @@ * * @param condition The condition, it should evaluate the variable `fd` */ -#define close_files(condition) \ - do \ - { \ - DIR* dir = opendir(SELF_FD); \ - struct dirent* file; \ - \ - if (dir == NULL) \ - perror(*argv); /* Well, that is just unfortunate, but we cannot really do anything. */ \ - else \ - { \ - int dfd = dirfd(dir); \ - while ((file = readdir(dir)) != NULL) \ - if (strcmp(file->d_name, ".") && strcmp(file->d_name, "..")) \ - { \ - int fd = atoi(file->d_name); \ - if (fd != dfd) \ - if (condition) \ - xclose(fd); \ - } \ - closedir(dir); \ - } \ - } \ - while (0) +#define close_files(condition)\ + do {\ + DIR *dir = opendir(SELF_FD);\ + struct dirent *file;\ + int dfd, fd;\ + \ + if (!dir) {\ + perror(*argv); /* Well, that is just unfortunate, but we cannot really do anything. */\ + } else {\ + dfd = dirfd(dir);\ + while ((file = readdir(dir))) {\ + if (strcmp(file->d_name, ".") && strcmp(file->d_name, "..")) {\ + fd = atoi(file->d_name);\ + if (fd != dfd)\ + if (condition)\ + xclose(fd);\ + }\ + }\ + closedir(dir);\ + }\ + } while (0) /** @@ -467,14 +454,13 @@ * @param elements:size_t The number of elements, in the array, to free * @scope i:size_t The variable `i` must be declared as `size_t` and avaiable for use */ -#define xfree(array, elements) \ - do \ - { \ - for (i = 0; i < (elements); i++) \ - free((array)[i]); \ - free(array), (array) = NULL; \ - } \ - while (0) +#define xfree(array, elements)\ + do {\ + for (i = 0; i < (elements); i++)\ + free((array)[i]);\ + free(array);\ + (array) = NULL;\ + } while (0) /** @@ -485,17 +471,17 @@ * @param type The data type of the elements for which to create an allocation * @return :int Evaluates to true if an only if the allocation failed */ -#define xmalloc(var, elements, type) \ - ((var = malloc((elements) * sizeof(type))) == NULL) +#define xmalloc(var, elements, type)\ + (!(var = malloc((elements) * sizeof(type)))) /* -#define xmalloc(var, elements, type) \ - ({ \ - size_t _x_elements = (elements); \ - size_t _x_size = _x_elements * sizeof(type); \ - fprintf(stderr, "xmalloc(%s, %zu, %s)(=%zu) @ %s:%i\n", \ - #var, _x_elements, #type, _x_size, __FILE__, __LINE__); \ - ((var = malloc(_x_size)) == NULL); \ - }) +#define xmalloc(var, elements, type)\ + ({\ + size_t _x_elements = (elements);\ + size_t _x_size = _x_elements * sizeof(type);\ + fprintf(stderr, "xmalloc(%s, %zu, %s)(=%zu) @ %s:%i\n",\ + #var, _x_elements, #type, _x_size, __FILE__, __LINE__);\ + (!(var = malloc(_x_size)));\ + }) */ @@ -506,16 +492,16 @@ * @param bytes:size_t The number of bytes to allocate * @return :int Evaluates to true if an only if the allocation failed */ -#define xbmalloc(var, bytes) \ - ((var = malloc(bytes)) == NULL) +#define xbmalloc(var, bytes) \ + (!(var = malloc(bytes))) /* -#define xbmalloc(var, bytes) \ - ({ \ - size_t _x_bytes = (bytes); \ - fprintf(stderr, "xbmalloc(%s, %zu) @ %s:%i\n", \ - #var, _x_bytes, __FILE__, __LINE__); \ - ((var = malloc(_x_bytes)) == NULL); \ - }) +#define xbmalloc(var, bytes)\ + ({\ + size_t _x_bytes = (bytes);\ + fprintf(stderr, "xbmalloc(%s, %zu) @ %s:%i\n",\ + #var, _x_bytes, __FILE__, __LINE__);\ + (!(var = malloc(_x_bytes)));\ + }) */ @@ -527,17 +513,17 @@ * @param type The data type of the elements for which to create an allocation * @return :int Evaluates to true if an only if the allocation failed */ -#define xcalloc(var, elements, type) \ - ((var = calloc(elements, sizeof(type))) == NULL) +#define xcalloc(var, elements, type)\ + (!(var = calloc(elements, sizeof(type)))) /* -#define xcalloc(var, elements, type) \ - ({ \ - size_t _x_elements = (elements); \ - size_t _x_size = _x_elements * sizeof(type); \ - fprintf(stderr, "xcalloc(%s, %zu, %s)(=%zu) @ %s:%i\n", \ - #var, _x_elements, #type, _x_size, __FILE__, __LINE__); \ - ((var = calloc(_x_elements, sizeof(type))) == NULL); \ - }) +#define xcalloc(var, elements, type)\ + ({\ + size_t _x_elements = (elements);\ + size_t _x_size = _x_elements * sizeof(type);\ + fprintf(stderr, "xcalloc(%s, %zu, %s)(=%zu) @ %s:%i\n",\ + #var, _x_elements, #type, _x_size, __FILE__, __LINE__);\ + (!(var = calloc(_x_elements, sizeof(type))));\ + }) */ @@ -548,16 +534,16 @@ * @param bytes:size_t The number of bytes to allocate * @return :int Evaluates to true if an only if the allocation failed */ -#define xbcalloc(var, bytes) \ - ((var = calloc(bytes, sizeof(char))) == NULL) +#define xbcalloc(var, bytes)\ + (!(var = calloc(bytes, sizeof(char)))) /* -#define xbcalloc(var, bytes) \ - ({ \ - size_t _x_bytes = (bytes); \ - fprintf(stderr, "xbcalloc(%s, %zu) @ %s:%i\n", \ - #var, _x_bytes, __FILE__, __LINE__); \ - ((var = calloc(_x_bytes, sizeof(char))) == NULL); \ - }) +#define xbcalloc(var, bytes)\ + ({\ + size_t _x_bytes = (bytes);\ + fprintf(stderr, "xbcalloc(%s, %zu) @ %s:%i\n",\ + #var, _x_bytes, __FILE__, __LINE__);\ + (!(var = calloc(_x_bytes, sizeof(char))));\ + }) */ @@ -570,16 +556,16 @@ * @return :int Evaluates to true if an only if the allocation failed */ #define xrealloc(var, elements, type) \ - ((var = realloc(var, (elements) * sizeof(type))) == NULL) + (!(var = realloc(var, (elements) * sizeof(type)))) /* -#define xrealloc(var, elements, type) \ - ({ \ - size_t _x_elements = (elements); \ - size_t _x_size = _x_elements * sizeof(type); \ - fprintf(stderr, "xrealloc(%s, %zu, %s)(=%zu) @ %s:%i\n", \ - #var, _x_elements, #type, _x_size, __FILE__, __LINE__); \ - ((var = realloc(var, _x_size)) == NULL); \ - }) +#define xrealloc(var, elements, type)\ + ({\ + size_t _x_elements = (elements);\ + size_t _x_size = _x_elements * sizeof(type);\ + fprintf(stderr, "xrealloc(%s, %zu, %s)(=%zu) @ %s:%i\n",\ + #var, _x_elements, #type, _x_size, __FILE__, __LINE__);\ + (!(var = realloc(var, _x_size)));\ + }) */ @@ -593,17 +579,17 @@ * @param type The data type of the elements for which to create an allocation * @return :int Evaluates to true if an only if the allocation failed */ -#define xxrealloc(old, var, elements, type) \ - (old = var, (((var = realloc(var, (elements) * sizeof(type))) == NULL) ? 1 : (old = NULL, 0))) +#define xxrealloc(old, var, elements, type)\ + (old = var, ((!(var = realloc(var, (elements) * sizeof(type)))) ? 1 : (old = NULL, 0))) /* -#define xxrealloc(old, var, elements, type) \ - ({ \ - size_t _x_elements = (elements); \ - size_t _x_size = _x_elements * sizeof(type); \ - fprintf(stderr, "xxrealloc(%s, %s, %zu, %s)(=%zu) @ %s:%i\n", \ - #old, #var, _x_elements, #type, _x_size, __FILE__, __LINE__); \ - (old = var, (((var = realloc(var, _x_size)) == NULL) ? 1 : (old = NULL, 0))); \ - }) +#define xxrealloc(old, var, elements, type)\ + ({\ + size_t _x_elements = (elements);\ + size_t _x_size = _x_elements * sizeof(type);\ + fprintf(stderr, "xxrealloc(%s, %s, %zu, %s)(=%zu) @ %s:%i\n",\ + #old, #var, _x_elements, #type, _x_size, __FILE__, __LINE__);\ + (old = var, ((!(var = realloc(var, _x_size))) ? 1 : (old = NULL, 0)));\ + }) */ @@ -616,19 +602,19 @@ * @param type The data type of the elements for which to create an allocation * @return :int Evaluates to true if an only if the allocation failed */ -#define yrealloc(tmp, var, elements, type) \ - ((tmp = var, (var = realloc(var, (elements) * sizeof(type))) == NULL) \ - ? (var = tmp, tmp = NULL, 1) : (tmp = NULL, 0)) +#define yrealloc(tmp, var, elements, type)\ + ((tmp = var, !(var = realloc(var, (elements) * sizeof(type))))\ + ? (var = tmp, tmp = NULL, 1) : (tmp = NULL, 0)) /* -#define yrealloc(tmp, var, elements, type) \ - ({ \ - size_t _x_elements = (elements); \ - size_t _x_size = _x_elements * sizeof(type); \ - fprintf(stderr, "yrealloc(%s, %s, %zu, %s)(=%zu) @ %s:%i\n", \ - #tmp, #var, _x_elements, #type, _x_size, __FILE__, __LINE__); \ - ((tmp = var, (var = realloc(var, _x_size)) == NULL) \ - ? (var = tmp, tmp = NULL, 1) : (tmp = NULL, 0)); \ - }) +#define yrealloc(tmp, var, elements, type)\ + ({\ + size_t _x_elements = (elements);\ + size_t _x_size = _x_elements * sizeof(type);\ + fprintf(stderr, "yrealloc(%s, %s, %zu, %s)(=%zu) @ %s:%i\n",\ + #tmp, #var, _x_elements, #type, _x_size, __FILE__, __LINE__);\ + ((tmp = var, !(var = realloc(var, _x_size)))\ + ? (var = tmp, tmp = NULL, 1) : (tmp = NULL, 0));\ + }) */ @@ -641,17 +627,17 @@ * @param type The data type of the elements for which to create an allocation * @return :int Evaluates to true if an only if the allocation failed */ -#define growalloc(old, var, elements, type) \ - (old = var, xrealloc(var, (elements) <<= 1, type) ? (var = old, (elements) >>= 1, 1) : 0) +#define growalloc(old, var, elements, type) \ + (old = var, xrealloc(var, (elements) <<= 1, type) ? (var = old, (elements) >>= 1, 1) : 0) /* -#define growalloc(old, var, elements, type) \ - ({ \ - size_t _x_elements_ = (elements); \ - size_t _x_size_ = _x_elements_ * sizeof(type); \ - fprintf(stderr, "growalloc(%s, %s, %zu, %s)(=%zu)\n--> ", \ - #old, #var, _x_elements_, #type, _x_size_, __FILE__, __LINE__); \ - (old = var, xrealloc(var, (elements) <<= 1, type) ? (var = old, (elements) >>= 1, 1) : 0); \ - }) +#define growalloc(old, var, elements, type)\ + ({\ + size_t _x_elements_ = (elements);\ + size_t _x_size_ = _x_elements_ * sizeof(type);\ + fprintf(stderr, "growalloc(%s, %s, %zu, %s)(=%zu)\n--> ",\ + #old, #var, _x_elements_, #type, _x_size_, __FILE__, __LINE__);\ + (old = var, xrealloc(var, (elements) <<= 1, type) ? (var = old, (elements) >>= 1, 1) : 0);\ + }) */ @@ -662,16 +648,16 @@ * @param original:const char* The string to duplicate, may be `NULL` * @return :int Evaluates to true if an only if the allocation failed */ -#define xstrdup(var, original) \ - (original ? ((var = strdup(original)) == NULL) : (var = NULL, 0)) +#define xstrdup(var, original)\ + (original ? !(var = strdup(original)) : (var = NULL, 0)) /* -#define xstrdup(var, original) \ - ({ \ - size_t _x_size = original ? strlen(original) : 0; \ - fprintf(stderr, "xstrdup(%s, %s(“%s”=%zu))(=%zu) @ %s:%i\n", \ - #var, #original, original, _x_size, _x_size + !!_x_size, __FILE__, __LINE__); \ - (original ? ((var = strdup(original)) == NULL) : (var = NULL, 0)); \ - }) +#define xstrdup(var, original)\ + ({\ + size_t _x_size = original ? strlen(original) : 0;\ + fprintf(stderr, "xstrdup(%s, %s(“%s”=%zu))(=%zu) @ %s:%i\n",\ + #var, #original, original, _x_size, _x_size + !!_x_size, __FILE__, __LINE__);\ + (original ? ((var = strdup(original)) == NULL) : (var = NULL, 0));\ + }) */ @@ -685,16 +671,16 @@ * @param original:const char* The string to duplicate, must not be `NULL` * @return :int Evaluates to true if an only if the allocation failed */ -#define xstrdup_nn(var, original) \ - ((var = strdup(original)) == NULL) +#define xstrdup_nn(var, original)\ + (!(var = strdup(original))) /* -#define xstrdup_nn(var, original) \ - ({ \ - size_t _x_size = strlen(original); \ - fprintf(stderr, "xstrdup_nn(%s, %s(“%s”=%zu))(=%zu) @ %s:%i\n", \ - #var, #original, original, _x_size, _x_size + !!_x_size, __FILE__, __LINE__); \ - (var = strdup(original)) == NULL; \ - }) +#define xstrdup_nn(var, original)\ + ({\ + size_t _x_size = strlen(original);\ + fprintf(stderr, "xstrdup_nn(%s, %s(“%s”=%zu))(=%zu) @ %s:%i\n",\ + #var, #original, original, _x_size, _x_size + !!_x_size, __FILE__, __LINE__);\ + !(var = strdup(original));\ + }) */ @@ -708,18 +694,18 @@ * @param type The data type of the elements to duplicate * @return :int Evaluates to true if an only if the allocation failed */ -#define xmemdup(var, original, elements, type) \ - (((var = malloc((elements) * sizeof(type))) == NULL) ? 1 : \ - (memcpy(var, original, (elements) * sizeof(type)), 0)) +#define xmemdup(var, original, elements, type)\ + (!(var = malloc((elements) * sizeof(type))) ? 1 :\ + (memcpy(var, original, (elements) * sizeof(type)), 0)) /* -#define xmemdup(var, original, elements, type) \ - ({ \ - size_t _x_elements = (elements); \ - size_t _x_size = _x_elements * sizeof(type); \ - fprintf(stderr, "xmemdup(%s, %s, %zu, %s)(=%zu) @ %s:%i\n", \ - #var, #original, _x_elements, #type, _x_size, __FILE__, __LINE__); \ - (((var = malloc(_x_size)) == NULL) ? 1 : (memcpy(var, original, _x_size), 0)); \ - }) +#define xmemdup(var, original, elements, type)\ + ({\ + size_t _x_elements = (elements);\ + size_t _x_size = _x_elements * sizeof(type);\ + fprintf(stderr, "xmemdup(%s, %s, %zu, %s)(=%zu) @ %s:%i\n",\ + #var, #original, _x_elements, #type, _x_size, __FILE__, __LINE__);\ + !(var = malloc(_x_size)) ? 1 : (memcpy(var, original, _x_size), 0);\ + }) */ diff --git a/src/libmdsserver/mds-message.c b/src/libmdsserver/mds-message.c index 4ec8142..c3d968f 100644 --- a/src/libmdsserver/mds-message.c +++ b/src/libmdsserver/mds-message.c @@ -27,7 +27,7 @@ #include -#define try(INSTRUCTION) if ((r = INSTRUCTION) < 0) return r +#define try(INSTRUCTION) do { if ((r = INSTRUCTION) < 0) return r; } while (0) /** @@ -38,20 +38,21 @@ * @return Non-zero on error, `errno` will be set accordingly. * Destroy the message on error. */ -int mds_message_initialise(mds_message_t* restrict this) +int +mds_message_initialise(mds_message_t *restrict this) { - this->headers = NULL; - this->header_count = 0; - this->payload = NULL; - this->payload_size = 0; - this->payload_ptr = 0; - this->buffer_size = 128; - this->buffer_ptr = 0; - this->stage = 0; - fail_if (xmalloc(this->buffer, this->buffer_size, char)); - return 0; - fail: - return -1; + this->headers = NULL; + this->header_count = 0; + this->payload = NULL; + this->payload_size = 0; + this->payload_ptr = 0; + this->buffer_size = 128; + this->buffer_ptr = 0; + this->stage = 0; + fail_if (xmalloc(this->buffer, this->buffer_size, char)); + return 0; +fail: + return -1; } @@ -60,17 +61,18 @@ int mds_message_initialise(mds_message_t* restrict this) * * @param this Memory slot in which to store the new message */ -void mds_message_zero_initialise(mds_message_t* restrict this) +void +mds_message_zero_initialise(mds_message_t *restrict this) { - this->headers = NULL; - this->header_count = 0; - this->payload = NULL; - this->payload_size = 0; - this->payload_ptr = 0; - this->buffer = NULL; - this->buffer_size = 0; - this->buffer_ptr = 0; - this->stage = 0; + this->headers = NULL; + this->header_count = 0; + this->payload = NULL; + this->payload_size = 0; + this->payload_ptr = 0; + this->buffer = NULL; + this->buffer_size = 0; + this->buffer_ptr = 0; + this->stage = 0; } @@ -80,14 +82,15 @@ void mds_message_zero_initialise(mds_message_t* restrict this) * * @param this The message */ -void mds_message_destroy(mds_message_t* restrict this) +void +mds_message_destroy(mds_message_t *restrict this) { - size_t i; - if (this->headers != NULL) - xfree(this->headers, this->header_count); - - free(this->payload), this->payload = NULL; - free(this->buffer), this->buffer = NULL; + size_t i; + if (this->headers) + xfree(this->headers, this->header_count); + + free(this->payload), this->payload = NULL; + free(this->buffer), this->buffer = NULL; } @@ -98,14 +101,15 @@ void mds_message_destroy(mds_message_t* restrict this) * @param extent The number of additional entries * @return Zero on success, -1 on error */ -int mds_message_extend_headers(mds_message_t* restrict this, size_t extent) +int +mds_message_extend_headers(mds_message_t *restrict this, size_t extent) { - char** new_headers = this->headers; - fail_if (xrealloc(new_headers, this->header_count + extent, char*)); - this->headers = new_headers; - return 0; - fail: - return -1; + char **new_headers = this->headers; + fail_if (xrealloc(new_headers, this->header_count + extent, char*)); + this->headers = new_headers; + return 0; +fail: + return -1; } @@ -115,16 +119,16 @@ int mds_message_extend_headers(mds_message_t* restrict this, size_t extent) * @param this The message * @return Zero on success, -1 on error */ -__attribute__((nonnull)) -static int mds_message_extend_buffer(mds_message_t* restrict this) +static int __attribute__((nonnull)) +mds_message_extend_buffer(mds_message_t *restrict this) { - char* new_buf = this->buffer; - fail_if (xrealloc(new_buf, this->buffer_size << 1, char)); - this->buffer = new_buf; - this->buffer_size <<= 1; - return 0; - fail: - return -1; + char *new_buf = this->buffer; + fail_if (xrealloc(new_buf, this->buffer_size << 1, char)); + this->buffer = new_buf; + this->buffer_size <<= 1; + return 0; +fail: + return -1; } @@ -133,18 +137,18 @@ static int mds_message_extend_buffer(mds_message_t* restrict this) * * @param this The message */ -__attribute__((nonnull)) -static void reset_message(mds_message_t* restrict this) +static void __attribute__((nonnull)) +reset_message(mds_message_t *restrict this) { - size_t i; - if (this->headers != NULL) - xfree(this->headers, this->header_count); - this->header_count = 0; - - free(this->payload); - this->payload = NULL; - this->payload_size = 0; - this->payload_ptr = 0; + size_t i; + if (this->headers) + xfree(this->headers, this->header_count); + this->header_count = 0; + + free(this->payload); + this->payload = NULL; + this->payload_size = 0; + this->payload_ptr = 0; } @@ -154,29 +158,29 @@ static void reset_message(mds_message_t* restrict this) * @param this The message * @return Zero on success, negative on error (malformated message: unrecoverable state) */ -__attribute__((pure, nonnull)) -static int get_payload_length(mds_message_t* restrict this) +static int __attribute__((pure, nonnull)) +get_payload_length(mds_message_t *restrict this) { - char* header; - size_t i; - - for (i = 0; i < this->header_count; i++) - if (strstr(this->headers[i], "Length: ") == this->headers[i]) - { - /* Store the message length. */ - header = this->headers[i] + strlen("Length: "); - this->payload_size = atoz(header); - - /* Do not except a length that is not correctly formated. */ - for (; *header; header++) - if ((*header < '0') || ('9' < *header)) - return -2; /* Malformated value, enters unrecoverable state. */ - - /* Stop searching for the ‘Length’ header, we have found and parsed it. */ - break; - } - - return 0; + char *header; + size_t i; + + for (i = 0; i < this->header_count; i++) { + if (strstr(this->headers[i], "Length: ") == this->headers[i]) { + /* Store the message length. */ + header = this->headers[i] + strlen("Length: "); + this->payload_size = atoz(header); + + /* Do not except a length that is not correctly formated. */ + for (; *header; header++) + if (*header < '0' || '9' < *header) + return -2; /* Malformated value, enters unrecoverable state. */ + + /* Stop searching for the ‘Length’ header, we have found and parsed it. */ + break; + } + } + + return 0; } @@ -187,21 +191,21 @@ static int get_payload_length(mds_message_t* restrict this) * @param length The length of the header * @return Zero if valid, negative if invalid (malformated message: unrecoverable state) */ -__attribute__((pure, nonnull)) -static int validate_header(const char* header, size_t length) +static int __attribute__((pure, nonnull)) +validate_header(const char *header, size_t length) { - char* p = memchr(header, ':', length * sizeof(char)); - - if (verify_utf8(header, 0) < 0) - /* Either the string is not UTF-8, or your are under an UTF-8 attack, - let's just call this unrecoverable because the client will not correct. */ - return -2; - - if ((p == NULL) || /* Buck you, rawmemchr should not segfault the program. */ - (p[1] != ' ')) /* Also an invalid format. ' ' is mandated after the ':'. */ - return -2; - - return 0; + char *p = memchr(header, ':', length * sizeof(char)); + + if (verify_utf8(header, 0) < 0) + /* Either the string is not UTF-8, or your are under an UTF-8 attack, + let's just call this unrecoverable because the client will not correct. */ + return -2; + + if (!p || /* Buck you, rawmemchr should not segfault the program. */ + p[1] != ' ') /* Also an invalid format. ' ' is mandated after the ':'. */ + return -2; + + return 0; } @@ -212,12 +216,12 @@ static int validate_header(const char* header, size_t length) * @param length The number of characters to remove * @param update_ptr Whether to update the buffer pointer */ -__attribute__((nonnull)) -static void unbuffer_beginning(mds_message_t* restrict this, size_t length, int update_ptr) +static void __attribute__((nonnull)) +unbuffer_beginning(mds_message_t *restrict this, size_t length, int update_ptr) { - memmove(this->buffer, this->buffer + length, (this->buffer_ptr - length) * sizeof(char)); - if (update_ptr) - this->buffer_ptr -= length; + memmove(this->buffer, this->buffer + length, (this->buffer_ptr - length) * sizeof(char)); + if (update_ptr) + this->buffer_ptr -= length; } @@ -228,23 +232,23 @@ static void unbuffer_beginning(mds_message_t* restrict this, size_t length, int * @param this The message * @return The return value follows the rules of `mds_message_read` */ -__attribute__((nonnull)) -static int initialise_payload(mds_message_t* restrict this) +static int __attribute__((nonnull)) +initialise_payload(mds_message_t *restrict this) { - /* Remove the \n (end of empty line) we found from the buffer. */ - unbuffer_beginning(this, 1, 1); - - /* Get the length of the payload. */ - if (get_payload_length(this) < 0) - return -2; /* Malformated value, enters unrecoverable state. */ - - /* Allocate the payload buffer. */ - if (this->payload_size > 0) - fail_if (xmalloc(this->payload, this->payload_size, char)); - - return 0; - fail: - return -1; + /* Remove the \n (end of empty line) we found from the buffer. */ + unbuffer_beginning(this, 1, 1); + + /* Get the length of the payload. */ + if (get_payload_length(this) < 0) + return -2; /* Malformated value, enters unrecoverable state. */ + + /* Allocate the payload buffer. */ + if (this->payload_size > 0) + fail_if (xmalloc(this->payload, this->payload_size, char)); + + return 0; +fail: + return -1; } @@ -255,35 +259,34 @@ static int initialise_payload(mds_message_t* restrict this) * @param length The length of the header, including LF-termination * @return The return value follows the rules of `mds_message_read` */ -__attribute__((nonnull)) -static int store_header(mds_message_t* restrict this, size_t length) +static int __attribute__((nonnull)) +store_header(mds_message_t *restrict this, size_t length) { - char* header; - - /* Allocate the header. */ - fail_if (xmalloc(header, length, char)); /* Last char is a LF, which is substituted with NUL. */ - /* Copy the header data into the allocated header, */ - memcpy(header, this->buffer, length * sizeof(char)); - /* and NUL-terminate it. */ - header[length - 1] = '\0'; - - /* Remove the header data from the read buffer. */ - unbuffer_beginning(this, length, 1); - - /* Make sure the the header syntax is correct so that - the program does not need to care about it. */ - if (validate_header(header, length)) - { - free(header); - return -2; - } - - /* Store the header in the header list. */ - this->headers[this->header_count++] = header; - - return 0; - fail: - return -1; + char *header; + + /* Allocate the header. */ + fail_if (xmalloc(header, length, char)); /* Last char is a LF, which is substituted with NUL. */ + /* Copy the header data into the allocated header, */ + memcpy(header, this->buffer, length * sizeof(char)); + /* and NUL-terminate it. */ + header[length - 1] = '\0'; + + /* Remove the header data from the read buffer. */ + unbuffer_beginning(this, length, 1); + + /* Make sure the the header syntax is correct so that + the program does not need to care about it. */ + if (validate_header(header, length)) { + free(header); + return -2; + } + + /* Store the header in the header list. */ + this->headers[this->header_count++] = header; + + return 0; +fail: + return -1; } @@ -294,37 +297,36 @@ static int store_header(mds_message_t* restrict this, size_t length) * @param fd The file descriptor of the socket * @return The return value follows the rules of `mds_message_read` */ -__attribute__((nonnull)) -static int continue_read(mds_message_t* restrict this, int fd) +static int __attribute__((nonnull)) +continue_read(mds_message_t *restrict this, int fd) { - size_t n; - ssize_t got; - int r; - - /* Figure out how much space we have left in the read buffer. */ - n = this->buffer_size - this->buffer_ptr; - - /* If we do not have too much left, */ - if (n < 128) - { - /* grow the buffer, */ - try (mds_message_extend_buffer(this)); - - /* and recalculate how much space we have left. */ - n = this->buffer_size - this->buffer_ptr; - } - - /* Then read from the socket. */ - errno = 0; - got = recv(fd, this->buffer + this->buffer_ptr, n, 0); - this->buffer_ptr += (size_t)(got < 0 ? 0 : got); - fail_if (errno); - if (got == 0) - fail_if ((errno = ECONNRESET)); - - return 0; - fail: - return -1; + size_t n; + ssize_t got; + int r; + + /* Figure out how much space we have left in the read buffer. */ + n = this->buffer_size - this->buffer_ptr; + + /* If we do not have too much left, */ + if (n < 128) { + /* grow the buffer, */ + try (mds_message_extend_buffer(this)); + + /* and recalculate how much space we have left. */ + n = this->buffer_size - this->buffer_ptr; + } + + /* Then read from the socket. */ + errno = 0; + got = recv(fd, this->buffer + this->buffer_ptr, n, 0); + this->buffer_ptr += (size_t)(got < 0 ? 0 : got); + fail_if (errno); + if (!got) + fail_if ((errno = ECONNRESET)); + + return 0; +fail: + return -1; } @@ -341,86 +343,78 @@ static int continue_read(mds_message_t* restrict this, int fd) * -2 indicates that the message is malformated, * which is a state that cannot be recovered from. */ -int mds_message_read(mds_message_t* restrict this, int fd) +int +mds_message_read(mds_message_t *restrict this, int fd) { - size_t header_commit_buffer = 0; - int r; - - /* If we are at stage 2, we are done and it is time to start over. - This is important because the function could have been interrupted. */ - if (this->stage == 2) - { - reset_message(this); - this->stage = 0; - } - - /* Read from file descriptor until we have a full message. */ - for (;;) - { - char* p; - size_t length; - - /* Stage 0: headers. */ - /* Read all headers that we have stored into the read buffer. */ - while ((this->stage == 0) && - ((p = memchr(this->buffer, '\n', this->buffer_ptr * sizeof(char))) != NULL)) - if ((length = (size_t)(p - this->buffer))) - { - /* We have found a header. */ - - /* On every eighth header found with this function call, - we prepare the header list for eight more headers so - that it does not need to be reallocated again and again. */ - if (header_commit_buffer == 0) - try (mds_message_extend_headers(this, header_commit_buffer = 8)); - - /* Create and store header. */ - try (store_header(this, length + 1)); - header_commit_buffer -= 1; - } - else - { - /* We have found an empty line, i.e. the end of the headers. */ - - /* Remove the header–payload delimiter from the buffer, - get the payload's size and allocate the payload. */ - try (initialise_payload(this)); - - /* Mark end of stage, next stage is getting the payload. */ - this->stage = 1; - } - - - /* Stage 1: payload. */ - if ((this->stage == 1) && (this->payload_size > 0)) - { - /* How much of the payload that has not yet been filled. */ - size_t need = this->payload_size - this->payload_ptr; - /* How much we have of that what is needed. */ - size_t move = min(this->buffer_ptr, need); - - /* Copy what we have, and remove it from the the read buffer. */ - memcpy(this->payload + this->payload_ptr, this->buffer, move * sizeof(char)); - unbuffer_beginning(this, move, 1); - - /* Keep track of how much we have read. */ - this->payload_ptr += move; + size_t header_commit_buffer = 0, length, need, move; + int r; + char *p; + + /* If we are at stage 2, we are done and it is time to start over. + This is important because the function could have been interrupted. */ + if (this->stage == 2) { + reset_message(this); + this->stage = 0; } - if ((this->stage == 1) && (this->payload_ptr == this->payload_size)) - { - /* If we have filled the payload (or there was no payload), - mark the end of this stage, i.e. that the message is - complete, and return with success. */ - this->stage = 2; - return 0; + + /* Read from file descriptor until we have a full message. */ + for (;;) { + /* Stage 0: headers. */ + /* Read all headers that we have stored into the read buffer. */ + while (!this->stage && ((p = memchr(this->buffer, '\n', this->buffer_ptr * sizeof(char))))) { + if ((length = (size_t)(p - this->buffer))) { + /* We have found a header. */ + + /* On every eighth header found with this function call, + we prepare the header list for eight more headers so + that it does not need to be reallocated again and again. */ + if (!header_commit_buffer) + try (mds_message_extend_headers(this, header_commit_buffer = 8)); + + /* Create and store header. */ + try (store_header(this, length + 1)); + header_commit_buffer -= 1; + } else { + /* We have found an empty line, i.e. the end of the headers. */ + + /* Remove the header–payload delimiter from the buffer, + get the payload's size and allocate the payload. */ + try (initialise_payload(this)); + + /* Mark end of stage, next stage is getting the payload. */ + this->stage = 1; + } + } + + + /* Stage 1: payload. */ + if (this->stage == 1 && this->payload_size > 0) { + /* How much of the payload that has not yet been filled. */ + need = this->payload_size - this->payload_ptr; + /* How much we have of that what is needed. */ + move = min(this->buffer_ptr, need); + + /* Copy what we have, and remove it from the the read buffer. */ + memcpy(this->payload + this->payload_ptr, this->buffer, move * sizeof(char)); + unbuffer_beginning(this, move, 1); + + /* Keep track of how much we have read. */ + this->payload_ptr += move; + } + if (this->stage == 1 && this->payload_ptr == this->payload_size) { + /* If we have filled the payload (or there was no payload), + mark the end of this stage, i.e. that the message is + complete, and return with success. */ + this->stage = 2; + return 0; + } + + + /* If stage 1 was not completed. */ + + /* Continue reading from the socket into the buffer. */ + try (continue_read(this, fd)); } - - - /* If stage 1 was not completed. */ - - /* Continue reading from the socket into the buffer. */ - try (continue_read(this, fd)); - } } @@ -431,15 +425,15 @@ int mds_message_read(mds_message_t* restrict this, int fd) * @param this The message * @return The size of the message when marshalled */ -size_t mds_message_marshal_size(const mds_message_t* restrict this) +size_t +mds_message_marshal_size(const mds_message_t *restrict this) { - size_t rc = this->header_count + this->payload_size; - size_t i; - for (i = 0; i < this->header_count; i++) - rc += strlen(this->headers[i]); - rc *= sizeof(char); - rc += 4 * sizeof(size_t) + 2 * sizeof(int); - return rc; + size_t i, rc = this->header_count + this->payload_size; + for (i = 0; i < this->header_count; i++) + rc += strlen(this->headers[i]); + rc *= sizeof(char); + rc += 4 * sizeof(size_t) + 2 * sizeof(int); + return rc; } @@ -449,29 +443,29 @@ size_t mds_message_marshal_size(const mds_message_t* restrict this) * @param this The message * @param data Output buffer for the marshalled data */ -void mds_message_marshal(const mds_message_t* restrict this, char* restrict data) +void +mds_message_marshal(const mds_message_t *restrict this, char *restrict data) { - size_t i, n; - - buf_set_next(data, int, MDS_MESSAGE_T_VERSION); - - buf_set_next(data, size_t, this->header_count); - buf_set_next(data, size_t, this->payload_size); - buf_set_next(data, size_t, this->payload_ptr); - buf_set_next(data, size_t, this->buffer_ptr); - buf_set_next(data, int, this->stage); - - for (i = 0; i < this->header_count; i++) - { - n = strlen(this->headers[i]) + 1; - memcpy(data, this->headers[i], n * sizeof(char)); - buf_next(data, char, n); - } - - memcpy(data, this->payload, this->payload_ptr * sizeof(char)); - buf_next(data, char, this->payload_ptr); - - memcpy(data, this->buffer, this->buffer_ptr * sizeof(char)); + size_t i, n; + + buf_set_next(data, int, MDS_MESSAGE_T_VERSION); + + buf_set_next(data, size_t, this->header_count); + buf_set_next(data, size_t, this->payload_size); + buf_set_next(data, size_t, this->payload_ptr); + buf_set_next(data, size_t, this->buffer_ptr); + buf_set_next(data, int, this->stage); + + for (i = 0; i < this->header_count; i++) { + n = strlen(this->headers[i]) + 1; + memcpy(data, this->headers[i], n * sizeof(char)); + buf_next(data, char, n); + } + + memcpy(data, this->payload, this->payload_ptr * sizeof(char)); + buf_next(data, char, this->payload_ptr); + + memcpy(data, this->buffer, this->buffer_ptr * sizeof(char)); } @@ -483,75 +477,74 @@ void mds_message_marshal(const mds_message_t* restrict this, char* restrict data * @return Non-zero on error, `errno` will be set accordingly. * Destroy the message on error. */ -int mds_message_unmarshal(mds_message_t* restrict this, char* restrict data) +int +mds_message_unmarshal(mds_message_t *restrict this, char *restrict data) { - size_t i, n, header_count; - - /* buf_get(data, int, 0, MDS_MESSAGE_T_VERSION); */ - buf_next(data, int, 1); - - this->header_count = 0; - buf_get_next(data, size_t, header_count); - buf_get_next(data, size_t, this->payload_size); - buf_get_next(data, size_t, this->payload_ptr); - buf_get_next(data, size_t, this->buffer_size = this->buffer_ptr); - buf_get_next(data, int, this->stage); - - /* Make sure that the pointers are NULL so that they are - not freed without being allocated when the message is - destroyed if this function fails. */ - this->headers = NULL; - this->payload = NULL; - this->buffer = NULL; - - /* To 2-power-multiple of 128 bytes. */ - this->buffer_size >>= 7; - if (this->buffer_size == 0) - this->buffer_size = 1; - else - { - this->buffer_size -= 1; - this->buffer_size |= this->buffer_size >> 1; - this->buffer_size |= this->buffer_size >> 2; - this->buffer_size |= this->buffer_size >> 4; - this->buffer_size |= this->buffer_size >> 8; - this->buffer_size |= this->buffer_size >> 16; + size_t i, n, header_count; + + /* buf_get(data, int, 0, MDS_MESSAGE_T_VERSION); */ + buf_next(data, int, 1); + + this->header_count = 0; + buf_get_next(data, size_t, header_count); + buf_get_next(data, size_t, this->payload_size); + buf_get_next(data, size_t, this->payload_ptr); + buf_get_next(data, size_t, this->buffer_size = this->buffer_ptr); + buf_get_next(data, int, this->stage); + + /* Make sure that the pointers are NULL so that they are + not freed without being allocated when the message is + destroyed if this function fails. */ + this->headers = NULL; + this->payload = NULL; + this->buffer = NULL; + + /* To 2-power-multiple of 128 bytes. */ + this->buffer_size >>= 7; + if (!this->buffer_size) { + this->buffer_size = 1; + } else { + this->buffer_size -= 1; + this->buffer_size |= this->buffer_size >> 1; + this->buffer_size |= this->buffer_size >> 2; + this->buffer_size |= this->buffer_size >> 4; + this->buffer_size |= this->buffer_size >> 8; + this->buffer_size |= this->buffer_size >> 16; #if SIZE_MAX == UINT64_MAX - this->buffer_size |= this->buffer_size >> 32; + this->buffer_size |= this->buffer_size >> 32; #endif - this->buffer_size += 1; - } - this->buffer_size <<= 7; - - /* Allocate header list, payload and read buffer. */ - - if (header_count > 0) - fail_if (xmalloc(this->headers, header_count, char*)); - - if (this->payload_size > 0) - fail_if (xmalloc(this->payload, this->payload_size, char)); - - fail_if (xmalloc(this->buffer, this->buffer_size, char)); - - /* Fill the header list, payload and read buffer. */ - - for (i = 0; i < header_count; i++) - { - n = strlen(data) + 1; - fail_if (xmemdup(this->headers[i], data, n, char)); - buf_next(data, char, n); - this->header_count++; - } - - memcpy(this->payload, data, this->payload_ptr * sizeof(char)); - buf_next(data, char, this->payload_ptr); - - memcpy(this->buffer, data, this->buffer_ptr * sizeof(char)); - - return 0; - - fail: - return -1; + this->buffer_size += 1; + } + this->buffer_size <<= 7; + + /* Allocate header list, payload and read buffer. */ + + if (header_count > 0) + fail_if (xmalloc(this->headers, header_count, char*)); + + if (this->payload_size > 0) + fail_if (xmalloc(this->payload, this->payload_size, char)); + + fail_if (xmalloc(this->buffer, this->buffer_size, char)); + + /* Fill the header list, payload and read buffer. */ + + for (i = 0; i < header_count; i++) { + n = strlen(data) + 1; + fail_if (xmemdup(this->headers[i], data, n, char)); + buf_next(data, char, n); + this->header_count++; + } + + memcpy(this->payload, data, this->payload_ptr * sizeof(char)); + buf_next(data, char, this->payload_ptr); + + memcpy(this->buffer, data, this->buffer_ptr * sizeof(char)); + + return 0; + +fail: + return -1; } @@ -562,13 +555,14 @@ int mds_message_unmarshal(mds_message_t* restrict this, char* restrict data) * @param this The message * @return The size of the message when marshalled */ -size_t mds_message_compose_size(const mds_message_t* restrict this) +size_t +mds_message_compose_size(const mds_message_t *restrict this) { - size_t rc = 1 + this->payload_size; - size_t i; - for (i = 0; i < this->header_count; i++) - rc += strlen(this->headers[i]) + 1; - return rc * sizeof(char); + size_t rc = 1 + this->payload_size; + size_t i; + for (i = 0; i < this->header_count; i++) + rc += strlen(this->headers[i]) + 1; + return rc * sizeof(char); } @@ -578,23 +572,22 @@ size_t mds_message_compose_size(const mds_message_t* restrict this) * @param this The message * @param data Output buffer for the marshalled data */ -void mds_message_compose(const mds_message_t* restrict this, char* restrict data) +void +mds_message_compose(const mds_message_t *restrict this, char *restrict data) { - size_t i, n; - - for (i = 0; i < this->header_count; i++) - { - n = strlen(this->headers[i]); - memcpy(data, this->headers[i], n * sizeof(char)); - data += n; - buf_set_next(data, char, '\n'); - } - buf_set_next(data, char, '\n'); - - if (this->payload_size > 0) - memcpy(data, this->payload, this->payload_size * sizeof(char)); + size_t i, n; + + for (i = 0; i < this->header_count; i++) { + n = strlen(this->headers[i]); + memcpy(data, this->headers[i], n * sizeof(char)); + data += n; + buf_set_next(data, char, '\n'); + } + buf_set_next(data, char, '\n'); + + if (this->payload_size > 0) + memcpy(data, this->payload, this->payload_size * sizeof(char)); } #undef try - diff --git a/src/libmdsserver/util.c b/src/libmdsserver/util.c index cac30ad..09d996a 100644 --- a/src/libmdsserver/util.c +++ b/src/libmdsserver/util.c @@ -49,20 +49,21 @@ static char self_exe[PATH_MAX] = {0}; * @param str The client ID string * @return The client ID integer */ -uint64_t parse_client_id(const char* str) +uint64_t +parse_client_id(const char *str) { - char client_words[22]; - char* client_high; - char* client_low; - uint64_t client; - - strcpy(client_high = client_words, str); - client_low = rawmemchr(client_words, ':'); - *client_low++ = '\0'; - client = atou64(client_high) << 32; - client |= atou64(client_low); - - return client; + char client_words[22]; + char *client_high; + char *client_low; + uint64_t client; + + strcpy(client_high = client_words, str); + client_low = rawmemchr(client_words, ':'); + *client_low++ = '\0'; + client = atou64(client_high) << 32; + client |= atou64(client_low); + + return client; } @@ -72,12 +73,11 @@ uint64_t parse_client_id(const char* str) * @param var The environment variable's name * @return The environment variable's value, `NULL` if empty or not defined */ -char* getenv_nonempty(const char* var) +char * +getenv_nonempty(const char *var) { - char* rc = getenv(var); - if ((rc == NULL) || (*rc == '\0')) - return NULL; - return rc; + char *rc = getenv(var); + return (rc && *rc) ? rc : NULL; } @@ -97,20 +97,21 @@ char* getenv_nonempty(const char* var) * * @return Zero on success, -1 on error */ -int prepare_reexec(void) +int +prepare_reexec(void) { - ssize_t len; - len = readlink(SELF_EXE, self_exe, (sizeof(self_exe) / sizeof(char)) - 1); - fail_if (len < 0); - /* ‘readlink() does not append a null byte to buf.’ */ - self_exe[len] = '\0'; - /* Handle possible race condition: file was removed. */ - if (access(self_exe, F_OK) < 0) - if (!strcmp(self_exe + (len - 10), " (deleted)")) - self_exe[len - 10] = '\0'; - return 0; - fail: - return -1; + ssize_t len; + len = readlink(SELF_EXE, self_exe, (sizeof(self_exe) / sizeof(char)) - 1); + fail_if (len < 0); + /* ‘readlink() does not append a null byte to buf.’ */ + self_exe[len] = '\0'; + /* Handle possible race condition: file was removed. */ + if (access(self_exe, F_OK) < 0) + if (!strcmp(self_exe + (len - 10), " (deleted)")) + self_exe[len - 10] = '\0'; + return 0; +fail: + return -1; } @@ -125,30 +126,30 @@ int prepare_reexec(void) * @param argv The command line arguments * @param reexeced Whether the server has previously been re-exec:ed */ -void reexec_server(int argc, char** argv, int reexeced) +void +reexec_server(int argc, char **argv, int reexeced) { - char** reexec_args; - char** reexec_args_; - int i; - - /* Re-exec the server. */ - reexec_args = alloca(((size_t)argc + 2) * sizeof(char*)); - reexec_args_ = reexec_args; - if (reexeced == 0) - { - *reexec_args_++ = *argv; - fail_if (xstrdup(*reexec_args_, "--re-exec")); - for (i = 1; i < argc; i++) - reexec_args_[i] = argv[i]; - } - else /* Don't let the --re-exec:s accumulate. */ - *reexec_args_ = *argv; - for (i = 1; i < argc; i++) - reexec_args_[i] = argv[i]; - reexec_args_[argc] = NULL; - execv(self_exe[0] ? self_exe : argv[0], reexec_args); - fail: - return; + char **reexec_args; + char **reexec_args_; + int i; + + /* Re-exec the server. */ + reexec_args = alloca(((size_t)argc + 2) * sizeof(char*)); + reexec_args_ = reexec_args; + if (!reexeced) { + *reexec_args_++ = *argv; + fail_if (xstrdup(*reexec_args_, "--re-exec")); + for (i = 1; i < argc; i++) + reexec_args_[i] = argv[i]; + } else { /* Don't let the --re-exec:s accumulate. */ + *reexec_args_ = *argv; + } + for (i = 1; i < argc; i++) + reexec_args_[i] = argv[i]; + reexec_args_[argc] = NULL; + execv(self_exe[0] ? self_exe : argv[0], reexec_args); +fail: + return; } @@ -164,17 +165,18 @@ void reexec_server(int argc, char** argv, int reexeced) * @param function The function to run when the signal is caught * @return Zero on success, -1 on error */ -int xsigaction(int signo, void (*function)(int signo)) +int +xsigaction(int signo, void (*function)(int signo)) { - struct sigaction action; - sigset_t sigset; - - sigemptyset(&sigset); - action.sa_handler = function; - action.sa_mask = sigset; - action.sa_flags = 0; - - return sigaction(signo, &action, NULL); + struct sigaction action; + sigset_t sigset; + + sigemptyset(&sigset); + action.sa_handler = function; + action.sa_mask = sigset; + action.sa_flags = 0; + + return sigaction(signo, &action, NULL); } @@ -186,34 +188,32 @@ int xsigaction(int signo, void (*function)(int signo)) * @param length The length of the message * @return The number of bytes that have been sent (even on error) */ -size_t send_message(int socket, const char* message, size_t length) +size_t +send_message(int socket, const char *message, size_t length) { - size_t block_size = length; - size_t sent = 0; - ssize_t just_sent; - - errno = 0; - while (length > 0) - if ((just_sent = send(socket, message + sent, min(block_size, length), MSG_NOSIGNAL)) < 0) - { - if (errno == EPIPE) - errno = ECONNRESET; - if (errno == EMSGSIZE) - { - block_size >>= 1; - if (block_size == 0) - return sent; - } - else - return sent; - } - else - { - sent += (size_t)just_sent; - length -= (size_t)just_sent; - } - - return sent; + size_t block_size = length; + size_t sent = 0; + ssize_t just_sent; + + errno = 0; + while (length > 0) { + if ((just_sent = send(socket, message + sent, min(block_size, length), MSG_NOSIGNAL)) < 0) { + if (errno == EPIPE) + errno = ECONNRESET; + if (errno == EMSGSIZE) { + block_size >>= 1; + if (!block_size) + return sent; + } else { + return sent; + } + } else { + sent += (size_t)just_sent; + length -= (size_t)just_sent; + } + } + + return sent; } @@ -226,20 +226,21 @@ size_t send_message(int socket, const char* message, size_t length) * @param max The maximum accepted value * @return Zero on success, -1 on syntax error */ -int strict_atoi(const char* str, int* value, int min, int max) +int +strict_atoi(const char *str, int *value, int min, int max) { - long long int r; - char* endptr; - - r = strtoll(str, &endptr, 10); - if ((*str == '\0') || isspace(*str) || - (endptr - str != (ssize_t)strlen(str)) || - (r < (long long int)min) || - (r > (long long int)max)) - return -1; - - *value = (int)r; - return 0; + long long int r; + char *endptr; + + r = strtoll(str, &endptr, 10); + if (!*str || isspace(*str) || + endptr - str != (ssize_t)strlen(str) || + r < (long long int)min || + r > (long long int)max) + return -1; + + *value = (int)r; + return 0; } @@ -252,51 +253,50 @@ int strict_atoi(const char* str, int* value, int min, int max) * @param max The maximum accepted value * @return Zero on success, -1 on syntax error */ -int strict_atoj(const char* str, intmax_t* value, intmax_t min, intmax_t max) +int +strict_atoj(const char *str, intmax_t *value, intmax_t min, intmax_t max) { - static char minstr[3 * sizeof(intmax_t) + 2] = { '\0' }; - intmax_t r = 0; - char c; - int neg = 0; - - if (*str == '-') - { - if (*minstr == '\0') - sprintf(minstr, "%j", INTMAX_MIN); - if (!strcmp(str, minstr)) - { - r = INTMAX_MIN; - goto done; + static char minstr[3 * sizeof(intmax_t) + 2] = { '\0' }; + intmax_t r = 0; + char c; + int neg = 0; + + if (*str == '-') { + if (!*minstr) + sprintf(minstr, "%j", INTMAX_MIN); + if (!strcmp(str, minstr)) { + r = INTMAX_MIN; + goto done; + } + neg = 1, str++; } - neg = 1, str++; - } - - if (*str == '\0') - return -1; - - while ((c = *str)) - if (('0' <= c) && (c <= '9')) - { - if (r > INTMAX_MAX / 10) - return -1; - else if (r == INTMAX_MAX / 10) - if ((c & 15) > INTMAX_MAX % 10) - return -1; - r = r * 10 + (c & 15); - } - else - return -1; - - if (neg) - r = -r; - - done: - - if ((r < min) || (r > max)) - return -1; - - *value = r; - return 0; + + if (!*str) + return -1; + + while ((c = *str)) { + if ('0' <= c && c <= '9') { + if (r > INTMAX_MAX / 10) { + return -1; + } else if (r == INTMAX_MAX / 10) { + if ((c & 15) > INTMAX_MAX % 10) + return -1; + } + r = r * 10 + (c & 15); + } else { + return -1; + } + } + + if (neg) + r = -r; + +done: + if (r < min || r > max) + return -1; + + *value = r; + return 0; } @@ -316,50 +316,53 @@ int strict_atoj(const char* str, intmax_t* value, intmax_t min, intmax_t max) * @param max The maximum accepted value * @return Zero on success, -1 on syntax error */ -int strict_atouj(const char* str, uintmax_t* value, uintmax_t min, uintmax_t max) +int +strict_atouj(const char *str, uintmax_t *value, uintmax_t min, uintmax_t max) { - uintmax_t r = 0; - char c; - - if (*str == '\0') - return -1; - - while ((c = *str)) - if (('0' <= c) && (c <= '9')) - { - if (r > INTMAX_MAX / 10) - return -1; - else if (r == INTMAX_MAX / 10) - if ((c & 15) > INTMAX_MAX % 10) - return -1; - r = r * 10 + (c & 15); - } - else - return -1; - - if ((r < min) || (r > max)) - return -1; - - *value = r; - return 0; + uintmax_t r = 0; + char c; + + if (!*str) + return -1; + + while ((c = *str)) { + if ('0' <= c && c <= '9') { + if (r > INTMAX_MAX / 10) { + return -1; + } else if (r == INTMAX_MAX / 10) { + if ((c & 15) > INTMAX_MAX % 10) + return -1; + } + r = r * 10 + (c & 15); + } else { + return -1; + } + } + + if (r < min || r > max) + return -1; + + *value = r; + return 0; } #if defined(__GNUC__) # pragma GCC diagnostic pop #endif -#define __strict_y(Y, TYPE, PARA_TYPE, HYPER_Y, HYPER_TYPE) \ - int strict_##Y(const char* str, TYPE* value, PARA_TYPE min, PARA_TYPE max) \ - { \ - HYPER_TYPE intermediate_value; \ - if (strict_##HYPER_Y(str, &intermediate_value, (HYPER_TYPE)min, (HYPER_TYPE)max) < 0) \ - return -1; \ - return *value = (TYPE)intermediate_value, 0; \ - } +#define __strict_y(Y, TYPE, PARA_TYPE, HYPER_Y, HYPER_TYPE)\ + int\ + strict_##Y(const char *str, TYPE *value, PARA_TYPE min, PARA_TYPE max)\ + {\ + HYPER_TYPE intermediate_value;\ + if (strict_##HYPER_Y(str, &intermediate_value, (HYPER_TYPE)min, (HYPER_TYPE)max) < 0)\ + return -1;\ + return *value = (TYPE)intermediate_value, 0;\ + } -#define __strict_x(X, TYPE, HYPER_X, HYPER_TYPE) \ - __strict_y(X, TYPE, TYPE, HYPER_X, HYPER_TYPE) +#define __strict_x(X, TYPE, HYPER_X, HYPER_TYPE)\ + __strict_y(X, TYPE, TYPE, HYPER_X, HYPER_TYPE) /** @@ -577,20 +580,20 @@ __strict_x(atou64, uint64_t, atouj, uintmax_t) * @param length The length of the buffer * @return Zero on success, -1 on error */ -int full_write(int fd, const char* buffer, size_t length) +int +full_write(int fd, const char *buffer, size_t length) { - ssize_t wrote; - while (length > 0) - { - errno = 0; - wrote = write(fd, buffer, length); - fail_if (errno && (errno != EINTR)); - length -= (size_t)max(wrote, 0); - buffer += (size_t)max(wrote, 0); - } - return 0; - fail: - return -1; + ssize_t wrote; + while (length > 0) { + errno = 0; + wrote = write(fd, buffer, length); + fail_if (errno && errno != EINTR); + length -= (size_t)max(wrote, 0); + buffer += (size_t)max(wrote, 0); + } + return 0; +fail: + return -1; } @@ -601,44 +604,44 @@ int full_write(int fd, const char* buffer, size_t length) * @param length Output parameter for the length of the file, may be `NULL` * @return The content of the file, you will need to free it. `NULL` on error. */ -char* full_read(int fd, size_t* length) +char * +full_read(int fd, size_t *length) { - char* old_buf = NULL; - size_t buffer_size = 8 << 10; - size_t buffer_ptr = 0; - char* buffer; - ssize_t got; - int saved_errno; - - if (length != NULL) - *length = 0; - - /* Allocate buffer for data. */ - fail_if (xmalloc(buffer, buffer_size, char)); - - /* Read the file. */ - for (;;) - { - /* Grow buffer if it is too small. */ - if (buffer_size == buffer_ptr) - fail_if (xxrealloc(old_buf, buffer, buffer_size <<= 1, char)); - - /* Read from the file into the buffer. */ - got = read(fd, buffer + buffer_ptr, buffer_size - buffer_ptr); - fail_if ((got < 0) && (errno != EINTR)); - if (got == 0) - break; - buffer_ptr += (size_t)got; - } - - if (length != NULL) - *length = buffer_ptr; - return buffer; - fail: - saved_errno = errno; - free(old_buf); - free(buffer); - return errno = saved_errno, NULL; + char *old_buf = NULL; + size_t buffer_size = 8 << 10; + size_t buffer_ptr = 0; + char *buffer; + ssize_t got; + int saved_errno; + + if (length) + *length = 0; + + /* Allocate buffer for data. */ + fail_if (xmalloc(buffer, buffer_size, char)); + + /* Read the file. */ + for (;;) { + /* Grow buffer if it is too small. */ + if (buffer_size == buffer_ptr) + fail_if (xxrealloc(old_buf, buffer, buffer_size <<= 1, char)); + + /* Read from the file into the buffer. */ + got = read(fd, buffer + buffer_ptr, buffer_size - buffer_ptr); + fail_if (got < 0 && errno != EINTR); + if (!got) + break; + buffer_ptr += (size_t)got; + } + + if (length) + *length = buffer_ptr; + return buffer; +fail: + saved_errno = errno; + free(old_buf); + free(buffer); + return errno = saved_errno, NULL; } @@ -650,20 +653,20 @@ char* full_read(int fd, size_t* length) * @param length The length of the message * @return Zero on success, -1 on error */ -int full_send(int socket, const char* message, size_t length) +int +full_send(int socket, const char *message, size_t length) { - size_t sent; + size_t sent; - while (length > 0) - { - sent = send_message(socket, message, length); - fail_if ((sent < length) && (errno != EINTR)); - message += sent; - length -= sent; - } - return 0; - fail: - return -1; + while (length > 0) { + sent = send_message(socket, message, length); + fail_if (sent < length && errno != EINTR); + message += sent; + length -= sent; + } + return 0; +fail: + return -1; } @@ -677,17 +680,18 @@ int full_send(int socket, const char* message, size_t length) * @param needle_n The length of `needle` * @return Whether the `haystack` begins with `needle` */ -int startswith_n(const char* haystack, const char* needle, size_t haystack_n, size_t needle_n) +int +startswith_n(const char *haystack, const char *needle, size_t haystack_n, size_t needle_n) { - size_t i; - if (haystack_n < needle_n) - return 0; - - for (i = 0; i < needle_n; i++) - if (haystack[i] != needle[i]) - return 0; - - return 1; + size_t i; + if (haystack_n < needle_n) + return 0; + + for (i = 0; i < needle_n; i++) + if (haystack[i] != needle[i]) + return 0; + + return 1; } @@ -700,30 +704,30 @@ int startswith_n(const char* haystack, const char* needle, size_t haystack_n, si * @param options See description of `options` in the documentation for `waitpid` * @return See the documentation for `waitpid` */ -pid_t uninterruptable_waitpid(pid_t pid, int* restrict status, int options) +pid_t +uninterruptable_waitpid(pid_t pid, int *restrict status, int options) { - struct timespec time_start; - struct timespec time_intr; - int intr_count = 0, have_time; - pid_t rc; - - have_time = (monotone(&time_start) >= 0); - - rewait: - rc = waitpid(pid, status, options); - if (rc == (pid_t)-1) - { - fail_if (errno != EINTR); - if (have_time && (monotone(&time_intr) >= 0)) - if (time_start.tv_sec != time_intr.tv_sec) - intr_count = 0; - if (intr_count++ < 100) - goto rewait; - /* Don't let the CPU catch fire! */ - errno = EINTR; - } - fail: - return rc; + struct timespec time_start; + struct timespec time_intr; + int intr_count = 0, have_time; + pid_t rc; + + have_time = (monotone(&time_start) >= 0); + +rewait: + rc = waitpid(pid, status, options); + if (rc == (pid_t)-1) { + fail_if (errno != EINTR); + if (have_time && monotone(&time_intr) >= 0) + if (time_start.tv_sec != time_intr.tv_sec) + intr_count = 0; + if (intr_count++ < 100) + goto rewait; + /* Don't let the CPU catch fire! */ + errno = EINTR; + } +fail: + return rc; } @@ -734,72 +738,71 @@ pid_t uninterruptable_waitpid(pid_t pid, int* restrict status, int options) * @param allow_modified_nul Whether Modified UTF-8 is allowed, which allows a two-byte encoding for NUL * @return Zero if good, -1 on encoding error */ -int verify_utf8(const char* string, int allow_modified_nul) +int +verify_utf8(const char *string, int allow_modified_nul) { - static long BYTES_TO_MIN_BITS[] = {0, 0, 8, 12, 17, 22, 37}; - static long BYTES_TO_MAX_BITS[] = {0, 7, 11, 16, 21, 26, 31}; - long bytes = 0, read_bytes = 0, bits = 0, c, character; - - /* min bits max bits - 0....... 0 7 - 110..... 10...... 8 11 - 1110.... 10...... 10...... 12 16 - 11110... 10...... 10...... 10...... 17 21 - 111110.. 10...... 10...... 10...... 10...... 22 26 - 1111110. 10...... 10...... 10...... 10...... 10...... 27 31 - */ - - while ((c = (long)(*string++))) - if (read_bytes == 0) - { - /* First byte of the character. */ - - if ((c & 0x80) == 0x00) - /* Single-byte character. */ - continue; - - if ((c & 0xC0) == 0x80) - /* Single-byte character marked as multibyte, or - a non-first byte in a multibyte character. */ - return -1; - - /* Multibyte character. */ - while ((c & 0x80)) - bytes++, c <<= 1; - read_bytes = 1; - character = c & 0x7F; - if (bytes > 6) - /* 31-bit characters can be encoded with 6-bytes, - and UTF-8 does not cover higher code points. */ - return -1; - } - else - { - /* Not first byte of the character. */ - - if ((c & 0xC0) != 0x80) - /* Beginning of new character before a - multibyte character has ended. */ - return -1; - - character = (character << 6) | (c & 0x7F); - - if (++read_bytes < bytes) - /* Not at last byte yet. */ - continue; - - /* Check that the character is not unnecessarily long. */ - while (character) - character >>= 1, bits++; - bits = ((bits == 0) && (bytes == 2) && allow_modified_nul) ? 8 : bits; - if ((bits < BYTES_TO_MIN_BITS[bytes]) || (BYTES_TO_MAX_BITS[bytes] < bits)) - return -1; - - read_bytes = bytes = bits = 0; - } - - /* Make sure we did not stop at the middle of a multibyte character. */ - return read_bytes == 0 ? 0 : -1; + static long BYTES_TO_MIN_BITS[] = {0, 0, 8, 12, 17, 22, 37}; + static long BYTES_TO_MAX_BITS[] = {0, 7, 11, 16, 21, 26, 31}; + long bytes = 0, read_bytes = 0, bits = 0, c, character; + + /* min bits max bits + 0....... 0 7 + 110..... 10...... 8 11 + 1110.... 10...... 10...... 12 16 + 11110... 10...... 10...... 10...... 17 21 + 111110.. 10...... 10...... 10...... 10...... 22 26 + 1111110. 10...... 10...... 10...... 10...... 10...... 27 31 + */ + + while ((c = (long)(*string++))) { + if (read_bytes == 0) { + /* First byte of the character. */ + + if (!(c & 0x80)) + /* Single-byte character. */ + continue; + + if ((c & 0xC0) == 0x80) + /* Single-byte character marked as multibyte, or + a non-first byte in a multibyte character. */ + return -1; + + /* Multibyte character. */ + while ((c & 0x80)) + bytes++, c <<= 1; + read_bytes = 1; + character = c & 0x7F; + if (bytes > 6) + /* 31-bit characters can be encoded with 6-bytes, + and UTF-8 does not cover higher code points. */ + return -1; + } else { + /* Not first byte of the character. */ + + if ((c & 0xC0) != 0x80) + /* Beginning of new character before a + multibyte character has ended. */ + return -1; + + character = (character << 6) | (c & 0x7F); + + if (++read_bytes < bytes) + /* Not at last byte yet. */ + continue; + + /* Check that the character is not unnecessarily long. */ + while (character) + character >>= 1, bits++; + bits = ((bits == 0) && (bytes == 2) && allow_modified_nul) ? 8 : bits; + if ((bits < BYTES_TO_MIN_BITS[bytes]) || (BYTES_TO_MAX_BITS[bytes] < bits)) + return -1; + + read_bytes = bytes = bits = 0; + } + } + + /* Make sure we did not stop at the middle of a multibyte character. */ + return read_bytes == 0 ? 0 : -1; } @@ -828,85 +831,85 @@ int verify_utf8(const char* string, int allow_modified_nul) * @param message_id The message ID of this message * @return The length of the message, zero on error */ -size_t construct_error_message(const char* restrict recv_client_id, const char* restrict recv_message_id, - const char* restrict recv_command, int custom, int errnum, - const char* restrict message, char** restrict send_buffer, - size_t* restrict send_buffer_size, uint32_t message_id) +size_t +construct_error_message(const char *restrict recv_client_id, const char *restrict recv_message_id, + const char *restrict recv_command, int custom, int errnum, + const char *restrict message, char **restrict send_buffer, + size_t *restrict send_buffer_size, uint32_t message_id) { - ssize_t part_length; - size_t length; - char* temp; - - /* Measure the maximum length of message, including NUL-termination.. */ - length = sizeof("Command: error\n" - "To: 4294967296:4294967296\n" - "In response to: 4294967296\n" - "Origin command: \n" - "Message ID: 4294967296\n" - "Error: custom \n" - "Length: \n" - "\n") / sizeof(char) + 3 * (sizeof(int)) + strlen(recv_command); - if (message != NULL) - length += (sizeof("Length: \n") / sizeof(char) - 1) + 3 * sizeof(char) + strlen(message) + 1; - - /* Ensure that the send buffer is large enough. */ - if (length > *send_buffer_size) - { - fail_if (yrealloc(temp, *send_buffer, length, char)); - *send_buffer_size = length; - } - - /* Reset `length` to indicate that the currently written - message has zero in length. */ - length = 0; - - /* Start writting the error message, begin with required - headers, but exclude the error number. */ - sprintf((*send_buffer) + length, - "Command: error\n" - "To: %s\n" - "In response to: %s\n" - "Origin command: %s\n" - "Message ID: %"PRIu32"\n" - "Error: %s%zn", - recv_client_id, recv_message_id, recv_command, - message_id, custom ? "custom" : "", - &part_length), - length += (size_t)part_length; - - /* If the error is custom and has a number we need - blank space before we write the error number. */ - if (custom && (errnum >= 0)) - (*send_buffer)[length++] = ' '; - - /* Add the error number of there is one. */ - if (errnum >= 0) - sprintf((*send_buffer) + length, "%i%zn", errnum, &part_length), - length += (size_t)part_length; - - /* End the `Error`-header line. */ - (*send_buffer)[length++] = '\n'; - - /* Add the `Length`-header if there is a description. */ - if (message != NULL) - sprintf((*send_buffer) + length, "Length: %zu\n%zn", - strlen(message) + 1, &part_length), - length += (size_t)part_length + strlen(message) + 1; - - /* Add an empty line to mark the end of headers. */ - (*send_buffer)[length++] = '\n'; - - /* Write the description if there is one. */ - if (message) - { - memcpy((*send_buffer) + length, message, strlen(message) * sizeof(char)); - length += strlen(message); - (*send_buffer)[length++] = '\n'; - } - - return length; - fail: - return 0; + ssize_t part_length; + size_t length; + char *temp; + + /* Measure the maximum length of message, including NUL-termination.. */ + length = sizeof("Command: error\n" + "To: 4294967296:4294967296\n" + "In response to: 4294967296\n" + "Origin command: \n" + "Message ID: 4294967296\n" + "Error: custom \n" + "Length: \n" + "\n") / sizeof(char) + 3 * (sizeof(int)) + strlen(recv_command); + if (message) + length += (sizeof("Length: \n") / sizeof(char) - 1) + 3 * sizeof(char) + strlen(message) + 1; + + /* Ensure that the send buffer is large enough. */ + if (length > *send_buffer_size) { + fail_if (yrealloc(temp, *send_buffer, length, char)); + *send_buffer_size = length; + } + + /* Reset `length` to indicate that the currently written + message has zero in length. */ + length = 0; + + /* Start writting the error message, begin with required + headers, but exclude the error number. */ + sprintf((*send_buffer) + length, + "Command: error\n" + "To: %s\n" + "In response to: %s\n" + "Origin command: %s\n" + "Message ID: %"PRIu32"\n" + "Error: %s%zn", + recv_client_id, recv_message_id, recv_command, + message_id, custom ? "custom" : "", + &part_length); + length += (size_t)part_length; + + /* If the error is custom and has a number we need + blank space before we write the error number. */ + if (custom && errnum >= 0) + (*send_buffer)[length++] = ' '; + + /* Add the error number of there is one. */ + if (errnum >= 0) + sprintf((*send_buffer) + length, "%i%zn", errnum, &part_length), + length += (size_t)part_length; + + /* End the `Error`-header line. */ + (*send_buffer)[length++] = '\n'; + + /* Add the `Length`-header if there is a description. */ + if (message) { + sprintf((*send_buffer) + length, "Length: %zu\n%zn", + strlen(message) + 1, &part_length); + length += (size_t)part_length + strlen(message) + 1; + } + + /* Add an empty line to mark the end of headers. */ + (*send_buffer)[length++] = '\n'; + + /* Write the description if there is one. */ + if (message) { + memcpy((*send_buffer) + length, message, strlen(message) * sizeof(char)); + length += strlen(message); + (*send_buffer)[length++] = '\n'; + } + + return length; +fail: + return 0; } @@ -936,17 +939,17 @@ size_t construct_error_message(const char* restrict recv_client_id, const char* * @param message_id The message ID of this message * @return Zero on success, -1 on error */ -int send_error(const char* restrict recv_client_id, const char* restrict recv_message_id, - const char* restrict recv_command, int custom, int errnum, const char* restrict message, - char** restrict send_buffer, size_t* restrict send_buffer_size, uint32_t message_id, - int socket_fd) +int +send_error(const char *restrict recv_client_id, const char *restrict recv_message_id, + const char *restrict recv_command, int custom, int errnum, const char *restrict message, + char **restrict send_buffer, size_t *restrict send_buffer_size, uint32_t message_id, + int socket_fd) { - size_t length; - fail_if ((length = construct_error_message(recv_client_id, recv_message_id, recv_command, custom, errnum, - message, send_buffer, send_buffer_size, message_id)) == 0); - fail_if (full_send(socket_fd, *send_buffer, length)); - return 0; - fail: - return -1; + size_t length; + fail_if (!(length = construct_error_message(recv_client_id, recv_message_id, recv_command, custom, errnum, + message, send_buffer, send_buffer_size, message_id))); + fail_if (full_send(socket_fd, *send_buffer, length)); + return 0; +fail: + return -1; } - diff --git a/src/mds-base.h b/src/mds-base.h index 9950117..c3bc735 100644 --- a/src/mds-base.h +++ b/src/mds-base.h @@ -23,15 +23,14 @@ #include -#define MDS_BASE_VARS_VERSION 0 +#define MDS_BASE_VARS_VERSION 0 /** * Characteristics of the server */ -typedef struct server_characteristics -{ +typedef struct server_characteristics { /** * Setting this to zero will cause the server to drop privileges as a security precaution */ @@ -78,7 +77,6 @@ typedef struct server_characteristics * --immortal is used. */ unsigned danger_is_deadly : 1; - } __attribute__((packed)) server_characteristics_t; diff --git a/src/mds-clipboard.h b/src/mds-clipboard.h index 26c15a4..f3672ff 100644 --- a/src/mds-clipboard.h +++ b/src/mds-clipboard.h @@ -30,30 +30,29 @@ /** * Delete entry only when needed */ -#define CLIPITEM_AUTOPURGE_NEVER 0 +#define CLIPITEM_AUTOPURGE_NEVER 0 /** * Delete entry when the client closes, or needed */ -#define CLIPITEM_AUTOPURGE_UPON_DEATH 1 +#define CLIPITEM_AUTOPURGE_UPON_DEATH 1 /** * Delete entry when a point in time has elapsed, or needed */ -#define CLIPITEM_AUTOPURGE_UPON_CLOCK 2 +#define CLIPITEM_AUTOPURGE_UPON_CLOCK 2 /** * Delete entry when the client closes or when a * point in time has elapsed, or when needed */ -#define CLIPITEM_AUTOPURGE_UPON_DEATH_OR_CLOCK 3 +#define CLIPITEM_AUTOPURGE_UPON_DEATH_OR_CLOCK 3 /** * A clipboard entry */ -typedef struct clipitem -{ +typedef struct clipitem { /** * The stored content */ @@ -78,7 +77,6 @@ typedef struct clipitem * Rule for automatic deletion */ int autopurge; - } clipitem_t; diff --git a/src/mds-colour.h b/src/mds-colour.h index 3ab718e..1332198 100644 --- a/src/mds-colour.h +++ b/src/mds-colour.h @@ -30,8 +30,7 @@ /** * Data structure for colour */ -typedef struct colour -{ +typedef struct colour { /** * The value of the red channel */ @@ -52,7 +51,6 @@ typedef struct colour * each channel is encoded */ int bytes; - } colour_t; @@ -139,4 +137,3 @@ void colour_list_entry_free(colour_list_entry_t *entry); #endif - diff --git a/src/mds-echo.c b/src/mds-echo.c index 2bb505f..72f43f8 100644 --- a/src/mds-echo.c +++ b/src/mds-echo.c @@ -30,7 +30,7 @@ -#define MDS_ECHO_VARS_VERSION 0 +#define MDS_ECHO_VARS_VERSION 0 @@ -363,4 +363,3 @@ received_info(int signo) iprintf("echo buffer size: %zu bytes", echo_buffer_size); SIGHANDLER_END; } - diff --git a/src/mds-echo.h b/src/mds-echo.h index 72aedca..5a6e87b 100644 --- a/src/mds-echo.h +++ b/src/mds-echo.h @@ -32,4 +32,3 @@ int echo_message(void); #endif - diff --git a/src/mds-kbdc/builtin-functions.c b/src/mds-kbdc/builtin-functions.c index e0594ab..72593cd 100644 --- a/src/mds-kbdc/builtin-functions.c +++ b/src/mds-kbdc/builtin-functions.c @@ -29,35 +29,35 @@ /** * Define useful data for built-in function with 2 parameters */ -#define define_2 \ - const char32_t* restrict a = *args++; \ - const char32_t* restrict b = *args++; \ - size_t an = string_length(a); \ - size_t bn = string_length(b); \ - size_t i, n = an > bn ? an : bn; \ - char32_t* restrict rc; \ - fail_if (xmalloc(rc, n + 1, char32_t)); \ - rc[n] = -1 +#define define_2\ + const char32_t *restrict a = *args++;\ + const char32_t *restrict b = *args++;\ + size_t an = string_length(a);\ + size_t bn = string_length(b);\ + size_t i, n = an > bn ? an : bn;\ + char32_t *restrict rc;\ + fail_if (xmalloc(rc, n + 1, char32_t));\ + rc[n] = -1 /** * Define useful data for built-in function with 1 parameter */ -#define define_1 \ - const char32_t* restrict a = *args++; \ - size_t i, n = string_length(a); \ - char32_t* restrict rc; \ - fail_if (xmalloc(rc, n + 1, char32_t)); \ - rc[n] = -1 +#define define_1\ + const char32_t* restrict a = *args++;\ + size_t i, n = string_length(a);\ + char32_t *restrict rc;\ + fail_if (xmalloc(rc, n + 1, char32_t));\ + rc[n] = -1 /** * Return a value, or if there was a failure somewhere, return `NULL` * * @param v:void* The value to return on success */ -#define return(v) \ - return v; \ - fail: \ - return NULL; +#define return(v)\ + return v;\ +fail:\ + return NULL; /** @@ -66,12 +66,13 @@ * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_add_2(const char32_t** restrict args) +static char32_t * +builtin_function_add_2(const char32_t **restrict args) { - define_2; - for (i = 0; i < n; i++) - rc[i] = a[i % an] + b[i % bn]; - return(rc); + define_2; + for (i = 0; i < n; i++) + rc[i] = a[i % an] + b[i % bn]; + return(rc); } @@ -81,12 +82,13 @@ static char32_t* builtin_function_add_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_sub_2(const char32_t** restrict args) +static char32_t * +builtin_function_sub_2(const char32_t **restrict args) { - define_2; - for (i = 0; i < n; i++) - rc[i] = a[i % an] - b[i % bn]; - return(rc); + define_2; + for (i = 0; i < n; i++) + rc[i] = a[i % an] - b[i % bn]; + return(rc); } @@ -96,12 +98,13 @@ static char32_t* builtin_function_sub_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_mul_2(const char32_t** restrict args) +static char32_t * +builtin_function_mul_2(const char32_t **restrict args) { - define_2; - for (i = 0; i < n; i++) - rc[i] = a[i % an] * b[i % bn]; - return(rc); + define_2; + for (i = 0; i < n; i++) + rc[i] = a[i % an] * b[i % bn]; + return(rc); } @@ -111,12 +114,13 @@ static char32_t* builtin_function_mul_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_div_2(const char32_t** restrict args) +static char32_t * +builtin_function_div_2(const char32_t **restrict args) { - define_2; - for (i = 0; i < n; i++) - rc[i] = a[i % an] / b[i % bn]; - return(rc); + define_2; + for (i = 0; i < n; i++) + rc[i] = a[i % an] / b[i % bn]; + return(rc); } @@ -126,12 +130,13 @@ static char32_t* builtin_function_div_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_mod_2(const char32_t** restrict args) +static char32_t * +builtin_function_mod_2(const char32_t **restrict args) { - define_2; - for (i = 0; i < n; i++) - rc[i] = a[i % an] % b[i % bn]; - return(rc); + define_2; + for (i = 0; i < n; i++) + rc[i] = a[i % an] % b[i % bn]; + return(rc); } @@ -141,12 +146,13 @@ static char32_t* builtin_function_mod_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_rsh_2(const char32_t** restrict args) +static char32_t * +builtin_function_rsh_2(const char32_t **restrict args) { - define_2; - for (i = 0; i < n; i++) - rc[i] = a[i % an] >> b[i % bn]; - return(rc); + define_2; + for (i = 0; i < n; i++) + rc[i] = a[i % an] >> b[i % bn]; + return(rc); } @@ -156,12 +162,13 @@ static char32_t* builtin_function_rsh_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_lsh_2(const char32_t** restrict args) +static char32_t * +builtin_function_lsh_2(const char32_t **restrict args) { - define_2; - for (i = 0; i < n; i++) - rc[i] = a[i % an] << b[i % bn]; - return(rc); + define_2; + for (i = 0; i < n; i++) + rc[i] = a[i % an] << b[i % bn]; + return(rc); } @@ -171,12 +178,13 @@ static char32_t* builtin_function_lsh_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_or_2(const char32_t** restrict args) +static char32_t * +builtin_function_or_2(const char32_t **restrict args) { - define_2; - for (i = 0; i < n; i++) - rc[i] = a[i % an] | b[i % bn]; - return(rc); + define_2; + for (i = 0; i < n; i++) + rc[i] = a[i % an] | b[i % bn]; + return(rc); } @@ -186,12 +194,13 @@ static char32_t* builtin_function_or_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_and_2(const char32_t** restrict args) +static char32_t * +builtin_function_and_2(const char32_t **restrict args) { - define_2; - for (i = 0; i < n; i++) - rc[i] = a[i % an] & b[i % bn]; - return(rc); + define_2; + for (i = 0; i < n; i++) + rc[i] = a[i % an] & b[i % bn]; + return(rc); } @@ -201,12 +210,13 @@ static char32_t* builtin_function_and_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_xor_2(const char32_t** restrict args) +static char32_t * +builtin_function_xor_2(const char32_t **restrict args) { - define_2; - for (i = 0; i < n; i++) - rc[i] = a[i % an] ^ b[i % bn]; - return(rc); + define_2; + for (i = 0; i < n; i++) + rc[i] = a[i % an] ^ b[i % bn]; + return(rc); } @@ -216,12 +226,13 @@ static char32_t* builtin_function_xor_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_not_1(const char32_t** restrict args) +static char32_t * +builtin_function_not_1(const char32_t **restrict args) { - define_1; - for (i = 0; i < n; i++) - rc[i] = !a[i]; - return(rc); + define_1; + for (i = 0; i < n; i++) + rc[i] = !a[i]; + return(rc); } @@ -231,12 +242,13 @@ static char32_t* builtin_function_not_1(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_equals_2(const char32_t** restrict args) +static char32_t * +builtin_function_equals_2(const char32_t **restrict args) { - define_2; - for (i = 0; i < n; i++) - rc[i] = a[i % an] == b[i % bn]; - return(rc); + define_2; + for (i = 0; i < n; i++) + rc[i] = a[i % an] == b[i % bn]; + return(rc); } @@ -246,12 +258,13 @@ static char32_t* builtin_function_equals_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_greater_2(const char32_t** restrict args) +static char32_t * +builtin_function_greater_2(const char32_t **restrict args) { - define_2; - for (i = 0; i < n; i++) - rc[i] = a[i % an] > b[i % bn]; - return(rc); + define_2; + for (i = 0; i < n; i++) + rc[i] = a[i % an] > b[i % bn]; + return(rc); } @@ -261,12 +274,13 @@ static char32_t* builtin_function_greater_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_less_2(const char32_t** restrict args) +static char32_t * +builtin_function_less_2(const char32_t **restrict args) { - define_2; - for (i = 0; i < n; i++) - rc[i] = a[i % an] < b[i % bn]; - return(rc); + define_2; + for (i = 0; i < n; i++) + rc[i] = a[i % an] < b[i % bn]; + return(rc); } @@ -276,17 +290,18 @@ static char32_t* builtin_function_less_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_get_2(const char32_t** restrict args) +static char32_t * +builtin_function_get_2(const char32_t **restrict args) { - const char32_t* restrict a = *args++; - const char32_t* restrict b = *args++; - char32_t* restrict rc; - size_t n = (size_t)*b; - mds_kbdc_tree_t* value = variables_get((size_t)*a)->array.elements; - while (n--) - value = value->next; - fail_if (rc = string_dup(value->compiled_string.string), rc == NULL); - return(rc); + const char32_t *restrict a = *args++; + const char32_t *restrict b = *args++; + char32_t *restrict rc; + size_t n = (size_t)*b; + mds_kbdc_tree_t *value = variables_get((size_t)*a)->array.elements; + while (n--) + value = value->next; + fail_if (rc = string_dup(value->compiled_string.string), rc == NULL); + return(rc); } @@ -296,21 +311,22 @@ static char32_t* builtin_function_get_2(const char32_t** restrict args) * @param args The arguments passed to the function * @return The return value of the function, `NULL` on error */ -static char32_t* builtin_function_set_3(const char32_t** restrict args) +static char32_t * +builtin_function_set_3(const char32_t **restrict args) { - const char32_t* restrict a = *args++; - const char32_t* restrict b = *args++; - const char32_t* restrict c = *args++; - char32_t* restrict rc; - size_t n = (size_t)*b; - mds_kbdc_tree_t* value = variables_get((size_t)*a)->array.elements; - while (n--) - value = value->next; - free(value->compiled_string.string); - value->compiled_string.string = string_dup(c); - fail_if (value->compiled_string.string == NULL); - fail_if (rc = string_dup(c), rc == NULL); - return(rc); + const char32_t *restrict a = *args++; + const char32_t *restrict b = *args++; + const char32_t *restrict c = *args++; + char32_t *restrict rc; + size_t n = (size_t)*b; + mds_kbdc_tree_t *value = variables_get((size_t)*a)->array.elements; + while (n--) + value = value->next; + free(value->compiled_string.string); + value->compiled_string.string = string_dup(c); + fail_if (!value->compiled_string.string); + fail_if (!(rc = string_dup(c))); + return(rc); } @@ -326,25 +342,26 @@ static char32_t* builtin_function_set_3(const char32_t** restrict args) * @param arg_count The number of arguments to pass to the function * @return Whether the described function is a builtin function */ -int builtin_function_defined(const char* restrict name, size_t arg_count) +int +builtin_function_defined(const char *restrict name, size_t arg_count) { - size_t i; - static const char* const BUILTIN_FUNCTIONS_2[] = - { - "add", "sub", "mul", "div", "mod", "rsh", "lsh", "or", - "and", "xor", "equals", "greater", "less", "get", NULL - }; - - if (arg_count == 3) - return !strcmp(name, "set"); - else if (arg_count == 1) - return !strcmp(name, "not"); - else if (arg_count == 2) - for (i = 0; BUILTIN_FUNCTIONS_2[i]; i++) - if (!strcmp(name, BUILTIN_FUNCTIONS_2[i])) - return 1; - - return 0; + size_t i; + static const char* const BUILTIN_FUNCTIONS_2[] = { + "add", "sub", "mul", "div", "mod", "rsh", "lsh", "or", + "and", "xor", "equals", "greater", "less", "get", NULL + }; + + if (arg_count == 1) { + return !strcmp(name, "not"); + } else if (arg_count == 2) { + for (i = 0; BUILTIN_FUNCTIONS_2[i]; i++) + if (!strcmp(name, BUILTIN_FUNCTIONS_2[i])) + return 1; + } else if (arg_count == 3) { + return !strcmp(name, "set"); + } + + return 0; } @@ -362,35 +379,35 @@ int builtin_function_defined(const char* restrict name, size_t arg_count) * @param args The arguments to pass * @return The return value of the function, `NULL` on error */ -char32_t* builtin_function_invoke(const char* restrict name, size_t arg_count, const char32_t** restrict args) +char32_t * +builtin_function_invoke(const char *restrict name, size_t arg_count, const char32_t **restrict args) { -#define t(f) do { fail_if (rc = builtin_function_##f(args), rc == NULL); return rc; } while (0) - char32_t* rc; - - if ((arg_count == 3) && !strcmp(name, "set")) t (set_3); - if ((arg_count == 1) && !strcmp(name, "not")) t (not_1); - - if (arg_count != 2) - abort(); - - if (!strcmp(name, "add")) t (add_2); - if (!strcmp(name, "sub")) t (sub_2); - if (!strcmp(name, "mul")) t (mul_2); - if (!strcmp(name, "div")) t (div_2); - if (!strcmp(name, "mod")) t (mod_2); - if (!strcmp(name, "rsh")) t (rsh_2); - if (!strcmp(name, "lsh")) t (lsh_2); - if (!strcmp(name, "or")) t (or_2); - if (!strcmp(name, "and")) t (and_2); - if (!strcmp(name, "xor")) t (xor_2); - if (!strcmp(name, "equals")) t (equals_2); - if (!strcmp(name, "greater")) t (greater_2); - if (!strcmp(name, "less")) t (less_2); - if (!strcmp(name, "get")) t (get_2); - - abort(); - fail: - return NULL; +#define t(f) do { fail_if (rc = builtin_function_##f(args), rc == NULL); return rc; } while (0) + char32_t *rc; + + if (arg_count == 3 && !strcmp(name, "set")) t (set_3); + if (arg_count == 1 && !strcmp(name, "not")) t (not_1); + + if (arg_count != 2) + abort(); + + if (!strcmp(name, "add")) t (add_2); + if (!strcmp(name, "sub")) t (sub_2); + if (!strcmp(name, "mul")) t (mul_2); + if (!strcmp(name, "div")) t (div_2); + if (!strcmp(name, "mod")) t (mod_2); + if (!strcmp(name, "rsh")) t (rsh_2); + if (!strcmp(name, "lsh")) t (lsh_2); + if (!strcmp(name, "or")) t (or_2); + if (!strcmp(name, "and")) t (and_2); + if (!strcmp(name, "xor")) t (xor_2); + if (!strcmp(name, "equals")) t (equals_2); + if (!strcmp(name, "greater")) t (greater_2); + if (!strcmp(name, "less")) t (less_2); + if (!strcmp(name, "get")) t (get_2); + + abort(); +fail: + return NULL; #undef t } - diff --git a/src/mds-kbdc/builtin-functions.h b/src/mds-kbdc/builtin-functions.h index fe94205..8d2cc2d 100644 --- a/src/mds-kbdc/builtin-functions.h +++ b/src/mds-kbdc/builtin-functions.h @@ -33,7 +33,8 @@ * @param arg_count The number of arguments to pass to the function * @return Whether the described function is a builtin function */ -int builtin_function_defined(const char* restrict name, size_t arg_count) __attribute__((pure)); +__attribute__((pure)) +int builtin_function_defined(const char *restrict name, size_t arg_count); /** * Invoke a builtin function @@ -49,9 +50,8 @@ int builtin_function_defined(const char* restrict name, size_t arg_count) __attr * @param args The arguments to pass * @return The return value of the function, `NULL` on error */ -char32_t* builtin_function_invoke(const char* restrict name, size_t arg_count, const char32_t** restrict args); +char32_t *builtin_function_invoke(const char *restrict name, size_t arg_count, const char32_t **restrict args); #endif - diff --git a/src/mds-kbdc/call-stack.c b/src/mds-kbdc/call-stack.c index 92c83a7..c864e7c 100644 --- a/src/mds-kbdc/call-stack.c +++ b/src/mds-kbdc/call-stack.c @@ -24,31 +24,29 @@ /** * An entry in the call-stack */ -typedef struct mds_kbdc_call -{ - /** - * The tree node where the call was made - */ - const mds_kbdc_tree_t* tree; - - /** - * The position of the line of the tree node - * where the call begins - */ - size_t start; - - /** - * The position of the line of the tree node - * where the call end - */ - size_t end; - - /** - * A snapshot of the include-stack as it - * looked when the call was being made - */ - mds_kbdc_include_stack_t* include_stack; - +typedef struct mds_kbdc_call { + /** + * The tree node where the call was made + */ + const mds_kbdc_tree_t *tree; + + /** + * The position of the line of the tree node + * where the call begins + */ + size_t start; + + /** + * The position of the line of the tree node + * where the call end + */ + size_t end; + + /** + * A snapshot of the include-stack as it + * looked when the call was being made + */ + mds_kbdc_include_stack_t *include_stack; } mds_kbdc_call_t; @@ -56,27 +54,27 @@ typedef struct mds_kbdc_call /** * Variable whether the latest created error is stored */ -static mds_kbdc_parse_error_t* error; +static mds_kbdc_parse_error_t *error; /** * The `result` parameter of root procedure that requires the include-stack */ -static mds_kbdc_parsed_t* result; +static mds_kbdc_parsed_t *result; /** * The original value of `result->pathname` */ -static char* original_pathname; +static char *original_pathname; /** * The original value of `result->source_code` */ -static mds_kbdc_source_code_t* original_source_code; +static mds_kbdc_source_code_t *original_source_code; /** * Stack of visited function- and macro-calls */ -static mds_kbdc_call_t* restrict calls = NULL; +static mds_kbdc_call_t *restrict calls = NULL; /** * The number elements allocated for `calls` @@ -95,57 +93,59 @@ static size_t calls_ptr = 0; * * @return Zero on success, -1 on error */ -int mds_kbdc_call_stack_dump(void) +int +mds_kbdc_call_stack_dump(void) { - char* old_pathname = result->pathname; - mds_kbdc_source_code_t* old_source_code = result->source_code; - size_t ptr = calls_ptr, iptr; - mds_kbdc_call_t* restrict call; - mds_kbdc_include_stack_t* restrict includes; - - while (ptr--) - { - call = calls + ptr; - includes = call->include_stack; - iptr = includes->ptr; - result->pathname = iptr ? includes->stack[iptr - 1]->filename : original_pathname; - result->source_code = iptr ? includes->stack[iptr - 1]->source_code : original_source_code; - NEW_ERROR_(result, NOTE, 1, call->tree->loc_line, call->start, call->end, 1, "called from here"); - DUMP_INCLUDE_STACK(iptr); - } - - result->pathname = old_pathname; - result->source_code = old_source_code; - return 0; - fail: - result->pathname = old_pathname; - result->source_code = old_source_code; - return -1; + char *old_pathname = result->pathname; + mds_kbdc_source_code_t *old_source_code = result->source_code; + size_t ptr = calls_ptr, iptr; + mds_kbdc_call_t *restrict call; + mds_kbdc_include_stack_t *restrict includes; + + while (ptr--) { + call = calls + ptr; + includes = call->include_stack; + iptr = includes->ptr; + result->pathname = iptr ? includes->stack[iptr - 1]->filename : original_pathname; + result->source_code = iptr ? includes->stack[iptr - 1]->source_code : original_source_code; + NEW_ERROR_(result, NOTE, 1, call->tree->loc_line, call->start, call->end, 1, "called from here"); + DUMP_INCLUDE_STACK(iptr); + } + + result->pathname = old_pathname; + result->source_code = old_source_code; + return 0; +fail: + result->pathname = old_pathname; + result->source_code = old_source_code; + return -1; } /** * Prepare for usage of call-stacks * -xo * @param result_ The `result` parameter of root procedure that requires the call-stack + * @param result_ The `result` parameter of root procedure that requires the call-stack */ -void mds_kbdc_call_stack_begin(mds_kbdc_parsed_t* restrict result_) +void +mds_kbdc_call_stack_begin(mds_kbdc_parsed_t *restrict result_) { - result = result_; - original_pathname = result_->pathname; - original_source_code = result_->source_code; + result = result_; + original_pathname = result_->pathname; + original_source_code = result_->source_code; } /** * Cleanup after usage of call-stacks */ -void mds_kbdc_call_stack_end(void) +void +mds_kbdc_call_stack_end(void) { - result->pathname = original_pathname; - result->source_code = original_source_code; - free(calls), calls = NULL; - calls_size = calls_ptr = 0; + result->pathname = original_pathname; + result->source_code = original_source_code; + free(calls), calls = NULL; + calls_size = calls_ptr = 0; } @@ -157,27 +157,27 @@ void mds_kbdc_call_stack_end(void) * @param end The position of the line of the tree node where the call end * @return Zero on success, -1 on error */ -int mds_kbdc_call_stack_push(const mds_kbdc_tree_t* restrict tree, size_t start, size_t end) +int +mds_kbdc_call_stack_push(const mds_kbdc_tree_t *restrict tree, size_t start, size_t end) { - mds_kbdc_call_t* tmp; - mds_kbdc_call_t* call; - - if (calls_ptr == calls_size) - { - fail_if (yrealloc(tmp, calls, calls_size + 4, mds_kbdc_call_t)); - calls_size += 4; - } - - call = calls + calls_ptr++; - call->tree = tree; - call->start = start; - call->end = end; - call->include_stack = mds_kbdc_include_stack_save(); - fail_if (call->include_stack == NULL); - - return 0; - fail: - return -1; + mds_kbdc_call_t *tmp; + mds_kbdc_call_t *call; + + if (calls_ptr == calls_size) { + fail_if (yrealloc(tmp, calls, calls_size + 4, mds_kbdc_call_t)); + calls_size += 4; + } + + call = calls + calls_ptr++; + call->tree = tree; + call->start = start; + call->end = end; + call->include_stack = mds_kbdc_include_stack_save(); + fail_if (!call->include_stack); + + return 0; +fail: + return -1; } @@ -186,10 +186,10 @@ int mds_kbdc_call_stack_push(const mds_kbdc_tree_t* restrict tree, size_t start, * * This function is guaranteed not to modify `errno` */ -void mds_kbdc_call_stack_pop(void) +void +mds_kbdc_call_stack_pop(void) { - int saved_errno = errno; - mds_kbdc_include_stack_free(calls[--calls_ptr].include_stack); - errno = saved_errno; + int saved_errno = errno; + mds_kbdc_include_stack_free(calls[--calls_ptr].include_stack); + errno = saved_errno; } - diff --git a/src/mds-kbdc/call-stack.h b/src/mds-kbdc/call-stack.h index db7a18a..94b6dc8 100644 --- a/src/mds-kbdc/call-stack.h +++ b/src/mds-kbdc/call-stack.h @@ -27,8 +27,8 @@ /** * Add “called from here”-notes */ -#define DUMP_CALL_STACK \ - fail_if (mds_kbdc_call_stack_dump()) +#define DUMP_CALL_STACK\ + fail_if (mds_kbdc_call_stack_dump()) @@ -44,7 +44,7 @@ int mds_kbdc_call_stack_dump(void); * * @param result The `result` parameter of root procedure that requires the call-stack */ -void mds_kbdc_call_stack_begin(mds_kbdc_parsed_t* restrict result); +void mds_kbdc_call_stack_begin(mds_kbdc_parsed_t *restrict result); /** * Cleanup after usage of call-stacks @@ -59,7 +59,7 @@ void mds_kbdc_call_stack_end(void); * @param end The position of the line of the tree node where the call end * @return Zero on success, -1 on error */ -int mds_kbdc_call_stack_push(const mds_kbdc_tree_t* restrict tree, size_t start, size_t end); +int mds_kbdc_call_stack_push(const mds_kbdc_tree_t *restrict tree, size_t start, size_t end); /** * Undo the lasted not-undone call to `mds_kbdc_call_stack_push` @@ -71,4 +71,3 @@ void mds_kbdc_call_stack_pop(void); #endif - diff --git a/src/mds-kbdc/callables.c b/src/mds-kbdc/callables.c index 24b1e8a..07b08b0 100644 --- a/src/mds-kbdc/callables.c +++ b/src/mds-kbdc/callables.c @@ -25,29 +25,29 @@ /** * Map, by index, from argument count, to list of callable's names */ -static char*** restrict names = NULL; +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; +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; +static size_t *restrict bucket_sizes = NULL; /** * List of callables */ -static mds_kbdc_tree_t** restrict callable_list = NULL; +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; +static mds_kbdc_include_stack_t **restrict callable_include_stack_list = NULL; /** * The number of buckets in `names` and `bucket_sizes` @@ -64,26 +64,26 @@ static size_t list_ptr = 0; /** * Destroy the callable storage */ -void callables_terminate(void) +void +callables_terminate(void) { - size_t i, j, n; - char** bucket; - for (i = 0; i < buckets; i++) - { - bucket = names[i]; - for (j = 0, n = bucket_sizes[i]; j < n; j++) - free(bucket[j]); - free(bucket); - free(callables[i]); - } - for (i = 0; i < list_ptr; i++) - mds_kbdc_include_stack_free(callable_include_stack_list[i]); - free(callables), callables = NULL; - 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; + size_t i, j, n; + char **bucket; + for (i = 0; i < buckets; i++) { + bucket = names[i]; + for (j = 0, n = bucket_sizes[i]; j < n; j++) + free(bucket[j]); + free(bucket); + free(callables[i]); + } + for (i = 0; i < list_ptr; i++) + mds_kbdc_include_stack_free(callable_include_stack_list[i]); + free(callables), callables = NULL; + 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; } @@ -97,57 +97,57 @@ void callables_terminate(void) * @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) +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) (yrealloc(tmp_##var, var, elements, type)) - - char* dupname = NULL; - char*** tmp_names = NULL; - size_t** tmp_callables = NULL; - size_t* tmp_bucket_sizes = NULL; - char** old_names = NULL; - size_t* old_callables = NULL; - mds_kbdc_tree_t** tmp_callable_list = NULL; - mds_kbdc_include_stack_t** tmp_callable_include_stack_list = NULL; - int saved_errno; - - fail_if (xstrdup(dupname, name)); - - 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 + buckets, 0, (arg_count + 1 - buckets) * sizeof(char**)); - memset(callables + buckets, 0, (arg_count + 1 - buckets) * sizeof(size_t*)); - memset(bucket_sizes + buckets, 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; - fail: - saved_errno = errno; - free(dupname); - if (old_names) - names[arg_count] = old_names; - if (old_callables) - callables[arg_count] = old_callables; - return errno = saved_errno, -1; +#define _yrealloc(var, elements, type) (yrealloc(tmp_##var, var, elements, type)) + + char *dupname = NULL; + char ***tmp_names = NULL; + size_t **tmp_callables = NULL; + size_t *tmp_bucket_sizes = NULL; + char **old_names = NULL; + size_t *old_callables = NULL; + mds_kbdc_tree_t **tmp_callable_list = NULL; + mds_kbdc_include_stack_t **tmp_callable_include_stack_list = NULL; + int saved_errno; + + fail_if (xstrdup(dupname, name)); + + 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 + buckets, 0, (arg_count + 1 - buckets) * sizeof(char**)); + memset(callables + buckets, 0, (arg_count + 1 - buckets) * sizeof(size_t*)); + memset(bucket_sizes + buckets, 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; +fail: + saved_errno = errno; + free(dupname); + if (old_names) + names[arg_count] = old_names; + if (old_callables) + callables[arg_count] = old_callables; + return errno = saved_errno, -1; #undef _yrealloc } @@ -161,27 +161,26 @@ int callables_set(const char* restrict name, size_t arg_count, mds_kbdc_tree_t* * @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) +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_; - size_t i, n; - - *callable = NULL; - *callable_include_stack = NULL; - - if (arg_count >= buckets) - return; - - names_ = names[arg_count]; - for (i = 0, n = bucket_sizes[arg_count]; 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; - } + char **restrict names_; + size_t i, n; + + *callable = NULL; + *callable_include_stack = NULL; + + if (arg_count >= buckets) + return; + + names_ = names[arg_count]; + for (i = 0, n = bucket_sizes[arg_count]; 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 index bb453f1..9e0d3b3 100644 --- a/src/mds-kbdc/callables.h +++ b/src/mds-kbdc/callables.h @@ -38,8 +38,8 @@ void callables_terminate(void); * @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); +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 @@ -50,9 +50,8 @@ int callables_set(const char* restrict name, size_t arg_count, mds_kbdc_tree_t* * @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); +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 199e870..8eb832b 100644 --- a/src/mds-kbdc/compile-layout.c +++ b/src/mds-kbdc/compile-layout.c @@ -34,12 +34,12 @@ /** * This process's value for `mds_kbdc_tree_t.processed` */ -#define PROCESS_LEVEL 6 +#define PROCESS_LEVEL 6 /** * Tree type constant shortener */ -#define C(TYPE) MDS_KBDC_TREE_TYPE_##TYPE +#define C(TYPE) MDS_KBDC_TREE_TYPE_##TYPE /** * Add an error with “included from here”-notes and, unless @@ -50,36 +50,34 @@ * @param ...:const char*, ... Error description format string and arguments * @scope error:mds_kbdc_parse_error_t* Variable where the new error will be stored */ -#define NEW_ERROR(NODE, SEVERITY, ...) \ - do \ - { \ - NEW_ERROR_WITH_INCLUDES(NODE, includes_ptr, SEVERITY, __VA_ARGS__); \ - if (strcmp(#SEVERITY, "NOTE")) \ - DUMP_CALL_STACK; \ - } \ - while (0) +#define NEW_ERROR(NODE, SEVERITY, ...)\ + do {\ + NEW_ERROR_WITH_INCLUDES(NODE, includes_ptr, SEVERITY, __VA_ARGS__);\ + if (strcmp(#SEVERITY, "NOTE"))\ + DUMP_CALL_STACK;\ + } while (0) /** * Beginning of failure clause */ -#define FAIL_BEGIN fail: saved_errno = errno +#define FAIL_BEGIN fail: saved_errno = errno /** * End of failure clause */ -#define FAIL_END return errno = saved_errno, -1 +#define FAIL_END return errno = saved_errno, -1 /** * Variable whether the latest created error is stored */ -static mds_kbdc_parse_error_t* error; +static mds_kbdc_parse_error_t *error; /** * The parameter of `compile_layout` */ -static mds_kbdc_parsed_t* restrict result; +static mds_kbdc_parsed_t *restrict result; /** * 3: `return` is being processed @@ -101,12 +99,12 @@ static int multiple_variants = 0; * * (We will not look too hard.) */ -static mds_kbdc_tree_t* last_value_statement = NULL; +static mds_kbdc_tree_t *last_value_statement = NULL; /** * Address of the current return value */ -static char32_t** current_return_value = NULL; +static char32_t **current_return_value = NULL; /** * Whether ‘\set/3’ has been called @@ -121,7 +119,7 @@ static int have_side_effect = 0; * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_subtree(mds_kbdc_tree_t* restrict tree); +static int compile_subtree(mds_kbdc_tree_t *restrict tree); /** * Check that a function used in a part of a literal is defined @@ -133,8 +131,8 @@ static int compile_subtree(mds_kbdc_tree_t* restrict tree); * @param rc Success status output parameter: zero on success, * -1 on error, 1 if an undefined function is used */ -static void check_function_call(const mds_kbdc_tree_t* restrict tree, const char* restrict raw, - size_t lineoff, const char* restrict* restrict end, int* restrict rc); +static void check_function_call(const mds_kbdc_tree_t *restrict tree, const char *restrict raw, + size_t lineoff, const char *restrict *restrict end, int *restrict rc); /** * Parse an argument in a function call @@ -146,8 +144,8 @@ static void check_function_call(const mds_kbdc_tree_t* restrict tree, const char * @param value Output parameter for the value to which the argument evaulates * @return Zero on success, -1 on error */ -static int parse_function_argument(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff, - const char* restrict* restrict end, char32_t** restrict value); +static int parse_function_argument(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff, + const char *restrict *restrict end, char32_t **restrict value); @@ -167,37 +165,36 @@ static int parse_function_argument(mds_kbdc_tree_t* restrict tree, const char* r * but could easily be mistaked for one that does * @return Zero on success, -1 on error */ -static int let(size_t variable, const char32_t* restrict string, const mds_kbdc_tree_t* restrict value, - mds_kbdc_tree_t* restrict statement, size_t lineoff, int possibile_shadow_attempt) +static int +let(size_t variable, const char32_t *restrict string, const mds_kbdc_tree_t *restrict value, + mds_kbdc_tree_t *restrict statement, size_t lineoff, int possibile_shadow_attempt) { - mds_kbdc_tree_t* tree = NULL; - int saved_errno; - - /* Warn if this is a possible shadow attempt. */ - if (possibile_shadow_attempt && variables_let_will_override(variable) && statement && - (variables_has_been_used_in_for(variable) == 0) && (statement->processed != PROCESS_LEVEL)) - { - statement->processed = PROCESS_LEVEL; - NEW_ERROR(statement, WARNING, "does not shadow existing definition"); - error->start = lineoff; - error->end = lineoff + (size_t)snprintf(NULL, 0, "\\%zu", variable); - } - - /* Duplicate value. */ - if (value) - fail_if (tree = mds_kbdc_tree_dup(value), tree == NULL); - if (value == NULL) - { - fail_if (tree = mds_kbdc_tree_create(C(COMPILED_STRING)), tree == NULL); - fail_if ((tree->compiled_string.string = string_dup(string)) == NULL); - } - - /* Assign variable. */ - fail_if (variables_let(variable, tree)); - return 0; - FAIL_BEGIN; - mds_kbdc_tree_free(tree); - FAIL_END; + mds_kbdc_tree_t *tree = NULL; + int saved_errno; + + /* Warn if this is a possible shadow attempt. */ + if (possibile_shadow_attempt && variables_let_will_override(variable) && statement && + !variables_has_been_used_in_for(variable) && statement->processed != PROCESS_LEVEL) { + statement->processed = PROCESS_LEVEL; + NEW_ERROR(statement, WARNING, "does not shadow existing definition"); + error->start = lineoff; + error->end = lineoff + (size_t)snprintf(NULL, 0, "\\%zu", variable); + } + + /* Duplicate value. */ + if (value) { + fail_if (!(tree = mds_kbdc_tree_dup(value))); + } else { + fail_if (!(tree = mds_kbdc_tree_create(C(COMPILED_STRING)))); + fail_if (!(tree->compiled_string.string = string_dup(string))); + } + + /* Assign variable. */ + fail_if (variables_let(variable, tree)); + return 0; + FAIL_BEGIN; + mds_kbdc_tree_free(tree); + FAIL_END; } @@ -212,48 +209,47 @@ static int let(size_t variable, const char32_t* restrict string, const mds_kbdc_ * @param end The offset on the line where the function call ends * @return Zero on success, -1 on error, 1 if the call is invalid */ -static int check_set_3_get_2_call(mds_kbdc_tree_t* restrict tree, int is_set, const char32_t* variable_arg, - const char32_t* index_arg, size_t start, size_t end) +static int +check_set_3_get_2_call(mds_kbdc_tree_t *restrict tree, int is_set, const char32_t *variable_arg, + const char32_t *index_arg, size_t start, size_t end) { -#define F (is_set ? "set/3" : "get/2") -#define FUN_ERROR(...) \ - do \ - { \ - NEW_ERROR(__VA_ARGS__); \ - error->start = start; \ - error->end = end; \ - return 1; \ - } \ - while(0); - - mds_kbdc_tree_t* variable; - mds_kbdc_tree_t* element; - size_t index, arg_count; - - if ((variable_arg[0] <= 0) || (variable_arg[1] != -1)) - FUN_ERROR(tree, ERROR, "first argument in call to function ‘%s’ must be a variable index", F); - - if ((index_arg[0] < 0) || (index_arg[1] != -1)) - FUN_ERROR(tree, ERROR, "second argument in call to function ‘%s’ must be an element index", F); - - variable = variables_get((size_t)*variable_arg); - if (variable == NULL) - FUN_ERROR(tree, ERROR, "‘\\%zu’ is not declared", (size_t)*variable_arg); - if (variable->type != C(ARRAY)) - FUN_ERROR(tree, ERROR, "‘\\%zu’ is not an array", (size_t)*variable_arg); - - arg_count = index = (size_t)*index_arg; - element = variable->array.elements; - while (element && index--) - element = element->next; - - if (element == NULL) - FUN_ERROR(tree, ERROR, "‘\\%zu’ does not hold %zu %s", - (size_t)*variable_arg, arg_count + 1, arg_count ? "elements" : "element"); - - return 0; - fail: - return -1; +#define F (is_set ? "set/3" : "get/2") +#define FUN_ERROR(...)\ + do {\ + NEW_ERROR(__VA_ARGS__);\ + error->start = start;\ + error->end = end;\ + return 1;\ + } while(0); + + mds_kbdc_tree_t *variable; + mds_kbdc_tree_t *element; + size_t index, arg_count; + + if (variable_arg[0] <= 0 || variable_arg[1] != -1) + FUN_ERROR(tree, ERROR, "first argument in call to function ‘%s’ must be a variable index", F); + + if (index_arg[0] < 0 || index_arg[1] != -1) + FUN_ERROR(tree, ERROR, "second argument in call to function ‘%s’ must be an element index", F); + + variable = variables_get((size_t)*variable_arg); + if (!variable) + FUN_ERROR(tree, ERROR, "‘\\%zu’ is not declared", (size_t)*variable_arg); + if (variable->type != C(ARRAY)) + FUN_ERROR(tree, ERROR, "‘\\%zu’ is not an array", (size_t)*variable_arg); + + arg_count = index = (size_t)*index_arg; + element = variable->array.elements; + while (element && index--) + element = element->next; + + if (!element) + FUN_ERROR(tree, ERROR, "‘\\%zu’ does not hold %zu %s", + (size_t)*variable_arg, arg_count + 1, arg_count ? "elements" : "element"); + + return 0; +fail: + return -1; #undef FUN_ERROR #undef F } @@ -274,125 +270,118 @@ static int check_set_3_get_2_call(mds_kbdc_tree_t* restrict tree, int is_set, co * as containing an error * @return Zero on success, -1 on error */ -static int call_function(mds_kbdc_tree_t* restrict tree, const char* restrict name, - const char32_t** restrict arguments, size_t start, size_t end, - char32_t** restrict return_value) +static int +call_function(mds_kbdc_tree_t *restrict tree, const char *restrict name, const char32_t **restrict arguments, + size_t start, size_t end, char32_t **restrict return_value) { -#define FUN_ERROR(...) \ - do \ - { \ - NEW_ERROR(__VA_ARGS__); \ - error->start = start; \ - error->end = end; \ - tree->processed = PROCESS_LEVEL; \ - free(*return_value), *return_value = NULL; \ - goto done; \ - } \ - while(0); - - size_t i, arg_count = 0, empty_count = 0; - char32_t** old_return_value; - mds_kbdc_tree_function_t* function = NULL; - mds_kbdc_include_stack_t* function_include_stack = NULL; - mds_kbdc_include_stack_t* our_include_stack = NULL; - int r, is_set, builtin, saved_errno; - - /* Push call-stack. */ - mds_kbdc_call_stack_push(tree, start, end); - - /* Count the number of arguments we have. */ - while (arguments[arg_count]) - arg_count++; - - /* Push return-stack. */ - *return_value = NULL; - old_return_value = current_return_value; - current_return_value = return_value; - - /* Get function definition. */ - builtin = builtin_function_defined(name, arg_count); - if (builtin == 0) - callables_get(name, arg_count, (mds_kbdc_tree_t**)&function, &function_include_stack); - if ((builtin == 0) && (function == NULL)) - FUN_ERROR(tree, ERROR, "function ‘%s/%zu’ has not been defined yet", name, arg_count); - - - /* Call non-builtin function. */ - if (builtin == 0) - { - /* Push call stack and set parameters. */ - variables_stack_push(); - for (i = 0; i < arg_count; i++) - fail_if (let(i + 1, arguments[i], NULL, NULL, 0, 0)); - - /* Switch include-stack to the function's. */ - fail_if (our_include_stack = mds_kbdc_include_stack_save(), our_include_stack == NULL); - fail_if (mds_kbdc_include_stack_restore(function_include_stack)); - - /* Call the function. */ - fail_if (compile_subtree(function->inner)); - - /* Switch back the include-stack to ours. */ - fail_if (mds_kbdc_include_stack_restore(our_include_stack)); - mds_kbdc_include_stack_free(our_include_stack), our_include_stack = NULL; - - /* Pop call stack. */ - variables_stack_pop(); - - /* Check that the function returned a value. */ - if (*return_value == NULL) - FUN_ERROR(tree, ERROR, "function ‘%s/%zu’ did not return a value", name, arg_count); - - goto done; - } - - - /* Call builtin function. */ - - /* Check argument sanity. */ - is_set = (arg_count == 3) && !strcmp(name, "set"); - if (is_set || ((arg_count == 2) && !strcmp(name, "get"))) - { - fail_if (r = check_set_3_get_2_call(tree, is_set, arguments[0], arguments[1], start, end), r < 0); - if (r) - { - tree->processed = PROCESS_LEVEL; - free(*return_value), *return_value = NULL; - goto done; +#define FUN_ERROR(...)\ + do {\ + NEW_ERROR(__VA_ARGS__);\ + error->start = start;\ + error->end = end;\ + tree->processed = PROCESS_LEVEL;\ + free(*return_value), *return_value = NULL;\ + goto done;\ + } while(0); + + size_t i, arg_count = 0, empty_count = 0; + char32_t **old_return_value; + mds_kbdc_tree_function_t *function = NULL; + mds_kbdc_include_stack_t *function_include_stack = NULL; + mds_kbdc_include_stack_t *our_include_stack = NULL; + int r, is_set, builtin, saved_errno; + + /* Push call-stack. */ + mds_kbdc_call_stack_push(tree, start, end); + + /* Count the number of arguments we have. */ + while (arguments[arg_count]) + arg_count++; + + /* Push return-stack. */ + *return_value = NULL; + old_return_value = current_return_value; + current_return_value = return_value; + + /* Get function definition. */ + builtin = builtin_function_defined(name, arg_count); + if (!builtin) + callables_get(name, arg_count, (mds_kbdc_tree_t**)&function, &function_include_stack); + if (!builtin && !function) + FUN_ERROR(tree, ERROR, "function ‘%s/%zu’ has not been defined yet", name, arg_count); + + + /* Call non-builtin function. */ + if (!builtin) { + /* Push call stack and set parameters. */ + variables_stack_push(); + for (i = 0; i < arg_count; i++) + fail_if (let(i + 1, arguments[i], NULL, NULL, 0, 0)); + + /* Switch include-stack to the function's. */ + fail_if (our_include_stack = mds_kbdc_include_stack_save(), our_include_stack == NULL); + fail_if (mds_kbdc_include_stack_restore(function_include_stack)); + + /* Call the function. */ + fail_if (compile_subtree(function->inner)); + + /* Switch back the include-stack to ours. */ + fail_if (mds_kbdc_include_stack_restore(our_include_stack)); + mds_kbdc_include_stack_free(our_include_stack), our_include_stack = NULL; + + /* Pop call stack. */ + variables_stack_pop(); + + /* Check that the function returned a value. */ + if (!*return_value) + FUN_ERROR(tree, ERROR, "function ‘%s/%zu’ did not return a value", name, arg_count); + + goto done; } - } - else - { - for (i = 0; i < arg_count; i++) - empty_count += string_length(arguments[i]) == 0; - if (empty_count && (empty_count != arg_count)) - FUN_ERROR(tree, ERROR, - "built-in function ‘%s/%zu’ requires that either none of" - " the arguments are empty strings or that all of them are", - name, arg_count); - } - - /* Call the function. */ - *return_value = builtin_function_invoke(name, arg_count, arguments); - fail_if (*return_value == NULL); - have_side_effect |= is_set; - /* XXX ideally, we want to make sure it is in a scope that actually brings side-effects. */ - - - done: - /* Pop call-stack. */ - mds_kbdc_call_stack_pop(); - - /* Pop return-stack. */ - current_return_value = old_return_value; - return 0; - - FAIL_BEGIN; - mds_kbdc_call_stack_pop(); - mds_kbdc_include_stack_free(our_include_stack); - free(*return_value), *return_value = NULL; - current_return_value = old_return_value; - FAIL_END; + + + /* Call builtin function. */ + + /* Check argument sanity. */ + is_set = arg_count == 3 && !strcmp(name, "set"); + if (is_set || (arg_count == 2 && !strcmp(name, "get"))) { + fail_if (r = check_set_3_get_2_call(tree, is_set, arguments[0], arguments[1], start, end), r < 0); + if (r) { + tree->processed = PROCESS_LEVEL; + free(*return_value), *return_value = NULL; + goto done; + } + } else { + for (i = 0; i < arg_count; i++) + empty_count += !string_length(arguments[i]); + if (empty_count && empty_count != arg_count) + FUN_ERROR(tree, ERROR, + "built-in function ‘%s/%zu’ requires that either none of" + " the arguments are empty strings or that all of them are", + name, arg_count); + } + + /* Call the function. */ + *return_value = builtin_function_invoke(name, arg_count, arguments); + fail_if (!*return_value); + have_side_effect |= is_set; + /* XXX ideally, we want to make sure it is in a scope that actually brings side-effects. */ + + +done: + /* Pop call-stack. */ + mds_kbdc_call_stack_pop(); + + /* Pop return-stack. */ + current_return_value = old_return_value; + return 0; + + FAIL_BEGIN; + mds_kbdc_call_stack_pop(); + mds_kbdc_include_stack_free(our_include_stack); + free(*return_value), *return_value = NULL; + current_return_value = old_return_value; + FAIL_END; #undef FUN_ERROR } @@ -408,102 +397,99 @@ static int call_function(mds_kbdc_tree_t* restrict tree, const char* restrict na * @param end Output parameter for the end of the escape * @return The text the escape represents, `NULL` on error */ -static char32_t* parse_function_call(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff, - int* restrict escape, const char* restrict* restrict end) +static char32_t * +parse_function_call(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff, + int *restrict escape, const char *restrict *restrict end) { -#define R(LOWER, UPPER) (((LOWER) <= c) && (c <= (UPPER))) -#define GROW_ARGS \ - if (arguments_ptr == arguments_size) \ - fail_if (xxrealloc(old_arguments, arguments, arguments_size += 4, char32_t*)) - - const char* restrict bracket = raw + 1; - char32_t* rc = NULL; - const char32_t** restrict arguments_; - char32_t** restrict arguments = NULL; - char32_t** restrict old_arguments = NULL; - size_t arguments_ptr = 0, arguments_size = 0; - char* restrict name; - char c; - int r, saved_errno = 0; - - /* Find the opening bracket associated with the function call and validate the escape. */ - for (; c = *bracket, 1; bracket++) - if ((c == '_') || R('0', '9') || R('a', 'z') || R('A', 'Z')); - else if (c == '(') - break; - else - { - *end = bracket; - if (tree->processed != PROCESS_LEVEL) - NEW_ERROR(tree, ERROR, "invalid escape"); - goto error; - } - - /* Copy the name of the function. */ - name = alloca((size_t)(bracket - raw) * sizeof(char)); - memcpy(name, raw + 1, (size_t)(bracket - raw - 1) * sizeof(char)); - name[bracket - raw - 1] = 0; - - /* Get arguments. */ - for (*end = ++bracket;;) - { - while (**end == ' ') - (*end)++; - GROW_ARGS; - arguments[arguments_ptr] = NULL; - if (**end == ')') - { - *escape = 0; - (*end)++; - arguments_ptr++; - break; +#define R(LOWER, UPPER) ((LOWER) <= c && c <= (UPPER)) +#define GROW_ARGS\ + if (arguments_ptr == arguments_size)\ + fail_if (xxrealloc(old_arguments, arguments, arguments_size += 4, char32_t*)) + + const char *restrict bracket = raw + 1; + char32_t *rc = NULL; + const char32_t **restrict arguments_; + char32_t **restrict arguments = NULL; + char32_t **restrict old_arguments = NULL; + size_t arguments_ptr = 0, arguments_size = 0; + char *restrict name; + char c; + int r, saved_errno = 0; + + /* Find the opening bracket associated with the function call and validate the escape. */ + for (; c = *bracket, 1; bracket++) { + if (c == '_' || R('0', '9') || R('a', 'z') || R('A', 'Z')); + else if (c == '(') { + break; + } else { + *end = bracket; + if (tree->processed != PROCESS_LEVEL) + NEW_ERROR(tree, ERROR, "invalid escape"); + goto error; + } } - else if (**end == '\0') - { - if (tree->processed != PROCESS_LEVEL) - NEW_ERROR(tree, ERROR, "incomplete function call"); - goto error; + + /* Copy the name of the function. */ + name = alloca((size_t)(bracket - raw) * sizeof(char)); + memcpy(name, raw + 1, (size_t)(bracket - raw - 1) * sizeof(char)); + name[bracket - raw - 1] = 0; + + /* Get arguments. */ + for (*end = ++bracket;;) { + while (**end == ' ') + (*end)++; + GROW_ARGS; + arguments[arguments_ptr] = NULL; + if (**end == ')') { + *escape = 0; + (*end)++; + arguments_ptr++; + break; + } else if (!**end) { + if (tree->processed != PROCESS_LEVEL) + NEW_ERROR(tree, ERROR, "incomplete function call"); + goto error; + } + r = parse_function_argument(tree, *end, lineoff + (size_t)(*end - raw), end, arguments + arguments_ptr++); + fail_if (r < 0); } - r = parse_function_argument(tree, *end, lineoff + (size_t)(*end - raw), end, arguments + arguments_ptr++); - fail_if (r < 0); - } - - /* Call the function. */ - if (tree->processed == PROCESS_LEVEL) - goto stop; - arguments_ = alloca(arguments_ptr * sizeof(const char32_t*)); - memcpy(arguments_, arguments, arguments_ptr * sizeof(const char32_t*)); - fail_if (call_function(tree, name, arguments_, lineoff, lineoff + (size_t)(*end - raw), &rc)); - if (rc == NULL) - goto stop; - - goto done; - - error: - error->start = lineoff; - error->end = lineoff + (size_t)(*end - raw); - stop: - *escape = 0; - tree->processed = PROCESS_LEVEL; - fail_if (xmalloc(rc, 1, char32_t)); - *rc = -1; - goto done; - - fail: - saved_errno = errno; - free(rc); - if (old_arguments) - arguments = old_arguments; - while (arguments_ptr--) - free(arguments[arguments_ptr]); - free(arguments); - rc = NULL; - done: - while (arguments_ptr--) - free(arguments[arguments_ptr]); - free(arguments); - errno = saved_errno; - return rc; + + /* Call the function. */ + if (tree->processed == PROCESS_LEVEL) + goto stop; + arguments_ = alloca(arguments_ptr * sizeof(const char32_t*)); + memcpy(arguments_, arguments, arguments_ptr * sizeof(const char32_t*)); + fail_if (call_function(tree, name, arguments_, lineoff, lineoff + (size_t)(*end - raw), &rc)); + if (!rc) + goto stop; + + goto done; + +error: + error->start = lineoff; + error->end = lineoff + (size_t)(*end - raw); +stop: + *escape = 0; + tree->processed = PROCESS_LEVEL; + fail_if (xmalloc(rc, 1, char32_t)); + *rc = -1; + goto done; + +fail: + saved_errno = errno; + free(rc); + if (old_arguments) + arguments = old_arguments; + while (arguments_ptr--) + free(arguments[arguments_ptr]); + free(arguments); + rc = NULL; +done: + while (arguments_ptr--) + free(arguments[arguments_ptr]); + free(arguments); + errno = saved_errno; + return rc; #undef GROW_ARGS #undef R } @@ -520,41 +506,39 @@ static char32_t* parse_function_call(mds_kbdc_tree_t* restrict tree, const char* * -1 on error, 1 if an undefined function is used * @return The number of arguments the part of the literal contains */ -static size_t check_function_calls_in_literal_(const mds_kbdc_tree_t* restrict tree, - const char* restrict raw, size_t lineoff, - const char* restrict* restrict end, int* restrict rc) +static size_t +check_function_calls_in_literal_(const mds_kbdc_tree_t *restrict tree, const char *restrict raw, + size_t lineoff, const char *restrict *restrict end, int *restrict rc) { -#define R(LOWER, UPPER) (((LOWER) <= c) && (c <= (UPPER))) - const char* restrict raw_ = raw; - size_t count = 0; - int space = 1, quote = 0, escape = 0; - char c; - - while ((c = *raw++)) - { - if (space && !strchr(" )", c)) - space = 0, count++; - - if (escape) - { - escape = 0; - if (((c == '_') || R('a', 'z') || R('A', 'Z')) && (c != 'u')) - /* \u*() is disallowed because \u* is used for hexadecimal representation. */ - if (check_function_call(tree, raw - 2, lineoff + (size_t)(raw - 2 - raw_), &raw, rc), *rc < 0) - break; - } - else if (c == '\\') escape = 1; - else if (c == '"') quote ^= 1; - else if (!quote) - { - space = (c == ' '); - if (c == ')') - break; +#define R(LOWER, UPPER) ((LOWER) <= c && c <= (UPPER)) + const char *restrict raw_ = raw; + size_t count = 0; + int space = 1, quote = 0, escape = 0; + char c; + + while ((c = *raw++)) { + if (space && !strchr(" )", c)) + space = 0, count++; + + if (escape) { + escape = 0; + if ((c == '_' || R('a', 'z') || R('A', 'Z')) && c != 'u') + /* \u*() is disallowed because \u* is used for hexadecimal representation. */ + if (check_function_call(tree, raw - 2, lineoff + (size_t)(raw - 2 - raw_), &raw, rc), *rc < 0) + break; + } else if (c == '\\') { + escape = 1; + } else if (c == '"') { + quote ^= 1; + } else if (!quote) { + space = c == ' '; + if (c == ')') + break; + } } - } - - *end = raw; - return count; + + *end = raw; + return count; #undef R } @@ -569,45 +553,46 @@ static size_t check_function_calls_in_literal_(const mds_kbdc_tree_t* restrict t * @param rc Success status output parameter: zero on success, * -1 on error, 1 if an undefined function is used */ -static void check_function_call(const mds_kbdc_tree_t* restrict tree, const char* restrict raw, - size_t lineoff, const char* restrict* restrict end, int* restrict rc) +static void +check_function_call(const mds_kbdc_tree_t *restrict tree, const char *restrict raw, + size_t lineoff, const char *restrict *restrict end, int *restrict rc) { - mds_kbdc_tree_t* function = NULL; - mds_kbdc_include_stack_t* _function_include_stack; - char* restrict bracket = strchr(raw, '('); - char* restrict name; - size_t arg_count; - - /* Check that it is a function call by check that it has an opening bracket. */ - if (bracket == NULL) - { - *end = raw + strlen(raw); - return; - } - - /* Copy the name of the function. */ - name = alloca((size_t)(bracket - raw) * sizeof(char)); - memcpy(name, raw + 1, (size_t)(bracket - raw - 1) * sizeof(char)); - name[bracket++ - raw - 1] = 0; - - /* Get the number of arguments used, and check function calls there too. */ - arg_count = check_function_calls_in_literal_(tree, bracket, lineoff + (size_t)(bracket - raw), end, rc); - if (*rc < 0) return; - - /* Check that the function is defined. */ - if (builtin_function_defined(name, arg_count)) - return; - callables_get(name, arg_count, &function, &_function_include_stack); - if (function != NULL) - return; - *rc |= 1; - NEW_ERROR(tree, ERROR, "function ‘%s/%zu’ has not been defined yet", name, arg_count); - error->start = lineoff; - error->end = lineoff + (size_t)(*end - raw); - return; - - fail: - *rc |= -1; + mds_kbdc_tree_t *function = NULL; + mds_kbdc_include_stack_t *_function_include_stack; + char *restrict bracket = strchr(raw, '('); + char *restrict name; + size_t arg_count; + + /* Check that it is a function call by check that it has an opening bracket. */ + if (!bracket) { + *end = raw + strlen(raw); + return; + } + + /* Copy the name of the function. */ + name = alloca((size_t)(bracket - raw) * sizeof(char)); + memcpy(name, raw + 1, (size_t)(bracket - raw - 1) * sizeof(char)); + name[bracket++ - raw - 1] = 0; + + /* Get the number of arguments used, and check function calls there too. */ + arg_count = check_function_calls_in_literal_(tree, bracket, lineoff + (size_t)(bracket - raw), end, rc); + if (*rc < 0) + return; + + /* Check that the function is defined. */ + if (builtin_function_defined(name, arg_count)) + return; + callables_get(name, arg_count, &function, &_function_include_stack); + if (function) + return; + *rc |= 1; + NEW_ERROR(tree, ERROR, "function ‘%s/%zu’ has not been defined yet", name, arg_count); + error->start = lineoff; + error->end = lineoff + (size_t)(*end - raw); + return; + +fail: + *rc |= -1; } @@ -619,14 +604,15 @@ static void check_function_call(const mds_kbdc_tree_t* restrict tree, const char * @param lineoff The offset on the line where the literal beings * @return Zero on success, -1 on error, 1 if an undefined function is used */ -static int check_function_calls_in_literal(const mds_kbdc_tree_t* restrict tree, - const char* restrict raw, size_t lineoff) +static int +check_function_calls_in_literal(const mds_kbdc_tree_t *restrict tree, + const char *restrict raw, size_t lineoff) { - int rc = 0; - (void) check_function_calls_in_literal_(tree, raw, lineoff, &raw, &rc); - fail_if (rc < 0); - fail: - return rc; + int rc = 0; + (void) check_function_calls_in_literal_(tree, raw, lineoff, &raw, &rc); + fail_if (rc < 0); +fail: + return rc; } @@ -641,102 +627,98 @@ static int check_function_calls_in_literal(const mds_kbdc_tree_t* restrict tree, * @param end Output parameter for the end of the escape * @return The text the escape represents, `NULL` on error */ -static char32_t* parse_escape(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff, - int* restrict escape, const char* restrict* restrict end) +static char32_t * +parse_escape(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff, + int *restrict escape, const char *restrict *restrict end) { -#define R(LOWER, UPPER) (((LOWER) <= c) && (c <= (UPPER))) -#define CR(COND, LOWER, UPPER) ((*escape == (COND)) && R(LOWER, UPPER)) -#define VARIABLE (int)(raw - raw_) - (c == '.'), raw_ -#define RETURN_ERROR(...) \ - do \ - { \ - NEW_ERROR(__VA_ARGS__); \ - error->start = lineoff; \ - error->end = lineoff + (size_t)(raw - raw_); \ - tree->processed = PROCESS_LEVEL; \ - *escape = 0; \ - if (rc) \ - goto done; \ - fail_if (xmalloc(rc, 1, char32_t)); \ - *rc = -1; \ - goto done; \ - } \ - while (0) - - const char* restrict raw_ = raw++; - char c = *raw++; - uintmax_t numbuf = 0; - char32_t* rc = NULL; - mds_kbdc_tree_t* value; - int have = 0, saved_errno; - - - /* Get escape type. */ - if (c == '0') - /* Octal representation. */ - *escape = 8, have = 1; - else if (c == 'u') - /* Hexadecimal representation. */ - *escape = 16; - else if (R('1', '9')) - /* Variable dereference. */ - *escape = 10, have = 1, numbuf = (uintmax_t)(c - '0'); - else if ((c == '_') || R('a', 'z') || R('A', 'Z')) - /* Function call. */ - *escape = 100; - else - RETURN_ERROR(tree, ERROR, "invalid escape"); - - - /* Read escape. */ - if (*escape == 100) - /* Function call. */ - { - fail_if (rc = parse_function_call(tree, raw_, lineoff, escape, end), rc == NULL); - return rc; - } - /* Octal or hexadecimal representation, or variable dereference. */ - for (; (c = *raw); have = 1, raw++) - if (CR( 8, '0', '7')) numbuf = 8 * numbuf + (c & 15); - else if (CR(16, '0', '9')) numbuf = 16 * numbuf + (c & 15); - else if (CR(16, 'a', 'f')) numbuf = 16 * numbuf + (c & 15) + 9; - else if (CR(16, 'A', 'F')) numbuf = 16 * numbuf + (c & 15) + 9; - else if (CR(10, '0', '9')) numbuf = 10 * numbuf + (c & 15); - else break; - if (c == '.') - raw++; - if (have == 0) - RETURN_ERROR(tree, ERROR, "invalid escape"); - - - /* Evaluate escape. */ - if (*escape == 10) - { - /* Variable dereference. */ - if (value = variables_get((size_t)numbuf), value == NULL) - RETURN_ERROR(tree, ERROR, "variable ‘%.*s’ is not defined", VARIABLE); - if (value->type == C(ARRAY)) - RETURN_ERROR(tree, ERROR, "variable ‘%.*s’ is an array", VARIABLE); - if (value->type != C(COMPILED_STRING)) - NEW_ERROR(tree, INTERNAL_ERROR, "variable ‘%.*s’ is of impossible type", VARIABLE); - fail_if (rc = string_dup(value->compiled_string.string), rc == NULL); - } - else - { - /* Octal or hexadecimal representation. */ - fail_if (xmalloc(rc, 2, char32_t)); - rc[0] = (char32_t)numbuf, rc[1] = -1; - } - - - done: - *escape = 0; - *end = raw; - return rc; - fail: - saved_errno = errno; - free(rc); - return errno = saved_errno, NULL; +#define R(LOWER, UPPER) ((LOWER) <= c && c <= (UPPER)) +#define CR(COND, LOWER, UPPER) (*escape == (COND) && R(LOWER, UPPER)) +#define VARIABLE (int)(raw - raw_) - (c == '.'), raw_ +#define RETURN_ERROR(...)\ + do {\ + NEW_ERROR(__VA_ARGS__);\ + error->start = lineoff;\ + error->end = lineoff + (size_t)(raw - raw_);\ + tree->processed = PROCESS_LEVEL;\ + *escape = 0;\ + if (rc)\ + goto done;\ + fail_if (xmalloc(rc, 1, char32_t));\ + *rc = -1;\ + goto done;\ + } while (0) + + const char* restrict raw_ = raw++; + char c = *raw++; + uintmax_t numbuf = 0; + char32_t* rc = NULL; + mds_kbdc_tree_t* value; + int have = 0, saved_errno; + + + /* Get escape type. */ + if (c == '0') + /* Octal representation. */ + *escape = 8, have = 1; + else if (c == 'u') + /* Hexadecimal representation. */ + *escape = 16; + else if (R('1', '9')) + /* Variable dereference. */ + *escape = 10, have = 1, numbuf = (uintmax_t)(c - '0'); + else if (c == '_' || R('a', 'z') || R('A', 'Z')) + /* Function call. */ + *escape = 100; + else + RETURN_ERROR(tree, ERROR, "invalid escape"); + + + /* Read escape. */ + if (*escape == 100) { + /* Function call. */ + fail_if (rc = parse_function_call(tree, raw_, lineoff, escape, end), rc == NULL); + return rc; + } + /* Octal or hexadecimal representation, or variable dereference. */ + for (; (c = *raw); have = 1, raw++) { + if (CR( 8, '0', '7')) numbuf = 8 * numbuf + (c & 15); + else if (CR(16, '0', '9')) numbuf = 16 * numbuf + (c & 15); + else if (CR(16, 'a', 'f')) numbuf = 16 * numbuf + (c & 15) + 9; + else if (CR(16, 'A', 'F')) numbuf = 16 * numbuf + (c & 15) + 9; + else if (CR(10, '0', '9')) numbuf = 10 * numbuf + (c & 15); + else break; + } + if (c == '.') + raw++; + if (have == 0) + RETURN_ERROR(tree, ERROR, "invalid escape"); + + + /* Evaluate escape. */ + if (*escape == 10) { + /* Variable dereference. */ + if (!(value = variables_get((size_t)numbuf))) + RETURN_ERROR(tree, ERROR, "variable ‘%.*s’ is not defined", VARIABLE); + if (value->type == C(ARRAY)) + RETURN_ERROR(tree, ERROR, "variable ‘%.*s’ is an array", VARIABLE); + if (value->type != C(COMPILED_STRING)) + NEW_ERROR(tree, INTERNAL_ERROR, "variable ‘%.*s’ is of impossible type", VARIABLE); + fail_if (!(rc = string_dup(value->compiled_string.string))); + } else { + /* Octal or hexadecimal representation. */ + fail_if (xmalloc(rc, 2, char32_t)); + rc[0] = (char32_t)numbuf, rc[1] = -1; + } + + +done: + *escape = 0; + *end = raw; + return rc; +fail: + saved_errno = errno; + free(rc); + return errno = saved_errno, NULL; #undef RETURN_ERROR #undef VARIABLE #undef CR @@ -752,127 +734,114 @@ static char32_t* parse_escape(mds_kbdc_tree_t* restrict tree, const char* restri * @param lineoff The offset on the line where the string beings * @return The string as pure text, `NULL` on error */ -static char32_t* parse_quoted_string(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff) +static char32_t * +parse_quoted_string(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff) { -#define GROW_BUF \ - if (buf_ptr == buf_size) \ - fail_if (xxrealloc(old_buf, buf, buf_size += 16, char)) -#define COPY \ - n = string_length(subrc); \ - fail_if (xxrealloc(old_rc, rc, rc_ptr + n, char32_t)); \ - memcpy(rc + rc_ptr, subrc, n * sizeof(char32_t)), rc_ptr += n; \ - free(subrc), subrc = NULL -#define STORE \ - if (buf_ptr) \ - do \ - { \ - GROW_BUF; \ - buf[buf_ptr] = '\0', buf_ptr = 0; \ - fail_if (subrc = string_decode(buf), subrc == NULL); \ - COPY; \ - } \ - while (0) -#define CHAR_ERROR(...) \ - do \ - { \ - NEW_ERROR(__VA_ARGS__); \ - error->end = lineoff + (size_t)(raw - raw_); \ - error->start = error->end - 1; \ - } \ - while (0) - - const char* restrict raw_ = raw; - char32_t* restrict subrc = NULL; - char32_t* restrict rc = NULL; - char32_t* restrict old_rc = NULL; - char* restrict buf = NULL; - char* restrict old_buf = NULL; - size_t rc_ptr = 0, n; - size_t buf_ptr = 0, buf_size = 0; - size_t escoff = 0; - int quote = 0, escape = 0; - char c; - int saved_errno; - - /* Parse the string. */ - while ((c = *raw++)) - if (escape && quote && strchr("()[]{}<>\"\\,", c)) - { - /* Buffer UTF-8 text for convertion to UTF-32. */ - GROW_BUF; - buf[buf_ptr++] = c; - escape = 0; - } - else if (escape) - { - /* Parse escape. */ - raw -= 2, escoff = lineoff + (size_t)(raw - raw_); - subrc = parse_escape(tree, raw, escoff, &escape, &raw); - fail_if (subrc == NULL); - COPY; - } - else if (c == '"') - { - /* Close or open quote, of it got closed, convert the buffered UTF-8 text to UTF-32. */ - if (quote ^= 1) continue; - if ((quote == 1) && (raw != raw_ + 1)) - CHAR_ERROR(tree, WARNING, "strings should either be unquoted or unclosed in one large quoted"); - STORE; - } - else if (c == '\\') - { - /* Convert the buffered UTF-8 text to UTF-32, and start an escape. */ - STORE; - escape = 1; - } - else if ((quote == 0) && (tree->processed != PROCESS_LEVEL)) - { - /* Only escapes may be used without quotes, if the string contains quotes. */ - if (*raw_ == '"') - CHAR_ERROR(tree, ERROR, "only escapes may be outside quotes in quoted strings"); - else - CHAR_ERROR(tree, ERROR, "mixing numericals and escapes is not allowed"); - tree->processed = PROCESS_LEVEL; - } - else - { - /* Buffer UTF-8 text for convertion to UTF-32. */ - GROW_BUF; - buf[buf_ptr++] = c; - } - - /* Check that no escape is incomplete. */ - if (escape && (tree->processed != PROCESS_LEVEL)) - { - NEW_ERROR(tree, ERROR, "incomplete escape"); - error->start = escoff; - error->end = lineoff + strlen(raw_); - tree->processed = PROCESS_LEVEL; - } - - /* Check that the quote is complete. */ - if (quote && (tree->processed != PROCESS_LEVEL)) - { - NEW_ERROR(tree, ERROR, "quote is not closed"); - error->start = lineoff; - error->end = lineoff + strlen(raw_); - tree->processed = PROCESS_LEVEL; - } - - /* Shrink or grow to string to its minimal size, and -1-terminate it. */ - fail_if (xxrealloc(old_rc, rc, rc_ptr + 1, char32_t)); - rc[rc_ptr] = -1; - - free(buf); - return rc; - fail: - saved_errno = errno; - free(subrc); - free(old_rc); - free(old_buf); - free(rc); - free(buf); - return errno = saved_errno, NULL; +#define GROW_BUF\ + if (buf_ptr == buf_size)\ + fail_if (xxrealloc(old_buf, buf, buf_size += 16, char)) +#define COPY\ + n = string_length(subrc);\ + fail_if (xxrealloc(old_rc, rc, rc_ptr + n, char32_t));\ + memcpy(rc + rc_ptr, subrc, n * sizeof(char32_t)), rc_ptr += n;\ + free(subrc), subrc = NULL +#define STORE\ + do {\ + if (buf_ptr) {\ + GROW_BUF;\ + buf[buf_ptr] = '\0', buf_ptr = 0;\ + fail_if (!(subrc = string_decode(buf)));\ + COPY;\ + }\ + } while (0) +#define CHAR_ERROR(...)\ + do {\ + NEW_ERROR(__VA_ARGS__);\ + error->end = lineoff + (size_t)(raw - raw_);\ + error->start = error->end - 1;\ + } while (0) + + const char *restrict raw_ = raw; + char32_t *restrict subrc = NULL; + char32_t *restrict rc = NULL; + char32_t *restrict old_rc = NULL; + char *restrict buf = NULL; + char *restrict old_buf = NULL; + size_t rc_ptr = 0, n; + size_t buf_ptr = 0, buf_size = 0; + size_t escoff = 0; + int quote = 0, escape = 0; + char c; + int saved_errno; + + /* Parse the string. */ + while ((c = *raw++)) { + if (escape && quote && strchr("()[]{}<>\"\\,", c)) { + /* Buffer UTF-8 text for convertion to UTF-32. */ + GROW_BUF; + buf[buf_ptr++] = c; + escape = 0; + } else if (escape) { + /* Parse escape. */ + raw -= 2, escoff = lineoff + (size_t)(raw - raw_); + subrc = parse_escape(tree, raw, escoff, &escape, &raw); + fail_if (!subrc); + COPY; + } else if (c == '"') { + /* Close or open quote, of it got closed, convert the buffered UTF-8 text to UTF-32. */ + if ((quote ^= 1)) + continue; + if (quote == 1 && raw != raw_ + 1) + CHAR_ERROR(tree, WARNING, "strings should either be unquoted or unclosed in one large quoted"); + STORE; + } else if (c == '\\') { + /* Convert the buffered UTF-8 text to UTF-32, and start an escape. */ + STORE; + escape = 1; + } else if (!quote && tree->processed != PROCESS_LEVEL) { + /* Only escapes may be used without quotes, if the string contains quotes. */ + if (*raw_ == '"') + CHAR_ERROR(tree, ERROR, "only escapes may be outside quotes in quoted strings"); + else + CHAR_ERROR(tree, ERROR, "mixing numericals and escapes is not allowed"); + tree->processed = PROCESS_LEVEL; + } else { + /* Buffer UTF-8 text for convertion to UTF-32. */ + GROW_BUF; + buf[buf_ptr++] = c; + } + } + + /* Check that no escape is incomplete. */ + if (escape && tree->processed != PROCESS_LEVEL) { + NEW_ERROR(tree, ERROR, "incomplete escape"); + error->start = escoff; + error->end = lineoff + strlen(raw_); + tree->processed = PROCESS_LEVEL; + } + + /* Check that the quote is complete. */ + if (quote && tree->processed != PROCESS_LEVEL) { + NEW_ERROR(tree, ERROR, "quote is not closed"); + error->start = lineoff; + error->end = lineoff + strlen(raw_); + tree->processed = PROCESS_LEVEL; + } + + /* Shrink or grow to string to its minimal size, and -1-terminate it. */ + fail_if (xxrealloc(old_rc, rc, rc_ptr + 1, char32_t)); + rc[rc_ptr] = -1; + + free(buf); + return rc; +fail: + saved_errno = errno; + free(subrc); + free(old_rc); + free(old_buf); + free(rc); + free(buf); + return errno = saved_errno, NULL; #undef CHAR_ERROR #undef STORE #undef COPY @@ -888,37 +857,36 @@ static char32_t* parse_quoted_string(mds_kbdc_tree_t* restrict tree, const char* * @param lineoff The offset on the line where the string beings * @return The string as pure text, `NULL` on error */ -static char32_t* parse_unquoted_string(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff) +static char32_t * +parse_unquoted_string(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff) { -#define R(LOWER, UPPER) (((LOWER) <= c) && (c <= (UPPER))) -#define CHAR_ERROR(...) \ - do \ - { \ - NEW_ERROR(__VA_ARGS__); \ - error->end = lineoff + (size_t)(raw - raw_); \ - error->start = error->end - 1; \ - tree->processed = PROCESS_LEVEL; \ - goto done; \ - } \ - while (0) - - const char* restrict raw_ = raw; - char32_t* rc; - char32_t buf = 0; - char c; - - while ((c = *raw++)) - if (R('0', '9')) buf = 10 * buf + (c & 15); - else if (c == '\\') CHAR_ERROR(tree, ERROR, "mixing numericals and escapes is not allowed"); - else if (c == '"') CHAR_ERROR(tree, ERROR, "mixing numericals and quotes is not allowed"); - else CHAR_ERROR(tree, ERROR, "stray ‘%c’", c); /* XXX support multibyte */ - - done: - fail_if (xmalloc(rc, 2, char32_t)); - return rc[0] = buf, rc[1] = -1, rc; +#define R(LOWER, UPPER) ((LOWER) <= c && c <= (UPPER)) +#define CHAR_ERROR(...)\ + do {\ + NEW_ERROR(__VA_ARGS__);\ + error->end = lineoff + (size_t)(raw - raw_);\ + error->start = error->end - 1;\ + tree->processed = PROCESS_LEVEL;\ + goto done;\ + } while (0) + + const char *restrict raw_ = raw; + char32_t *rc, buf = 0; + char c; + + while ((c = *raw++)) { + if (R('0', '9')) buf = 10 * buf + (c & 15); + else if (c == '\\') CHAR_ERROR(tree, ERROR, "mixing numericals and escapes is not allowed"); + else if (c == '"') CHAR_ERROR(tree, ERROR, "mixing numericals and quotes is not allowed"); + else CHAR_ERROR(tree, ERROR, "stray ‘%c’", c); /* XXX support multibyte */ + } + +done: + fail_if (xmalloc(rc, 2, char32_t)); + return rc[0] = buf, rc[1] = -1, rc; - fail: - return NULL; +fail: + return NULL; #undef CHAR_ERROR #undef R } @@ -932,15 +900,16 @@ static char32_t* parse_unquoted_string(mds_kbdc_tree_t* restrict tree, const cha * @param lineoff The offset on the line where the string beings * @return The string as pure text, `NULL` on error */ -static char32_t* parse_string(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff) +static char32_t * +parse_string(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff) { - mds_kbdc_tree_t* old_last_value_statement = last_value_statement; - char32_t* rc = (strchr("\"\\", *raw) ? parse_quoted_string : parse_unquoted_string)(tree, raw, lineoff); - last_value_statement = old_last_value_statement; - fail_if (rc == NULL); - return rc; - fail: - return NULL; + mds_kbdc_tree_t *old_last_value_statement = last_value_statement; + char32_t *rc = (strchr("\"\\", *raw) ? parse_quoted_string : parse_unquoted_string)(tree, raw, lineoff); + last_value_statement = old_last_value_statement; + fail_if (!rc); + return rc; +fail: + return NULL; } @@ -952,120 +921,108 @@ static char32_t* parse_string(mds_kbdc_tree_t* restrict tree, const char* restri * @param lineoff The offset on the line where the string beings * @return The string as pure text, `NULL` on error */ -static char32_t* parse_keys(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff) +static char32_t * +parse_keys(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff) { -#define GROW_BUF \ - if (buf_ptr == buf_size) \ - fail_if (xxrealloc(old_buf, buf, buf_size += 16, char)) -#define COPY \ - n = string_length(subrc); \ - fail_if (xxrealloc(old_rc, rc, rc_ptr + n, char32_t)); \ - memcpy(rc + rc_ptr, subrc, n * sizeof(char32_t)), rc_ptr += n; \ - free(subrc), subrc = NULL -#define STORE \ - if (buf_ptr) \ - do \ - { \ - GROW_BUF; \ - buf[buf_ptr] = '\0', buf_ptr = 0; \ - fail_if (subrc = string_decode(buf), subrc == NULL); \ - COPY; \ - } \ - while (0) -#define SPECIAL(VAL) \ - STORE; \ - fail_if (xxrealloc(old_rc, rc, rc_ptr + 1, char32_t)); \ - rc[rc_ptr++] = -(VAL + 1) - - mds_kbdc_tree_t* old_last_value_statement = last_value_statement; - const char* restrict raw_ = raw++; - char32_t* restrict subrc = NULL; - char32_t* restrict rc = NULL; - char32_t* restrict old_rc = NULL; - char* restrict buf = NULL; - char* restrict old_buf = NULL; - size_t rc_ptr = 0, n; - size_t buf_ptr = 0, buf_size = 0; - size_t escoff = 0; - int escape = 0, quote = 0; - char c; - int saved_errno; - - /* Parse the string. */ - while (c = *raw++, c && *raw) - if (escape && strchr("()[]{}<>\"\\,", c)) - { - /* Buffer UTF-8 text for convertion to UTF-32. */ - GROW_BUF; - buf[buf_ptr++] = c; - escape = 0; - } - else if (escape) - { - /* Parse escape. */ - raw -= 2, escoff = lineoff + (size_t)(raw - raw_); - subrc = parse_escape(tree, raw, escoff, &escape, &raw); - fail_if (subrc == NULL); - COPY; - } - else if (c == '\\') - { - /* Convert the buffered UTF-8 text to UTF-32, and start an escape. */ +#define GROW_BUF\ + if (buf_ptr == buf_size)\ + fail_if (xxrealloc(old_buf, buf, buf_size += 16, char)) +#define COPY\ + n = string_length(subrc);\ + fail_if (xxrealloc(old_rc, rc, rc_ptr + n, char32_t));\ + memcpy(rc + rc_ptr, subrc, n * sizeof(char32_t)), rc_ptr += n;\ + free(subrc), subrc = NULL +#define STORE\ + do {\ + if (buf_ptr) {\ + GROW_BUF;\ + buf[buf_ptr] = '\0', buf_ptr = 0;\ + fail_if (!(subrc = string_decode(buf)));\ + COPY;\ + }\ + } while (0) +#define SPECIAL(VAL)\ + STORE;\ + fail_if (xxrealloc(old_rc, rc, rc_ptr + 1, char32_t));\ + rc[rc_ptr++] = -(VAL + 1) + + mds_kbdc_tree_t *old_last_value_statement = last_value_statement; + const char *restrict raw_ = raw++; + char32_t *restrict subrc = NULL; + char32_t *restrict rc = NULL; + char32_t *restrict old_rc = NULL; + char *restrict buf = NULL; + char *restrict old_buf = NULL; + size_t rc_ptr = 0, n; + size_t buf_ptr = 0, buf_size = 0; + size_t escoff = 0; + int escape = 0, quote = 0; + char c; + int saved_errno; + + /* Parse the string. */ + while (c = *raw++, c && *raw) { + if (escape && strchr("()[]{}<>\"\\,", c)) { + /* Buffer UTF-8 text for convertion to UTF-32. */ + GROW_BUF; + buf[buf_ptr++] = c; + escape = 0; + } else if (escape) { + /* Parse escape. */ + raw -= 2, escoff = lineoff + (size_t)(raw - raw_); + subrc = parse_escape(tree, raw, escoff, &escape, &raw); + fail_if (!subrc); + COPY; + } else if (c == '\\') { + /* Convert the buffered UTF-8 text to UTF-32, and start an escape. */ + STORE; + escape = 1; + } else if (c == ',' && !quote) { + /* Sequence in key-combination. */ + SPECIAL(1); + } else if (c == '"') { + /* String in key-combination. */ + quote ^= 1; + SPECIAL(2); + } else { + /* Buffer UTF-8 text for convertion to UTF-32. */ + GROW_BUF; + buf[buf_ptr++] = c; + } + } STORE; - escape = 1; - } - else if ((c == ',') && !quote) - { - /* Sequence in key-combination. */ - SPECIAL(1); - } - else if (c == '"') - { - /* String in key-combination. */ - quote ^= 1; - SPECIAL(2); - } - else - { - /* Buffer UTF-8 text for convertion to UTF-32. */ - GROW_BUF; - buf[buf_ptr++] = c; - } - STORE; - - /* Check that no escape is incomplete. */ - if (escape && (tree->processed != PROCESS_LEVEL)) - { - NEW_ERROR(tree, ERROR, "incomplete escape"); - error->start = lineoff + (size_t)(strrchr(raw_, '\\') - raw_); - error->end = lineoff + strlen(raw_); - tree->processed = PROCESS_LEVEL; - } - - /* Check that key-combination is complete. */ - if ((c != '>') && (tree->processed != PROCESS_LEVEL)) - { - NEW_ERROR(tree, ERROR, "key-combination is not closed"); - error->start = lineoff; - error->end = lineoff + strlen(raw_); - tree->processed = PROCESS_LEVEL; - } - - /* Shrink or grow to string to its minimal size, and -1-terminate it. */ - fail_if (xxrealloc(old_rc, rc, rc_ptr + 1, char32_t)); - rc[rc_ptr] = -1; - - free(buf); - return last_value_statement = old_last_value_statement, rc; - fail: - saved_errno = errno; - free(subrc); - free(old_rc); - free(old_buf); - free(rc); - free(buf); - errno = saved_errno; - return last_value_statement = old_last_value_statement, NULL; + + /* Check that no escape is incomplete. */ + if (escape && tree->processed != PROCESS_LEVEL) { + NEW_ERROR(tree, ERROR, "incomplete escape"); + error->start = lineoff + (size_t)(strrchr(raw_, '\\') - raw_); + error->end = lineoff + strlen(raw_); + tree->processed = PROCESS_LEVEL; + } + + /* Check that key-combination is complete. */ + if (c != '>' && tree->processed != PROCESS_LEVEL) { + NEW_ERROR(tree, ERROR, "key-combination is not closed"); + error->start = lineoff; + error->end = lineoff + strlen(raw_); + tree->processed = PROCESS_LEVEL; + } + + /* Shrink or grow to string to its minimal size, and -1-terminate it. */ + fail_if (xxrealloc(old_rc, rc, rc_ptr + 1, char32_t)); + rc[rc_ptr] = -1; + + free(buf); + return last_value_statement = old_last_value_statement, rc; +fail: + saved_errno = errno; + free(subrc); + free(old_rc); + free(old_buf); + free(rc); + free(buf); + errno = saved_errno; + return last_value_statement = old_last_value_statement, NULL; #undef SPECIAL #undef STORE #undef COPY @@ -1081,54 +1038,55 @@ static char32_t* parse_keys(mds_kbdc_tree_t* restrict tree, const char* restrict * @param lineoff The offset on the line where the variable string begins * @return The index of the variable, zero on error */ -static size_t parse_variable(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff) +static size_t +parse_variable(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff) { - size_t var, n; - const char* restrict raw_ = raw; - char* restrict dotless; - - /* The variable must begin with \. */ - if (*raw++ != '\\') goto bad; - /* Zero is not a valid varible, nor may there be leading zeroes or be empty. */ - if (*raw == '0') goto bad; - if (*raw == '.') goto bad; - if (*raw == '\0') goto bad; - for (; *raw; raw++) - /* Check that the variable consists only of digits. */ - if (('0' <= *raw) && (*raw <= '9')); - /* However, it may end with a dot. */ - else if ((raw[0] == '.') && (raw[1] == '\0')) - break; - else - goto bad; - - /* Parse the variable string and check that it did not overflow. */ - n = (size_t)(raw - raw_); - dotless = alloca((n + 1) * sizeof(char)); - memcpy(dotless, raw_, n * sizeof(char)), dotless[n] = '\0'; - var = atoz(dotless + 1); - if (strlen(dotless + 1) != (size_t)snprintf(NULL, 0, "%zu", var)) - fail_if ((errno = ERANGE)); - if (var == 0) - { - NEW_ERROR(tree, INTERNAL_ERROR, - "parsed a variable string to be 0, which should not be possible"); - error->start = lineoff; - error->end = lineoff + strlen(raw_); - tree->processed = PROCESS_LEVEL; - return 1; - } - return var; - fail: - return 0; - - bad: - /* Report an error but return a variable index if the variable-string is invalid. */ - NEW_ERROR(tree, ERROR, "not a variable"); - error->start = lineoff; - error->end = lineoff + strlen(raw_); - tree->processed = PROCESS_LEVEL; - return 1; + size_t var, n; + const char *restrict raw_ = raw; + char *restrict dotless; + + /* The variable must begin with \. */ + if (*raw++ != '\\') goto bad; + /* Zero is not a valid varible, nor may there be leading zeroes or be empty. */ + if (*raw == '0') goto bad; + if (*raw == '.') goto bad; + if (*raw == '\0') goto bad; + for (; *raw; raw++) { + /* Check that the variable consists only of digits. */ + if ('0' <= *raw && *raw <= '9') + /* However, it may end with a dot. */; + else if (raw[0] == '.' && raw[1] == '\0') + break; + else + goto bad; + } + + /* Parse the variable string and check that it did not overflow. */ + n = (size_t)(raw - raw_); + dotless = alloca((n + 1) * sizeof(char)); + memcpy(dotless, raw_, n * sizeof(char)), dotless[n] = '\0'; + var = atoz(dotless + 1); + if (strlen(dotless + 1) != (size_t)snprintf(NULL, 0, "%zu", var)) + fail_if ((errno = ERANGE)); + if (!var) { + NEW_ERROR(tree, INTERNAL_ERROR, + "parsed a variable string to be 0, which should not be possible"); + error->start = lineoff; + error->end = lineoff + strlen(raw_); + tree->processed = PROCESS_LEVEL; + return 1; + } + return var; +fail: + return 0; + +bad: + /* Report an error but return a variable index if the variable-string is invalid. */ + NEW_ERROR(tree, ERROR, "not a variable"); + error->start = lineoff; + error->end = lineoff + strlen(raw_); + tree->processed = PROCESS_LEVEL; + return 1; } @@ -1142,63 +1100,65 @@ static size_t parse_variable(mds_kbdc_tree_t* restrict tree, const char* restric * @param value Output parameter for the value to which the argument evaulates * @return Zero on success, -1 on error */ -static int parse_function_argument(mds_kbdc_tree_t* restrict tree, const char* restrict raw, size_t lineoff, - const char* restrict* restrict end, char32_t** restrict value) +static int +parse_function_argument(mds_kbdc_tree_t *restrict tree, const char *restrict raw, size_t lineoff, + const char *restrict *restrict end, char32_t **restrict value) { - size_t size = strlen(raw), ptr = 0, call_end = 0; - int escape = 0, quote = 0; - char* raw_argument = NULL; - int saved_errno; - - /* Find the span of the argument. */ - while (ptr < size) - { - char c = raw[ptr++]; - - /* Escapes may be longer than one character, - but only the first can affect the parsing. */ - if (escape) escape = 0; - /* Nested function and nested quotes can appear. */ - else if (ptr <= call_end) ; - /* Quotes end with the same symbols as they start with, - and quotes automatically escape brackets. */ - /* \ can either start a functon call or an escape. */ - else if (c == '\\') - { - /* It may not be an escape, but registering it - as an escape cannot harm us since we only - skip the first character, and a function call - cannot be that short. */ - escape = 1; - /* Nested quotes can appear at function calls. */ - call_end = get_end_of_call(raw, ptr, size); - } - /* " is the quote symbol. */ - else if (quote) quote = (c != '"'); - else if (c == '"') quote = 1; - /* End of argument? */ - else if (strchr(" )", c)) - { - ptr--; - break; + size_t size = strlen(raw), ptr = 0, call_end = 0; + int escape = 0, quote = 0, saved_errno; + char *raw_argument = NULL; + char c; + + /* Find the span of the argument. */ + while (ptr < size) { + c = raw[ptr++]; + + /* Escapes may be longer than one character, + but only the first can affect the parsing. */ + if (escape) + escape = 0; + /* Nested function and nested quotes can appear. */ + else if (ptr <= call_end) + ; + /* Quotes end with the same symbols as they start with, + and quotes automatically escape brackets. */ + /* \ can either start a functon call or an escape. */ + else if (c == '\\') { + /* It may not be an escape, but registering it + as an escape cannot harm us since we only + skip the first character, and a function call + cannot be that short. */ + escape = 1; + /* Nested quotes can appear at function calls. */ + call_end = get_end_of_call(raw, ptr, size); + } + /* " is the quote symbol. */ + else if (quote) + quote = (c != '"'); + else if (c == '"') + quote = 1; + /* End of argument? */ + else if (strchr(" )", c)) { + ptr--; + break; + } } - } - *end = raw + ptr; - - /* Copy the argument so that we have a NUL-terminates string. */ - fail_if (xmalloc(raw_argument, ptr + 1, char)); - memcpy(raw_argument, raw, ptr * sizeof(char)); - raw_argument[ptr] = '\0'; - - /* Evaluate argument. */ - *value = parse_string(tree, raw_argument, lineoff); - fail_if (*value == NULL); - - free(raw_argument); - return 0; - FAIL_BEGIN; - free(raw_argument); - FAIL_END; + *end = raw + ptr; + + /* Copy the argument so that we have a NUL-terminates string. */ + fail_if (xmalloc(raw_argument, ptr + 1, char)); + memcpy(raw_argument, raw, ptr * sizeof(char)); + raw_argument[ptr] = '\0'; + + /* Evaluate argument. */ + *value = parse_string(tree, raw_argument, lineoff); + fail_if (!*value); + + free(raw_argument); + return 0; + FAIL_BEGIN; + free(raw_argument); + FAIL_END; } @@ -1209,13 +1169,13 @@ static int parse_function_argument(mds_kbdc_tree_t* restrict tree, const char* r * @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) +static int +set_macro(mds_kbdc_tree_macro_t *restrict macro, mds_kbdc_include_stack_t *macro_include_stack) { - fail_if (callables_set(macro->name, 0, (mds_kbdc_tree_t*)macro, macro_include_stack)); - return 0; - fail: - return -1; + fail_if (callables_set(macro->name, 0, (mds_kbdc_tree_t *)macro, macro_include_stack)); + return 0; +fail: + return -1; } @@ -1226,10 +1186,11 @@ static int set_macro(mds_kbdc_tree_macro_t* restrict macro, * @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) +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) { - callables_get(macro_name, 0, (mds_kbdc_tree_t**)macro, macro_include_stack); + callables_get(macro_name, 0, (mds_kbdc_tree_t **)macro, macro_include_stack); } @@ -1246,29 +1207,29 @@ static void get_macro_lax(const char* restrict macro_name, mds_kbdc_tree_macro_t * @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) +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) { - char* code = result->source_code->lines[macro_call->loc_line]; - char* end = code + strlen(code) - 1; - - get_macro_lax(macro_call->name, macro, macro_include_stack); - if (*macro == NULL) - { - NEW_ERROR(macro_call, ERROR, "macro ‘%s’ has not been defined yet", macro_call->name); - while (*end == ' ') - end--; - error->end = (size_t)(++end - code); - macro_call->processed = PROCESS_LEVEL; - return 0; - } - if ((*macro)->processed == PROCESS_LEVEL) - *macro = NULL; - - return 0; - fail: - return -1; + char *code = result->source_code->lines[macro_call->loc_line]; + char *end = code + strlen(code) - 1; + + get_macro_lax(macro_call->name, macro, macro_include_stack); + if (!*macro) { + NEW_ERROR(macro_call, ERROR, "macro ‘%s’ has not been defined yet", macro_call->name); + while (*end == ' ') + end--; + error->end = (size_t)(++end - code); + macro_call->processed = PROCESS_LEVEL; + return 0; + } + if ((*macro)->processed == PROCESS_LEVEL) + *macro = NULL; + + return 0; +fail: + return -1; } @@ -1279,20 +1240,21 @@ static int get_macro(mds_kbdc_tree_macro_call_t* restrict macro_call, * @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) +static int +set_function(mds_kbdc_tree_function_t *restrict function, + mds_kbdc_include_stack_t *function_include_stack) { - char* suffixless = function->name; - char* suffix_start = strchr(suffixless, '/'); - size_t arg_count = atoz(suffix_start + 1); - int r; - - *suffix_start = '\0'; - r = callables_set(suffixless, arg_count, (mds_kbdc_tree_t*)function, function_include_stack); - fail_if (*suffix_start = '/', r); - return 0; - fail: - return -1; + char *suffixless = function->name; + char *suffix_start = strchr(suffixless, '/'); + size_t arg_count = atoz(suffix_start + 1); + int r; + + *suffix_start = '\0'; + r = callables_set(suffixless, arg_count, (mds_kbdc_tree_t *)function, function_include_stack); + fail_if (*suffix_start = '/', r); + return 0; +fail: + return -1; } @@ -1304,11 +1266,12 @@ static int set_function(mds_kbdc_tree_function_t* restrict function, * @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) +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) { - callables_get(function_name, arg_count, (mds_kbdc_tree_t**)function, function_include_stack); + callables_get(function_name, arg_count, (mds_kbdc_tree_t **)function, function_include_stack); } @@ -1318,21 +1281,23 @@ static void get_function_lax(const char* restrict function_name, size_t arg_coun * @param value The value the function should return * @return Zero on success, 1 if no function is currently being called */ -static int set_return_value(char32_t* restrict value) +static int +set_return_value(char32_t *restrict value) { - if (current_return_value == NULL) - return free(value), 1; - free(*current_return_value); - *current_return_value = value; - return 0; + if (!current_return_value) + return free(value), 1; + free(*current_return_value); + *current_return_value = value; + return 0; } -static int add_mapping(mds_kbdc_tree_map_t* restrict mapping, mds_kbdc_include_stack_t* restrict include_stack) +static int +add_mapping(mds_kbdc_tree_map_t *restrict mapping, mds_kbdc_include_stack_t *restrict include_stack) { - mds_kbdc_tree_free((mds_kbdc_tree_t*)mapping); - mds_kbdc_include_stack_free(include_stack); - return 0; /* TODO */ + mds_kbdc_tree_free((mds_kbdc_tree_t *)mapping); + mds_kbdc_include_stack_free(include_stack); + return 0; /* TODO */ } @@ -1346,23 +1311,24 @@ static int add_mapping(mds_kbdc_tree_map_t* restrict mapping, mds_kbdc_include_s * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_include(mds_kbdc_tree_include_t* restrict tree) +static int +compile_include(mds_kbdc_tree_include_t *restrict tree) { - void* data; - int r; - fail_if (mds_kbdc_include_stack_push(tree, &data)); - r = compile_subtree(tree->inner); - mds_kbdc_include_stack_pop(data); - - /* For simplicity we set `last_value_statement` on includes, - * so we are sure `last_value_statement` has the same - * include-stack as its overriding statement. */ - last_value_statement = NULL; - - fail_if (r); - return 0; - fail: - return -1; + void *data; + int r; + fail_if (mds_kbdc_include_stack_push(tree, &data)); + r = compile_subtree(tree->inner); + mds_kbdc_include_stack_pop(data); + + /* For simplicity we set `last_value_statement` on includes, + * so we are sure `last_value_statement` has the same + * include-stack as its overriding statement. */ + last_value_statement = NULL; + + fail_if (r); + return 0; +fail: + return -1; } @@ -1372,39 +1338,39 @@ static int compile_include(mds_kbdc_tree_include_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_language(mds_kbdc_tree_information_language_t* restrict tree) +static int +compile_language(mds_kbdc_tree_information_language_t *restrict tree) { - size_t lineoff; - char* restrict code = result->source_code->real_lines[tree->loc_line]; - char32_t* restrict data = NULL; - char** old = NULL; - int saved_errno; - - /* Make sure the language-list fits another entry. */ - if (result->languages_ptr == result->languages_size) - { - result->languages_size = result->languages_size ? (result->languages_size << 1) : 1; - fail_if (xxrealloc(old, result->languages, result->languages_size, char*)); - } - - /* Locate the first character in the language-string. */ - for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); - /* Evaluate function calls, variable dereferences and escapes in the language-string. */ - fail_if (data = parse_string((mds_kbdc_tree_t*)tree, tree->data, lineoff), data == NULL); - if (tree->processed == PROCESS_LEVEL) - return free(data), 0; - /* We want the string in UTF-8, not UTF-16. */ - fail_if (code = string_encode(data), code == NULL); - free(data); - - /* Add the language to the language-list. */ - result->languages[result->languages_ptr++] = code; - - return 0; - FAIL_BEGIN; - free(old); - free(data); - FAIL_END; + size_t lineoff; + char *restrict code = result->source_code->real_lines[tree->loc_line]; + char32_t *restrict data = NULL; + char **old = NULL; + int saved_errno; + + /* Make sure the language-list fits another entry. */ + if (result->languages_ptr == result->languages_size) { + result->languages_size = result->languages_size ? (result->languages_size << 1) : 1; + fail_if (xxrealloc(old, result->languages, result->languages_size, char*)); + } + + /* Locate the first character in the language-string. */ + for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); + /* Evaluate function calls, variable dereferences and escapes in the language-string. */ + fail_if (!(data = parse_string((mds_kbdc_tree_t*)tree, tree->data, lineoff))); + if (tree->processed == PROCESS_LEVEL) + return free(data), 0; + /* We want the string in UTF-8, not UTF-16. */ + fail_if (!(code = string_encode(data))); + free(data); + + /* Add the language to the language-list. */ + result->languages[result->languages_ptr++] = code; + + return 0; + FAIL_BEGIN; + free(old); + free(data); + FAIL_END; } @@ -1414,39 +1380,39 @@ static int compile_language(mds_kbdc_tree_information_language_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_country(mds_kbdc_tree_information_country_t* restrict tree) +static int +compile_country(mds_kbdc_tree_information_country_t *restrict tree) { - size_t lineoff; - char* restrict code = result->source_code->real_lines[tree->loc_line]; - char32_t* restrict data = NULL; - char** old = NULL; - int saved_errno; - - /* Make sure the country-list fits another entry. */ - if (result->countries_ptr == result->countries_size) - { - result->countries_size = result->countries_size ? (result->countries_size << 1) : 1; - fail_if (xxrealloc(old, result->countries, result->countries_size, char*)); - } - - /* Locate the first character in the country-string. */ - for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); - /* Evaluate function calls, variable dereferences and escapes in the country-string. */ - fail_if (data = parse_string((mds_kbdc_tree_t*)tree, tree->data, lineoff), data == NULL); - if (tree->processed == PROCESS_LEVEL) - return free(data), 0; - /* We want the string in UTF-8, not UTF-16. */ - fail_if (code = string_encode(data), code == NULL); - free(data); - - /* Add the country to the country-list. */ - result->countries[result->countries_ptr++] = code; - - return 0; - FAIL_BEGIN; - free(old); - free(data); - FAIL_END; + size_t lineoff; + char *restrict code = result->source_code->real_lines[tree->loc_line]; + char32_t *restrict data = NULL; + char **old = NULL; + int saved_errno; + + /* Make sure the country-list fits another entry. */ + if (result->countries_ptr == result->countries_size) { + result->countries_size = result->countries_size ? (result->countries_size << 1) : 1; + fail_if (xxrealloc(old, result->countries, result->countries_size, char *)); + } + + /* Locate the first character in the country-string. */ + for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); + /* Evaluate function calls, variable dereferences and escapes in the country-string. */ + fail_if (!(data = parse_string((mds_kbdc_tree_t*)tree, tree->data, lineoff))); + if (tree->processed == PROCESS_LEVEL) + return free(data), 0; + /* We want the string in UTF-8, not UTF-16. */ + fail_if (!(code = string_encode(data))); + free(data); + + /* Add the country to the country-list. */ + result->countries[result->countries_ptr++] = code; + + return 0; + FAIL_BEGIN; + free(old); + free(data); + FAIL_END; } @@ -1456,39 +1422,39 @@ static int compile_country(mds_kbdc_tree_information_country_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_variant(mds_kbdc_tree_information_variant_t* restrict tree) +static int +compile_variant(mds_kbdc_tree_information_variant_t *restrict tree) { - size_t lineoff; - char* restrict code = result->source_code->real_lines[tree->loc_line]; - char32_t* restrict data = NULL; - int saved_errno; - - /* Make sure the variant has not already been set. */ - if (result->variant) - { - if (multiple_variants == 0) - NEW_ERROR(tree, ERROR, "only one ‘variant’ is allowed"); - multiple_variants = 1; - return 0; - } - - /* Locate the first character in the variant-string. */ - for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); - /* Evaluate function calls, variable dereferences and escapes in the variant-string. */ - fail_if (data = parse_string((mds_kbdc_tree_t*)tree, tree->data, lineoff), data == NULL); - if (tree->processed == PROCESS_LEVEL) - return free(data), 0; - /* We want the string in UTF-8, not UTF-16. */ - fail_if (code = string_encode(data), code == NULL); - free(data); - - /* Store the variant. */ - result->variant = code; - - return 0; - FAIL_BEGIN; - free(data); - FAIL_END; + size_t lineoff; + char *restrict code = result->source_code->real_lines[tree->loc_line]; + char32_t *restrict data = NULL; + int saved_errno; + + /* Make sure the variant has not already been set. */ + if (result->variant) { + if (!multiple_variants) + NEW_ERROR(tree, ERROR, "only one ‘variant’ is allowed"); + multiple_variants = 1; + return 0; + } + + /* Locate the first character in the variant-string. */ + for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); + /* Evaluate function calls, variable dereferences and escapes in the variant-string. */ + fail_if (!(data = parse_string((mds_kbdc_tree_t*)tree, tree->data, lineoff))); + if (tree->processed == PROCESS_LEVEL) + return free(data), 0; + /* We want the string in UTF-8, not UTF-16. */ + fail_if (!(code = string_encode(data))); + free(data); + + /* Store the variant. */ + result->variant = code; + + return 0; + FAIL_BEGIN; + free(data); + FAIL_END; } @@ -1498,54 +1464,50 @@ static int compile_variant(mds_kbdc_tree_information_variant_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_have(mds_kbdc_tree_assumption_have_t* restrict tree) +static int +compile_have(mds_kbdc_tree_assumption_have_t *restrict tree) { - mds_kbdc_tree_t* node = tree->data; - char32_t* data = NULL; - char32_t** old = NULL; - size_t new_size = 0; - int saved_errno; - - /* Make sure we can fit all assumption in the assumption list (part 1/2). */ - new_size = (node->type == C(STRING)) ? result->assumed_strings_size : result->assumed_keys_size; - new_size = new_size ? (new_size << 1) : 1; - - if (node->type == C(STRING)) - { - /* Evaluate function calls, variable dereferences and escapes in the string. */ - fail_if (data = parse_string(node, node->string.string, node->loc_start), data == NULL); - if (node->processed == PROCESS_LEVEL) - return free(data), 0; - /* Make sure we can fit all strings in the assumption list (part 2/2). */ - if (result->assumed_strings_ptr == result->assumed_strings_size) - { - fail_if (xxrealloc(old, result->assumed_strings, new_size, char32_t*)); - result->assumed_strings_size = new_size; + mds_kbdc_tree_t *node = tree->data; + char32_t *data = NULL, **old = NULL; + size_t new_size = 0; + int saved_errno; + + /* Make sure we can fit all assumption in the assumption list (part 1/2). */ + new_size = (node->type == C(STRING)) ? result->assumed_strings_size : result->assumed_keys_size; + new_size = new_size ? (new_size << 1) : 1; + + if (node->type == C(STRING)) { + /* Evaluate function calls, variable dereferences and escapes in the string. */ + fail_if (!(data = parse_string(node, node->string.string, node->loc_start))); + if (node->processed == PROCESS_LEVEL) + return free(data), 0; + /* Make sure we can fit all strings in the assumption list (part 2/2). */ + if (result->assumed_strings_ptr == result->assumed_strings_size) + { + fail_if (xxrealloc(old, result->assumed_strings, new_size, char32_t*)); + result->assumed_strings_size = new_size; + } + /* Add the assumption to the list. */ + result->assumed_strings[result->assumed_strings_ptr++] = data; + } else { + /* Evaluate function calls, variable dereferences and escapes in the key-combination. */ + fail_if (!(data = parse_keys(node, node->keys.keys, node->loc_start))); + if (node->processed == PROCESS_LEVEL) + return free(data), 0; + /* Make sure we can fit all key-combinations in the assumption list (part 2/2). */ + if (result->assumed_keys_ptr == result->assumed_keys_size) { + fail_if (xxrealloc(old, result->assumed_keys, new_size, char32_t*)); + result->assumed_keys_size = new_size; + } + /* Add the assumption to the list. */ + result->assumed_keys[result->assumed_keys_ptr++] = data; } - /* Add the assumption to the list. */ - result->assumed_strings[result->assumed_strings_ptr++] = data; - } - else - { - /* Evaluate function calls, variable dereferences and escapes in the key-combination. */ - fail_if (data = parse_keys(node, node->keys.keys, node->loc_start), data == NULL); - if (node->processed == PROCESS_LEVEL) - return free(data), 0; - /* Make sure we can fit all key-combinations in the assumption list (part 2/2). */ - if (result->assumed_keys_ptr == result->assumed_keys_size) - { - fail_if (xxrealloc(old, result->assumed_keys, new_size, char32_t*)); - result->assumed_keys_size = new_size; - } - /* Add the assumption to the list. */ - result->assumed_keys[result->assumed_keys_ptr++] = data; - } - - return 0; - FAIL_BEGIN; - free(old); - free(data); - FAIL_END; + + return 0; + FAIL_BEGIN; + free(old); + free(data); + FAIL_END; } @@ -1555,47 +1517,46 @@ static int compile_have(mds_kbdc_tree_assumption_have_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_have_chars(mds_kbdc_tree_assumption_have_chars_t* restrict tree) +static int +compile_have_chars(mds_kbdc_tree_assumption_have_chars_t *restrict tree) { - size_t lineoff; - char* restrict code = result->source_code->real_lines[tree->loc_line]; - char32_t* restrict data = NULL; - char32_t** old = NULL; - char32_t* restrict character; - size_t n; - int saved_errno; - - /* Locate the first character in the list. */ - for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); - /* Evaluate function calls, variable dereferences - and escapes in the charcter list. */ - fail_if (data = parse_string((mds_kbdc_tree_t*)tree, tree->chars, lineoff), data == NULL); - if (tree->processed == PROCESS_LEVEL) - return free(data), 0; - - /* Make sure we can fit all characters in the assumption list. */ - for (n = 0; data[n] >= 0; n++); - if (result->assumed_strings_ptr + n > result->assumed_strings_size) - { - result->assumed_strings_size += n; - fail_if (xxrealloc(old, result->assumed_strings, result->assumed_strings_size, char32_t*)); - } - - /* Add all characters to the assumption list. */ - while (n--) - { - fail_if (xmalloc(character, 2, char32_t)); - character[0] = data[n]; - character[1] = -1; - result->assumed_strings[result->assumed_strings_ptr++] = character; - } - - free(data); - return 0; - FAIL_BEGIN; - free(data); - free(old); - FAIL_END; + size_t lineoff; + char *restrict code = result->source_code->real_lines[tree->loc_line]; + char32_t *restrict data = NULL; + char32_t **old = NULL; + char32_t *restrict character; + size_t n; + int saved_errno; + + /* Locate the first character in the list. */ + for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); + /* Evaluate function calls, variable dereferences + and escapes in the charcter list. */ + fail_if (!(data = parse_string((mds_kbdc_tree_t*)tree, tree->chars, lineoff))); + if (tree->processed == PROCESS_LEVEL) + return free(data), 0; + + /* Make sure we can fit all characters in the assumption list. */ + for (n = 0; data[n] >= 0; n++); + if (result->assumed_strings_ptr + n > result->assumed_strings_size) { + result->assumed_strings_size += n; + fail_if (xxrealloc(old, result->assumed_strings, result->assumed_strings_size, char32_t *)); + } + + /* Add all characters to the assumption list. */ + while (n--) { + fail_if (xmalloc(character, 2, char32_t)); + character[0] = data[n]; + character[1] = -1; + result->assumed_strings[result->assumed_strings_ptr++] = character; + } + + free(data); + return 0; + FAIL_BEGIN; + free(data); + free(old); + FAIL_END; } @@ -1605,88 +1566,85 @@ static int compile_have_chars(mds_kbdc_tree_assumption_have_chars_t* restrict tr * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_have_range(mds_kbdc_tree_assumption_have_range_t* restrict tree) +static int +compile_have_range(mds_kbdc_tree_assumption_have_range_t *restrict tree) { - size_t lineoff_first; - size_t lineoff_last; - char* restrict code = result->source_code->real_lines[tree->loc_line]; - char32_t* restrict first = NULL; - char32_t* restrict last = NULL; - char32_t** old = NULL; - char32_t* restrict character; - size_t n; - int saved_errno; - - - /* Locate the first characters of both bound strings. */ - for (lineoff_first = tree->loc_end; code[lineoff_first] == ' '; lineoff_first++); - for (lineoff_last = lineoff_first + strlen(tree->first); code[lineoff_last] == ' '; lineoff_last++); - - /* Duplicate bounds and evaluate function calls, - variable dereferences and escapes in the bounds. */ - fail_if (first = parse_string((mds_kbdc_tree_t*)tree, tree->first, lineoff_first), first == NULL); - fail_if (last = parse_string((mds_kbdc_tree_t*)tree, tree->last, lineoff_last), last == NULL); - - /* Did one of the bound not evaluate, then stop. */ - if (tree->processed == PROCESS_LEVEL) - goto done; - - - /* Check that the primary bound is single-character. */ - if ((first[0] == -1) || (first[1] != -1)) - { - NEW_ERROR(tree, ERROR, "iteration boundary must be a single character string"); - error->start = lineoff_first, lineoff_first = 0; - error->end = error->start + strlen(tree->first); - } - /* Check that the secondary bound is single-character. */ - if ((last[0] == -1) || (last[1] != -1)) - { - NEW_ERROR(tree, ERROR, "iteration boundary must be a single character string"); - error->start = lineoff_last, lineoff_last = 0; - error->end = error->start + strlen(tree->last); - } - - /* Was one of the bounds not single-character, then stop. */ - if ((lineoff_first == 0) || (lineoff_last == 0)) - goto done; - - - /* If the range is descending, swap the bounds so it is ascending. - (This cannot be done in for-loops as that may cause side-effects - to be created in the wrong order.) */ - if (*first > *last) - *first ^= *last, *last ^= *first, *first ^= *last; - - /* Make sure we can fit all characters in the assumption list. */ - n = (size_t)(*last - *first) + 1; - if (result->assumed_strings_ptr + n > result->assumed_strings_size) - { - result->assumed_strings_size += n; - fail_if (xxrealloc(old, result->assumed_strings, result->assumed_strings_size, char32_t*)); - } - - /* Add all characters to the assumption list. */ - for (;;) - { - fail_if (xmalloc(character, 2, char32_t)); - character[0] = *first; - character[1] = -1; - result->assumed_strings[result->assumed_strings_ptr++] = character; - /* Bounds are inclusive. */ - if ((*first)++ == *last) - break; - } - - done: - free(first); - free(last); - return 0; - FAIL_BEGIN; - free(first); - free(last); - free(old); - FAIL_END; + size_t lineoff_first; + size_t lineoff_last; + char *restrict code = result->source_code->real_lines[tree->loc_line]; + char32_t *restrict first = NULL; + char32_t *restrict last = NULL; + char32_t **old = NULL; + char32_t *restrict character; + size_t n; + int saved_errno; + + + /* Locate the first characters of both bound strings. */ + for (lineoff_first = tree->loc_end; code[lineoff_first] == ' '; lineoff_first++); + for (lineoff_last = lineoff_first + strlen(tree->first); code[lineoff_last] == ' '; lineoff_last++); + + /* Duplicate bounds and evaluate function calls, + variable dereferences and escapes in the bounds. */ + fail_if (!(first = parse_string((mds_kbdc_tree_t*)tree, tree->first, lineoff_first))); + fail_if (!(last = parse_string((mds_kbdc_tree_t*)tree, tree->last, lineoff_last))); + + /* Did one of the bound not evaluate, then stop. */ + if (tree->processed == PROCESS_LEVEL) + goto done; + + + /* Check that the primary bound is single-character. */ + if (first[0] == -1 || first[1] != -1) { + NEW_ERROR(tree, ERROR, "iteration boundary must be a single character string"); + error->start = lineoff_first, lineoff_first = 0; + error->end = error->start + strlen(tree->first); + } + /* Check that the secondary bound is single-character. */ + if (last[0] == -1 || last[1] != -1) { + NEW_ERROR(tree, ERROR, "iteration boundary must be a single character string"); + error->start = lineoff_last, lineoff_last = 0; + error->end = error->start + strlen(tree->last); + } + + /* Was one of the bounds not single-character, then stop. */ + if (!lineoff_first || !lineoff_last) + goto done; + + + /* If the range is descending, swap the bounds so it is ascending. + (This cannot be done in for-loops as that may cause side-effects + to be created in the wrong order.) */ + if (*first > *last) + *first ^= *last, *last ^= *first, *first ^= *last; + + /* Make sure we can fit all characters in the assumption list. */ + n = (size_t)(*last - *first) + 1; + if (result->assumed_strings_ptr + n > result->assumed_strings_size) { + result->assumed_strings_size += n; + fail_if (xxrealloc(old, result->assumed_strings, result->assumed_strings_size, char32_t *)); + } + + /* Add all characters to the assumption list. */ + for (;;) { + fail_if (xmalloc(character, 2, char32_t)); + character[0] = *first; + character[1] = -1; + result->assumed_strings[result->assumed_strings_ptr++] = character; + /* Bounds are inclusive. */ + if ((*first)++ == *last) + break; + } + +done: + free(first); + free(last); + return 0; + FAIL_BEGIN; + free(first); + free(last); + free(old); + FAIL_END; } @@ -1696,47 +1654,48 @@ 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(mds_kbdc_tree_t* restrict tree) +static int +check_marco_calls(mds_kbdc_tree_t *restrict tree) { -#define t(...) fail_if (rc |= r = (__VA_ARGS__), r < 0) - mds_kbdc_tree_macro_t* _macro; - mds_kbdc_include_stack_t* _macro_include_stack; - void* data; - int r, rc = 0; - again: - if (tree == NULL) - return rc; - - switch (tree->type) - { - case C(INCLUDE): - t (mds_kbdc_include_stack_push(&(tree->include), &data)); - t (r = check_marco_calls(tree->include.inner), mds_kbdc_include_stack_pop(data), r); - break; - - case C(FOR): - t (check_marco_calls(tree->for_.inner)); - break; - - case C(IF): - t (check_marco_calls(tree->if_.inner)); - t (check_marco_calls(tree->if_.otherwise)); - break; - - case C(MACRO_CALL): - t (get_macro(&(tree->macro_call), &_macro, &_macro_include_stack)); - break; - - default: - break; - } - - tree = tree->next; - goto again; - fail: - return -1; - (void) _macro; - (void) _macro_include_stack; +#define t(...) fail_if (rc |= r = (__VA_ARGS__), r < 0) + mds_kbdc_tree_macro_t *_macro; + mds_kbdc_include_stack_t *_macro_include_stack; + void *data; + int r, rc = 0; + +again: + if (!tree) + return rc; + + switch (tree->type) { + case C(INCLUDE): + t (mds_kbdc_include_stack_push(&(tree->include), &data)); + t (r = check_marco_calls(tree->include.inner), mds_kbdc_include_stack_pop(data), r); + break; + + case C(FOR): + t (check_marco_calls(tree->for_.inner)); + break; + + case C(IF): + t (check_marco_calls(tree->if_.inner)); + t (check_marco_calls(tree->if_.otherwise)); + break; + + case C(MACRO_CALL): + t (get_macro(&(tree->macro_call), &_macro, &_macro_include_stack)); + break; + + default: + break; + } + + tree = tree->next; + goto again; +fail: + return -1; + (void) _macro; + (void) _macro_include_stack; #undef t } @@ -1747,24 +1706,25 @@ static int check_marco_calls(mds_kbdc_tree_t* restrict tree) * @param tree The tree to evaluate * @return Zero on success, -1 on error, 1 if an undefined function is used */ -static int check_function_calls_in_for(const mds_kbdc_tree_for_t* restrict tree) +static int +check_function_calls_in_for(const mds_kbdc_tree_for_t *restrict tree) { -#define t(...) fail_if (rc |= r = check_function_calls_in_literal(__VA_ARGS__), r < 0) - size_t lineoff_first; - size_t lineoff_last; - char* restrict code = result->source_code->real_lines[tree->loc_line]; - int r, rc = 0; - - for (lineoff_first = tree->loc_end; code[lineoff_first] == ' '; lineoff_first++); - for (lineoff_last = lineoff_first + strlen(tree->first); code[lineoff_last] == ' '; lineoff_last++); - for (lineoff_last += strlen("to"); code[lineoff_last] == ' '; lineoff_last++); - - t ((const mds_kbdc_tree_t*)tree, tree->first, lineoff_first); - t ((const mds_kbdc_tree_t*)tree, tree->last, lineoff_last); - - return rc; - fail: - return -1; +#define t(...) fail_if (rc |= r = check_function_calls_in_literal(__VA_ARGS__), r < 0) + size_t lineoff_first; + size_t lineoff_last; + char *restrict code = result->source_code->real_lines[tree->loc_line]; + int r, rc = 0; + + for (lineoff_first = tree->loc_end; code[lineoff_first] == ' '; lineoff_first++); + for (lineoff_last = lineoff_first + strlen(tree->first); code[lineoff_last] == ' '; lineoff_last++); + for (lineoff_last += strlen("to"); code[lineoff_last] == ' '; lineoff_last++); + + t ((const mds_kbdc_tree_t *)tree, tree->first, lineoff_first); + t ((const mds_kbdc_tree_t *)tree, tree->last, lineoff_last); + + return rc; +fail: + return -1; #undef t } @@ -1775,17 +1735,18 @@ static int check_function_calls_in_for(const mds_kbdc_tree_for_t* restrict tree) * @param tree The tree to evaluate * @return Zero on success, -1 on error, 1 if an undefined function is used */ -static int check_function_calls_in_if(const mds_kbdc_tree_if_t* restrict tree) +static int +check_function_calls_in_if(const mds_kbdc_tree_if_t *restrict tree) { - size_t lineoff; - char* restrict code = result->source_code->real_lines[tree->loc_line]; - int r; - - for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); - r = check_function_calls_in_literal((const mds_kbdc_tree_t*)tree, tree->condition, lineoff); - fail_if (r < 0); - fail: - return r; + size_t lineoff; + char *restrict code = result->source_code->real_lines[tree->loc_line]; + int r; + + for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); + r = check_function_calls_in_literal((const mds_kbdc_tree_t *)tree, tree->condition, lineoff); + fail_if (r < 0); +fail: + return r; } @@ -1795,13 +1756,14 @@ static int check_function_calls_in_if(const mds_kbdc_tree_if_t* restrict tree) * @param tree The tree to evaluate * @return Zero on success, -1 on error, 1 if an undefined function is used */ -static int check_function_calls_in_keys(const mds_kbdc_tree_keys_t* restrict tree) +static int +check_function_calls_in_keys(const mds_kbdc_tree_keys_t *restrict tree) { - int r; - r = check_function_calls_in_literal((const mds_kbdc_tree_t*)tree, tree->keys, tree->loc_start); - fail_if (r < 0); - fail: - return r; + int r; + r = check_function_calls_in_literal((const mds_kbdc_tree_t *)tree, tree->keys, tree->loc_start); + fail_if (r < 0); +fail: + return r; } @@ -1811,13 +1773,14 @@ static int check_function_calls_in_keys(const mds_kbdc_tree_keys_t* restrict tre * @param tree The tree to evaluate * @return Zero on success, -1 on error, 1 if an undefined function is used */ -static int check_function_calls_in_string(const mds_kbdc_tree_string_t* restrict tree) +static int +check_function_calls_in_string(const mds_kbdc_tree_string_t *restrict tree) { - int r; - r = check_function_calls_in_literal((const mds_kbdc_tree_t*)tree, tree->string, tree->loc_start); - fail_if (r < 0); - fail: - return r; + int r; + r = check_function_calls_in_literal((const mds_kbdc_tree_t *)tree, tree->string, tree->loc_start); + fail_if (r < 0); +fail: + return r; } @@ -1827,46 +1790,47 @@ static int check_function_calls_in_string(const mds_kbdc_tree_string_t* restrict * @param tree The tree to evaluate * @return Zero on success, -1 on error, 1 if an undefined function is used */ -static int check_function_calls(const mds_kbdc_tree_t* restrict tree) +static int +check_function_calls(const mds_kbdc_tree_t *restrict tree) { -#define t(...) fail_if (rc |= r = (__VA_ARGS__), r < 0) - void* data; - int r, rc = 0; - again: - if (tree == NULL) - return rc; - - switch (tree->type) - { - case C(INCLUDE): - t (mds_kbdc_include_stack_push(&(tree->include), &data)); - t (r = check_function_calls(tree->include.inner), mds_kbdc_include_stack_pop(data), r); - break; - - case C(FOR): - t (check_function_calls_in_for(&(tree->for_))); - t (check_function_calls(tree->for_.inner)); - break; - - case C(IF): - t (check_function_calls_in_if(&(tree->if_))); - t (check_function_calls(tree->if_.inner)); - t (check_function_calls(tree->if_.otherwise)); - break; - - case C(LET): t (check_function_calls(tree->let.value)); break; - case C(ARRAY): t (check_function_calls(tree->array.elements)); break; - case C(KEYS): t (check_function_calls_in_keys(&(tree->keys))); break; - case C(STRING): t (check_function_calls_in_string(&(tree->string))); break; - case C(MAP): t (check_function_calls(tree->map.sequence)); break; - default: - break; - } - - tree = tree->next; - goto again; - fail: - return -1; +#define t(...) fail_if (rc |= r = (__VA_ARGS__), r < 0) + void *data; + int r, rc = 0; + +again: + if (!tree) + return rc; + + switch (tree->type) { + case C(INCLUDE): + t (mds_kbdc_include_stack_push(&(tree->include), &data)); + t (r = check_function_calls(tree->include.inner), mds_kbdc_include_stack_pop(data), r); + break; + + case C(FOR): + t (check_function_calls_in_for(&(tree->for_))); + t (check_function_calls(tree->for_.inner)); + break; + + case C(IF): + t (check_function_calls_in_if(&(tree->if_))); + t (check_function_calls(tree->if_.inner)); + t (check_function_calls(tree->if_.otherwise)); + break; + + case C(LET): t (check_function_calls(tree->let.value)); break; + case C(ARRAY): t (check_function_calls(tree->array.elements)); break; + case C(KEYS): t (check_function_calls_in_keys(&(tree->keys))); break; + case C(STRING): t (check_function_calls_in_string(&(tree->string))); break; + case C(MAP): t (check_function_calls(tree->map.sequence)); break; + default: + break; + } + + tree = tree->next; + goto again; +fail: + return -1; #undef t } @@ -1877,52 +1841,50 @@ static int check_function_calls(const mds_kbdc_tree_t* restrict tree) * @param tree The tree to inspect * @return Zero on sucess, -1 on error, 1 if the name-suffix in invalid */ -static int check_name_suffix(struct mds_kbdc_tree_callable* restrict tree) +static int +check_name_suffix(struct mds_kbdc_tree_callable *restrict tree) { - const char* restrict name = strchr(tree->name, '/'); - const char* restrict code = result->source_code->real_lines[tree->loc_line]; - - /* A "/" must exist in the name to tell us how many parameters there are. */ - if (name == NULL) - { - NEW_ERROR(tree, ERROR, "name-suffix is missing"); - goto name_error; - } - /* Do not let the suffix by just "/". */ - if (*++name == '\0') - { - NEW_ERROR(tree, ERROR, "empty name-suffix"); - goto name_error; - } - - /* We are all good if the suffix is simply "/0" */ - if (!strcmp(name, "0")) - return 0; - - /* The suffix may not have leading zeroes. */ - if (*name == '0') - { - NEW_ERROR(tree, ERROR, "leading zero in name-suffix"); - goto name_error; - } - /* The suffix must be a decimal, non-negative number. */ - for (; *name; name++) - if ((*name < '0') || ('9' < *name)) - { - NEW_ERROR(tree, ERROR, "name-suffix may only contain digits"); - goto name_error; - } - - return 0; - fail: - return -1; - name_error: - error->start = tree->loc_end; - while (code[error->start] == ' ') - error->start++; - error->end = error->start + strlen(tree->name); - tree->processed = PROCESS_LEVEL; - return 1; + const char *restrict name = strchr(tree->name, '/'); + const char *restrict code = result->source_code->real_lines[tree->loc_line]; + + /* A "/" must exist in the name to tell us how many parameters there are. */ + if (!name) { + NEW_ERROR(tree, ERROR, "name-suffix is missing"); + goto name_error; + } + /* Do not let the suffix by just "/". */ + if (!*++name) { + NEW_ERROR(tree, ERROR, "empty name-suffix"); + goto name_error; + } + + /* We are all good if the suffix is simply "/0" */ + if (!strcmp(name, "0")) + return 0; + + /* The suffix may not have leading zeroes. */ + if (*name == '0') { + NEW_ERROR(tree, ERROR, "leading zero in name-suffix"); + goto name_error; + } + /* The suffix must be a decimal, non-negative number. */ + for (; *name; name++) { + if (*name < '0' || '9' < *name) { + NEW_ERROR(tree, ERROR, "name-suffix may only contain digits"); + goto name_error; + } + } + + return 0; +fail: + return -1; +name_error: + error->start = tree->loc_end; + while (code[error->start] == ' ') + error->start++; + error->end = error->start + strlen(tree->name); + tree->processed = PROCESS_LEVEL; + return 1; } @@ -1932,67 +1894,67 @@ static int check_name_suffix(struct mds_kbdc_tree_callable* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_function(mds_kbdc_tree_function_t* 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 - 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; - char* suffix_start = NULL; - size_t arg_count; - int r, saved_errno; - - /* Check that the suffix if properly formatted. */ - t (check_name_suffix((struct mds_kbdc_tree_callable*)tree)); - if (r) return 0; - - /* Get the function's name without suffix, and parse the suffix. */ - suffixless = tree->name; - suffix_start = strchr(suffixless, '/'); - *suffix_start++ = '\0'; - arg_count = atoz(suffix_start--); - - /* Check that the function is not already defined as a builtin function. */ - if (builtin_function_defined(suffixless, arg_count)) - { - NEW_ERROR(tree, ERROR, "function ‘%s/%zu’ is already defined as a builtin function", - tree->name, arg_count); - *suffix_start = '/'; - return 0; - } - /* 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. */ - 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) - { - *suffix_start = '/'; - NEW_ERROR(tree, ERROR, "function ‘%s’ is already defined", tree->name); - fail_if (mds_kbdc_include_stack_restore(function_include_stack)); - NEW_ERROR(function, NOTE, "previously defined here"); - fail_if (mds_kbdc_include_stack_restore(our_include_stack)); - mds_kbdc_include_stack_free(our_include_stack); - return 0; - } - - /* Check the the function does not call macros or functions - * before they are defined, otherwise they may get defined - * between the definition of the function and calls to it. */ - t (check_marco_calls(tree->inner)); - t (check_function_calls(tree->inner)); - - /* List the function as defined. */ - *suffix_start = '/', suffix_start = NULL; - t (set_function(tree, our_include_stack)); - - return 0; - FAIL_BEGIN; - if (suffix_start) - *suffix_start = '/'; - mds_kbdc_include_stack_free(our_include_stack); - FAIL_END; +#define t(expr) do { fail_if (r = (expr), r < 0); if (r) tree->processed = PROCESS_LEVEL; } while (0) + 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; + char *suffix_start = NULL; + size_t arg_count; + int r, saved_errno; + + /* Check that the suffix if properly formatted. */ + t (check_name_suffix((struct mds_kbdc_tree_callable*)tree)); + if (r) + return 0; + + /* Get the function's name without suffix, and parse the suffix. */ + suffixless = tree->name; + suffix_start = strchr(suffixless, '/'); + *suffix_start++ = '\0'; + arg_count = atoz(suffix_start--); + + /* Check that the function is not already defined as a builtin function. */ + if (builtin_function_defined(suffixless, arg_count)) { + NEW_ERROR(tree, ERROR, "function ‘%s/%zu’ is already defined as a builtin function", + tree->name, arg_count); + *suffix_start = '/'; + return 0; + } + /* 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. */ + get_function_lax(suffixless, arg_count, &function, &function_include_stack); + fail_if (!(our_include_stack = mds_kbdc_include_stack_save(), our_include_stack)); + if (function) { + *suffix_start = '/'; + NEW_ERROR(tree, ERROR, "function ‘%s’ is already defined", tree->name); + fail_if (mds_kbdc_include_stack_restore(function_include_stack)); + NEW_ERROR(function, NOTE, "previously defined here"); + fail_if (mds_kbdc_include_stack_restore(our_include_stack)); + mds_kbdc_include_stack_free(our_include_stack); + return 0; + } + + /* Check the the function does not call macros or functions + * before they are defined, otherwise they may get defined + * between the definition of the function and calls to it. */ + t (check_marco_calls(tree->inner)); + t (check_function_calls(tree->inner)); + + /* List the function as defined. */ + *suffix_start = '/', suffix_start = NULL; + t (set_function(tree, our_include_stack)); + + return 0; + FAIL_BEGIN; + if (suffix_start) + *suffix_start = '/'; + mds_kbdc_include_stack_free(our_include_stack); + FAIL_END; #undef t } @@ -2003,46 +1965,47 @@ static int compile_function(mds_kbdc_tree_function_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_macro(mds_kbdc_tree_macro_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 - 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; - - /* Check that the suffix if properly formatted. */ - t (check_name_suffix((struct mds_kbdc_tree_callable*)tree)); - if (r) return 0; - - /* Check that the macro is not already defined, - 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); - get_macro_lax(tree->name, ¯o, ¯o_include_stack); - if (macro) - { - NEW_ERROR(tree, ERROR, "macro ‘%s’ is already defined", tree->name); - fail_if (mds_kbdc_include_stack_restore(macro_include_stack)); - NEW_ERROR(macro, NOTE, "previously defined here"); - fail_if (mds_kbdc_include_stack_restore(our_include_stack)); - mds_kbdc_include_stack_free(our_include_stack); - return 0; - } - - /* Check the the macro does not call macros or functions - * before they are defined, otherwise they may get defined - * between the definition of the macro and calls to it. */ - t (check_marco_calls(tree->inner)); - t (check_function_calls(tree->inner)); - - /* List the macro as defined. */ - t (set_macro(tree, our_include_stack)); - - return 0; - FAIL_BEGIN; - mds_kbdc_include_stack_free(our_include_stack); - FAIL_END; +#define t(expr) do { fail_if (r = (expr), r < 0); if (r) tree->processed = PROCESS_LEVEL; } while (0) + 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; + + /* Check that the suffix if properly formatted. */ + t (check_name_suffix((struct mds_kbdc_tree_callable*)tree)); + if (r) + return 0; + + /* Check that the macro is not already defined, + 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())); + get_macro_lax(tree->name, ¯o, ¯o_include_stack); + if (macro) { + NEW_ERROR(tree, ERROR, "macro ‘%s’ is already defined", tree->name); + fail_if (mds_kbdc_include_stack_restore(macro_include_stack)); + NEW_ERROR(macro, NOTE, "previously defined here"); + fail_if (mds_kbdc_include_stack_restore(our_include_stack)); + mds_kbdc_include_stack_free(our_include_stack); + return 0; + } + + /* Check the the macro does not call macros or functions + * before they are defined, otherwise they may get defined + * between the definition of the macro and calls to it. */ + t (check_marco_calls(tree->inner)); + t (check_function_calls(tree->inner)); + + /* List the macro as defined. */ + t (set_macro(tree, our_include_stack)); + + return 0; + FAIL_BEGIN; + mds_kbdc_include_stack_free(our_include_stack); + FAIL_END; #undef t } @@ -2053,94 +2016,92 @@ static int compile_macro(mds_kbdc_tree_macro_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_for(mds_kbdc_tree_for_t* restrict tree) +static int +compile_for(mds_kbdc_tree_for_t *restrict tree) { - size_t lineoff_first; - size_t lineoff_last; - size_t lineoff_var; - char* restrict code = result->source_code->real_lines[tree->loc_line]; - char32_t* restrict first = NULL; - char32_t* restrict last = NULL; - char32_t diff; - char32_t character[2]; - size_t variable; - int possible_shadow = 1, saved_errno; - - - last_value_statement = NULL; - - - /* Locate the first character of the primary bound's string. */ - for (lineoff_first = tree->loc_end; code[lineoff_first] == ' '; lineoff_first++); - /* Locate the first character of the secondary bound's string. */ - for (lineoff_last = lineoff_first + strlen(tree->first); code[lineoff_last] == ' '; lineoff_last++); - for (lineoff_last += strlen("to"); code[lineoff_last] == ' '; lineoff_last++); - /* Locate the first character of the select variable. */ - for (lineoff_var = lineoff_last + strlen(tree->last); code[lineoff_var] == ' '; lineoff_var++); - for (lineoff_var += strlen("as"); code[lineoff_var] == ' '; lineoff_var++); - - /* Duplicate bounds and evaluate function calls, - variable dereferences and escapes in the bounds. */ - fail_if (first = parse_string((mds_kbdc_tree_t*)tree, tree->first, lineoff_first), first == NULL); - fail_if (last = parse_string((mds_kbdc_tree_t*)tree, tree->last, lineoff_last), last == NULL); - /* Get the index of the selected variable. */ - fail_if (variable = parse_variable((mds_kbdc_tree_t*)tree, tree->variable, lineoff_var), variable == 0); - - /* Did one of the bound not evaluate, then stop. */ - if (tree->processed == PROCESS_LEVEL) - goto done; - - - /* Check that the primary bound is single-character. */ - if ((first[0] == -1) || (first[1] != -1)) - { - NEW_ERROR(tree, ERROR, "iteration boundary must be a single character string"); - error->start = lineoff_first, lineoff_first = 0; - error->end = error->start + strlen(tree->first); - } - /* Check that the secondary bound is single-character. */ - if ((last[0] == -1) || (last[1] != -1)) - { - NEW_ERROR(tree, ERROR, "iteration boundary must be a single character string"); - error->start = lineoff_last, lineoff_last = 0; - error->end = error->start + strlen(tree->last); - } - - /* Was one of the bounds not single-character, then stop. */ - if ((lineoff_first == 0) || (lineoff_last == 0)) - goto done; - - - /* Iterate over the loop for as long as a `return` or `break` has not - been encountered (without being caught elsewhere). */ - character[1] = -1; - for (diff = (*first > *last) ? -1 : +1; break_level < 2; *first += diff) - { - break_level = 0; - character[0] = *first; - fail_if (let(variable, character, NULL, (mds_kbdc_tree_t*)tree, lineoff_var, possible_shadow)); - possible_shadow = 0; - fail_if (compile_subtree(tree->inner)); - /* Bounds are inclusive. */ - if (*first == *last) - break; - } - fail_if (variables_was_used_in_for(variable)); - - /* Catch `break` and `continue`, they may not propagate further. */ - if (break_level < 3) - break_level = 0; - - - done: - last_value_statement = NULL; - free(first); - free(last); - return 0; - FAIL_BEGIN; - free(first); - free(last); - FAIL_END; + size_t lineoff_first; + size_t lineoff_last; + size_t lineoff_var; + char *restrict code = result->source_code->real_lines[tree->loc_line]; + char32_t *restrict first = NULL; + char32_t *restrict last = NULL; + char32_t diff; + char32_t character[2]; + size_t variable; + int possible_shadow = 1, saved_errno; + + + last_value_statement = NULL; + + + /* Locate the first character of the primary bound's string. */ + for (lineoff_first = tree->loc_end; code[lineoff_first] == ' '; lineoff_first++); + /* Locate the first character of the secondary bound's string. */ + for (lineoff_last = lineoff_first + strlen(tree->first); code[lineoff_last] == ' '; lineoff_last++); + for (lineoff_last += strlen("to"); code[lineoff_last] == ' '; lineoff_last++); + /* Locate the first character of the select variable. */ + for (lineoff_var = lineoff_last + strlen(tree->last); code[lineoff_var] == ' '; lineoff_var++); + for (lineoff_var += strlen("as"); code[lineoff_var] == ' '; lineoff_var++); + + /* Duplicate bounds and evaluate function calls, + variable dereferences and escapes in the bounds. */ + fail_if (!(first = parse_string((mds_kbdc_tree_t*)tree, tree->first, lineoff_first))); + fail_if (!(last = parse_string((mds_kbdc_tree_t*)tree, tree->last, lineoff_last))); + /* Get the index of the selected variable. */ + fail_if (variable = parse_variable((mds_kbdc_tree_t*)tree, tree->variable, lineoff_var), variable == 0); + + /* Did one of the bound not evaluate, then stop. */ + if (tree->processed == PROCESS_LEVEL) + goto done; + + + /* Check that the primary bound is single-character. */ + if (first[0] == -1 || first[1] != -1) { + NEW_ERROR(tree, ERROR, "iteration boundary must be a single character string"); + error->start = lineoff_first, lineoff_first = 0; + error->end = error->start + strlen(tree->first); + } + /* Check that the secondary bound is single-character. */ + if (last[0] == -1 || last[1] != -1) { + NEW_ERROR(tree, ERROR, "iteration boundary must be a single character string"); + error->start = lineoff_last, lineoff_last = 0; + error->end = error->start + strlen(tree->last); + } + + /* Was one of the bounds not single-character, then stop. */ + if (!lineoff_first || !lineoff_last) + goto done; + + + /* Iterate over the loop for as long as a `return` or `break` has not + been encountered (without being caught elsewhere). */ + character[1] = -1; + for (diff = (*first > *last) ? -1 : +1; break_level < 2; *first += diff) { + break_level = 0; + character[0] = *first; + fail_if (let(variable, character, NULL, (mds_kbdc_tree_t*)tree, lineoff_var, possible_shadow)); + possible_shadow = 0; + fail_if (compile_subtree(tree->inner)); + /* Bounds are inclusive. */ + if (*first == *last) + break; + } + fail_if (variables_was_used_in_for(variable)); + + /* Catch `break` and `continue`, they may not propagate further. */ + if (break_level < 3) + break_level = 0; + + +done: + last_value_statement = NULL; + free(first); + free(last); + return 0; + FAIL_BEGIN; + free(first); + free(last); + FAIL_END; } @@ -2150,36 +2111,37 @@ static int compile_for(mds_kbdc_tree_for_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_if(mds_kbdc_tree_if_t* restrict tree) +static int +compile_if(mds_kbdc_tree_if_t *restrict tree) { - size_t lineoff; - char* restrict code = result->source_code->real_lines[tree->loc_line]; - char32_t* restrict data = NULL; - int ok, saved_errno; - size_t i; - - last_value_statement = NULL; - - /* Locate the first character in the condition. */ - for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); - /* Evaluate function calls, variable dereferences and escapes in the condition. */ - fail_if (data = parse_string((mds_kbdc_tree_t*)tree, tree->condition, lineoff), data == NULL); - if (tree->processed == PROCESS_LEVEL) - return free(data), 0; - - /* Evaluate whether the evaluted value is true. */ - for (ok = 1, i = 0; data[i] >= 0; i++) - ok &= !!(data[i]); - free(data), data = NULL;; - - /* Compile the appropriate clause. */ - ok = compile_subtree(ok ? tree->inner : tree->otherwise); - last_value_statement = NULL; - fail_if (ok < 0); - return 0; - FAIL_BEGIN; - free(data); - FAIL_END; + size_t lineoff; + char *restrict code = result->source_code->real_lines[tree->loc_line]; + char32_t *restrict data = NULL; + int ok, saved_errno; + size_t i; + + last_value_statement = NULL; + + /* Locate the first character in the condition. */ + for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); + /* Evaluate function calls, variable dereferences and escapes in the condition. */ + fail_if (!(data = parse_string((mds_kbdc_tree_t*)tree, tree->condition, lineoff))); + if (tree->processed == PROCESS_LEVEL) + return free(data), 0; + + /* Evaluate whether the evaluted value is true. */ + for (ok = 1, i = 0; data[i] >= 0; i++) + ok &= !!(data[i]); + free(data), data = NULL;; + + /* Compile the appropriate clause. */ + ok = compile_subtree(ok ? tree->inner : tree->otherwise); + last_value_statement = NULL; + fail_if (ok < 0); + return 0; + FAIL_BEGIN; + free(data); + FAIL_END; } @@ -2189,35 +2151,36 @@ static int compile_if(mds_kbdc_tree_if_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_let(mds_kbdc_tree_let_t* restrict tree) +static int +compile_let(mds_kbdc_tree_let_t *restrict tree) { - size_t lineoff; - char* restrict code = result->source_code->real_lines[tree->loc_line]; - mds_kbdc_tree_t* value = NULL; - size_t variable; - int saved_errno; - - /* Get the index of the selected variable. */ - for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); - fail_if (variable = parse_variable((mds_kbdc_tree_t*)tree, tree->variable, lineoff), variable == 0); - if (tree->processed == PROCESS_LEVEL) - return 0; - - /* Duplicate arguments and evaluate function calls, - variable dereferences and escapes in the value. */ - fail_if (value = mds_kbdc_tree_dup(tree->value), value == NULL); - fail_if (compile_subtree(value)); - if ((tree->processed = value->processed) == PROCESS_LEVEL) - return mds_kbdc_tree_free(value), 0; - - /* Set the value of the variable. */ - fail_if (let(variable, NULL, value, NULL, 0, 0)); - - mds_kbdc_tree_free(value); - return 0; - FAIL_BEGIN; - free(value); - FAIL_END; + size_t lineoff; + char *restrict code = result->source_code->real_lines[tree->loc_line]; + mds_kbdc_tree_t* value = NULL; + size_t variable; + int saved_errno; + + /* Get the index of the selected variable. */ + for (lineoff = tree->loc_end; code[lineoff] == ' '; lineoff++); + fail_if (!(variable = parse_variable((mds_kbdc_tree_t *)tree, tree->variable, lineoff))); + if (tree->processed == PROCESS_LEVEL) + return 0; + + /* Duplicate arguments and evaluate function calls, + variable dereferences and escapes in the value. */ + fail_if (!(value = mds_kbdc_tree_dup(tree->value))); + fail_if (compile_subtree(value)); + if ((tree->processed = value->processed) == PROCESS_LEVEL) + return mds_kbdc_tree_free(value), 0; + + /* Set the value of the variable. */ + fail_if (let(variable, NULL, value, NULL, 0, 0)); + + mds_kbdc_tree_free(value); + return 0; + FAIL_BEGIN; + free(value); + FAIL_END; } @@ -2237,26 +2200,26 @@ static int compile_let(mds_kbdc_tree_let_t* restrict tree) * @param node The element to evaluate * @return Zero on success, -1 on error, 1 if the element is invalid */ -static int evaluate_element(mds_kbdc_tree_t* restrict node) +static int +evaluate_element(mds_kbdc_tree_t *restrict node) { - char32_t* restrict data = NULL; - int bad = 0; - - for (; node; node = node->next) - { - if (node->type == C(STRING)) - fail_if (data = parse_string(node, node->string.string, node->loc_start), data == NULL); - if (node->type == C(KEYS)) - fail_if (data = parse_keys(node, node->keys.keys, node->loc_start), data == NULL); - free(node->string.string); - node->type = (node->type == C(STRING)) ? C(COMPILED_STRING) : C(COMPILED_KEYS); - node->compiled_string.string = data; - bad |= (node->processed == PROCESS_LEVEL); - } - - return bad; - fail: - return -1; + char32_t *restrict data = NULL; + int bad = 0; + + for (; node; node = node->next) { + if (node->type == C(STRING)) + fail_if (!(data = parse_string(node, node->string.string, node->loc_start))); + if (node->type == C(KEYS)) + fail_if (!(data = parse_keys(node, node->keys.keys, node->loc_start))); + free(node->string.string); + node->type = (node->type == C(STRING)) ? C(COMPILED_STRING) : C(COMPILED_KEYS); + node->compiled_string.string = data; + bad |= (node->processed == PROCESS_LEVEL); + } + + return bad; +fail: + return -1; } @@ -2266,12 +2229,13 @@ static int evaluate_element(mds_kbdc_tree_t* restrict node) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_keys(mds_kbdc_tree_keys_t* restrict tree) +static int +compile_keys(mds_kbdc_tree_keys_t *restrict tree) { - fail_if (evaluate_element((mds_kbdc_tree_t*)tree) < 0); - return 0; - fail: - return -1; + fail_if (evaluate_element((mds_kbdc_tree_t *)tree) < 0); + return 0; +fail: + return -1; } @@ -2281,12 +2245,13 @@ static int compile_keys(mds_kbdc_tree_keys_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_string(mds_kbdc_tree_string_t* restrict tree) +static int +compile_string(mds_kbdc_tree_string_t *restrict tree) { - fail_if (evaluate_element((mds_kbdc_tree_t*)tree) < 0); - return 0; - fail: - return -1; + fail_if (evaluate_element((mds_kbdc_tree_t *)tree) < 0); + return 0; +fail: + return -1; } @@ -2296,15 +2261,16 @@ static int compile_string(mds_kbdc_tree_string_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_array(mds_kbdc_tree_array_t* restrict tree) +static int +compile_array(mds_kbdc_tree_array_t *restrict tree) { - int r = evaluate_element(tree->elements); - fail_if (r < 0); - if (r) - tree->processed = PROCESS_LEVEL; - return 0; - fail: - return -1; + int r = evaluate_element(tree->elements); + fail_if (r < 0); + if (r) + tree->processed = PROCESS_LEVEL; + return 0; +fail: + return -1; } @@ -2316,27 +2282,28 @@ static int compile_array(mds_kbdc_tree_array_t* restrict tree) * @return Zero on success, -1 on error, 1 if any of * the elements contain a NULL character */ -static int check_nonnul(mds_kbdc_tree_t* restrict tree) +static int +check_nonnul(mds_kbdc_tree_t *restrict tree) { - const char32_t* restrict string; - int rc = 0; - again: - if (tree == NULL) - return rc; - - for (string = tree->compiled_string.string; *string != -1; string++) - if (*string == 0) - { - NEW_ERROR(tree, ERROR, "NULL characters are not allowed in mappings"); - tree->processed = PROCESS_LEVEL; - rc = 1; - break; - } - - tree = tree->next; - goto again; - fail: - return -1; + const char32_t *restrict string; + int rc = 0; +again: + if (!tree) + return rc; + + for (string = tree->compiled_string.string; *string != -1; string++) { + if (!*string) { + NEW_ERROR(tree, ERROR, "NULL characters are not allowed in mappings"); + tree->processed = PROCESS_LEVEL; + rc = 1; + break; + } + } + + tree = tree->next; + goto again; +fail: + return -1; } @@ -2346,115 +2313,112 @@ static int check_nonnul(mds_kbdc_tree_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_map(mds_kbdc_tree_map_t* restrict tree) +static int +compile_map(mds_kbdc_tree_map_t *restrict tree) { - int bad = 0, old_have_side_effect = have_side_effect; - mds_kbdc_include_stack_t* restrict include_stack = NULL; - mds_kbdc_tree_t* seq = NULL; - mds_kbdc_tree_t* res = NULL; - mds_kbdc_tree_t* old_seq = tree->sequence; - mds_kbdc_tree_t* old_res = tree->result; - mds_kbdc_tree_map_t* dup_map = NULL; - int r, saved_errno; - mds_kbdc_tree_t* previous_last_value_statement = last_value_statement; - - have_side_effect = 0; - - /* Duplicate arguments and evaluate function calls, - variable dereferences and escapes in the mapping - input sequence. */ - fail_if (seq = mds_kbdc_tree_dup(old_seq), seq == NULL); - fail_if (bad |= evaluate_element(seq), bad < 0); - - /* Duplicate arguments and evaluate function calls, - variable dereferences and escapes in the mapping - output sequence, unless this is a value-statement. */ - if (tree->result) - { - fail_if (res = mds_kbdc_tree_dup(old_res), res == NULL); - fail_if (bad |= evaluate_element(res), bad < 0); - } - - /* Stop if any of the mapping-arguments could not be evaluated. */ - if (bad) - goto done; - - - if (tree->result) - { - /* Mapping-statement. */ - - /* Check for invalid characters in the mapping-arguments. */ - fail_if (bad |= check_nonnul(seq), bad < 0); - fail_if (bad |= check_nonnul(res), bad < 0); - if (bad) - goto done; - - /* Duplicate the mapping-statement but give it the evaluated mapping-arguments. */ - tree->sequence = NULL; - tree->result = NULL; - fail_if (dup_map = &(mds_kbdc_tree_dup((mds_kbdc_tree_t*)tree)->map), dup_map == NULL); - tree->sequence = old_seq, dup_map->sequence = seq, seq = NULL; - tree->result = old_res, dup_map->result = res, res = NULL; - - /* Enlist the mapping for assembling. */ - fail_if (include_stack = mds_kbdc_include_stack_save(), include_stack == NULL); - fail_if (add_mapping(dup_map, include_stack)); - - goto done; - } - - - /* Value-statement */ - - /* Save this statement so we can warn later if it is unnecessary, - * `set_return_value` will set it to `NULL` if there are side-effects, - * which would make this statement necessary (unless the overridding - * statement has identical side-effect, but we will not check for that). - * For simplicity, we do not store the include-stack, instead, we reset - * `last_value_statement` to `NULL` when we visit an include-statement. */ - last_value_statement = (mds_kbdc_tree_t*)tree; - - /* Add the value statement */ - r = set_return_value(seq->compiled_string.string); - seq->compiled_string.string = NULL; - - /* Check that the value-statement is inside a function call, or has - side-effects by directly or indirectly calling ‘\set/3’ on an - array that is not shadowed by an inner function- or macro-call. */ - if (r && !have_side_effect) - { - NEW_ERROR(tree, ERROR, "value-statement outside function without side-effects"); - tree->processed = PROCESS_LEVEL; - } - if (have_side_effect) - last_value_statement = NULL; - - /* Check whether we made a previous value-statement unnecessary. */ - if (previous_last_value_statement) - { - /* For simplicity we set `last_value_statement` on includes, - * so we are sure `last_value_statement` has the same include-stack. */ - - NEW_ERROR(previous_last_value_statement, WARNING, "value-statement has no effects"); - NEW_ERROR(tree, NOTE, "overridden here"); - } - - - done: - mds_kbdc_tree_free(seq); - mds_kbdc_tree_free(res); - have_side_effect |= old_have_side_effect; - return 0; - FAIL_BEGIN; - mds_kbdc_include_stack_free(include_stack); - mds_kbdc_tree_free((mds_kbdc_tree_t*)dup_map); - mds_kbdc_tree_free(seq); - mds_kbdc_tree_free(res); - tree->sequence = old_seq; - tree->result = old_res; - have_side_effect = old_have_side_effect; - FAIL_END; + int bad = 0, old_have_side_effect = have_side_effect; + mds_kbdc_include_stack_t *restrict include_stack = NULL; + mds_kbdc_tree_t *seq = NULL; + mds_kbdc_tree_t *res = NULL; + mds_kbdc_tree_t *old_seq = tree->sequence; + mds_kbdc_tree_t *old_res = tree->result; + mds_kbdc_tree_map_t *dup_map = NULL; + int r, saved_errno; + mds_kbdc_tree_t *previous_last_value_statement = last_value_statement; + + have_side_effect = 0; + + /* Duplicate arguments and evaluate function calls, + variable dereferences and escapes in the mapping + input sequence. */ + fail_if (!(seq = mds_kbdc_tree_dup(old_seq))); + fail_if ((bad |= evaluate_element(seq)) < 0); + + /* Duplicate arguments and evaluate function calls, + variable dereferences and escapes in the mapping + output sequence, unless this is a value-statement. */ + if (tree->result) { + fail_if (!(res = mds_kbdc_tree_dup(old_res))); + fail_if ((bad |= evaluate_element(res)) < 0); + } + + /* Stop if any of the mapping-arguments could not be evaluated. */ + if (bad) + goto done; + + + if (tree->result) { + /* Mapping-statement. */ + + /* Check for invalid characters in the mapping-arguments. */ + fail_if ((bad |= check_nonnul(seq)) < 0); + fail_if ((bad |= check_nonnul(res)) < 0); + if (bad) + goto done; + + /* Duplicate the mapping-statement but give it the evaluated mapping-arguments. */ + tree->sequence = NULL; + tree->result = NULL; + fail_if (!(dup_map = &mds_kbdc_tree_dup((mds_kbdc_tree_t *)tree)->map)); + tree->sequence = old_seq, dup_map->sequence = seq, seq = NULL; + tree->result = old_res, dup_map->result = res, res = NULL; + + /* Enlist the mapping for assembling. */ + fail_if (!(include_stack = mds_kbdc_include_stack_save())); + fail_if (add_mapping(dup_map, include_stack)); + + goto done; + } + + + /* Value-statement */ + + /* Save this statement so we can warn later if it is unnecessary, + * `set_return_value` will set it to `NULL` if there are side-effects, + * which would make this statement necessary (unless the overridding + * statement has identical side-effect, but we will not check for that). + * For simplicity, we do not store the include-stack, instead, we reset + * `last_value_statement` to `NULL` when we visit an include-statement. */ + last_value_statement = (mds_kbdc_tree_t *)tree; + + /* Add the value statement */ + r = set_return_value(seq->compiled_string.string); + seq->compiled_string.string = NULL; + + /* Check that the value-statement is inside a function call, or has + side-effects by directly or indirectly calling ‘\set/3’ on an + array that is not shadowed by an inner function- or macro-call. */ + if (r && !have_side_effect) { + NEW_ERROR(tree, ERROR, "value-statement outside function without side-effects"); + tree->processed = PROCESS_LEVEL; + } + if (have_side_effect) + last_value_statement = NULL; + + /* Check whether we made a previous value-statement unnecessary. */ + if (previous_last_value_statement) { + /* For simplicity we set `last_value_statement` on includes, + * so we are sure `last_value_statement` has the same include-stack. */ + + NEW_ERROR(previous_last_value_statement, WARNING, "value-statement has no effects"); + NEW_ERROR(tree, NOTE, "overridden here"); + } + + +done: + mds_kbdc_tree_free(seq); + mds_kbdc_tree_free(res); + have_side_effect |= old_have_side_effect; + return 0; + FAIL_BEGIN; + mds_kbdc_include_stack_free(include_stack); + mds_kbdc_tree_free((mds_kbdc_tree_t*)dup_map); + mds_kbdc_tree_free(seq); + mds_kbdc_tree_free(res); + tree->sequence = old_seq; + tree->result = old_res; + have_side_effect = old_have_side_effect; + FAIL_END; } @@ -2464,70 +2428,71 @@ static int compile_map(mds_kbdc_tree_map_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_macro_call(mds_kbdc_tree_macro_call_t* restrict tree) +static int +compile_macro_call(mds_kbdc_tree_macro_call_t *restrict tree) { - mds_kbdc_tree_t* arg = NULL; - mds_kbdc_tree_t* arg_; - 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 = 0; - int bad, saved_errno; - - last_value_statement = NULL; - - /* Push call-stack. */ - mds_kbdc_call_stack_push((mds_kbdc_tree_t*)tree, tree->loc_start, tree->loc_end); - - /* Duplicate arguments and evaluate function calls, - variable dereferences and escapes in the macro - call arguments. */ - if (tree->arguments) - fail_if (arg = mds_kbdc_tree_dup(tree->arguments), arg == NULL); - fail_if (bad = evaluate_element(arg), bad < 0); - if (bad) - return mds_kbdc_tree_free(arg), 0; - - /* Get the macro's subtree and include-stack, if it has - not been defined `get_macro` will add an error message - and return `NULL`. */ - fail_if (get_macro(tree, ¯o, ¯o_include_stack)); - if (macro == NULL) - goto done; - - - /* Push variable-stack and set parameters. */ - variables_stack_push(); - for (arg_ = arg; arg_; arg_ = arg_->next) - fail_if (let(++variable, NULL, arg_, NULL, 0, 0)); - - /* Switch include-stack to the macro's. */ - fail_if (our_include_stack = mds_kbdc_include_stack_save(), our_include_stack == NULL); - fail_if (mds_kbdc_include_stack_restore(macro_include_stack)); - - /* Call the macro. */ - fail_if (compile_subtree(macro->inner)); - - /* Switch back the include-stack to ours. */ - fail_if (mds_kbdc_include_stack_restore(our_include_stack)); - mds_kbdc_include_stack_free(our_include_stack), our_include_stack = NULL; - - /* Pop variable-stack. */ - variables_stack_pop(); - - done: - /* Pop call-stack. */ - mds_kbdc_call_stack_pop(); - - last_value_statement = NULL; - break_level = 0; - mds_kbdc_tree_free(arg); - return 0; - FAIL_BEGIN; - mds_kbdc_call_stack_pop(); - mds_kbdc_tree_free(arg); - mds_kbdc_include_stack_free(our_include_stack); - FAIL_END; + mds_kbdc_tree_t *arg = NULL; + mds_kbdc_tree_t *arg_; + 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 = 0; + int bad, saved_errno; + + last_value_statement = NULL; + + /* Push call-stack. */ + mds_kbdc_call_stack_push((mds_kbdc_tree_t *)tree, tree->loc_start, tree->loc_end); + + /* Duplicate arguments and evaluate function calls, + variable dereferences and escapes in the macro + call arguments. */ + if (tree->arguments) + fail_if (!(arg = mds_kbdc_tree_dup(tree->arguments))); + fail_if (bad = evaluate_element(arg), bad < 0); + if (bad) + return mds_kbdc_tree_free(arg), 0; + + /* Get the macro's subtree and include-stack, if it has + not been defined `get_macro` will add an error message + and return `NULL`. */ + fail_if (get_macro(tree, ¯o, ¯o_include_stack)); + if (!macro) + goto done; + + + /* Push variable-stack and set parameters. */ + variables_stack_push(); + for (arg_ = arg; arg_; arg_ = arg_->next) + fail_if (let(++variable, NULL, arg_, NULL, 0, 0)); + + /* Switch include-stack to the macro's. */ + fail_if (!(our_include_stack = mds_kbdc_include_stack_save())); + fail_if (mds_kbdc_include_stack_restore(macro_include_stack)); + + /* Call the macro. */ + fail_if (compile_subtree(macro->inner)); + + /* Switch back the include-stack to ours. */ + fail_if (mds_kbdc_include_stack_restore(our_include_stack)); + mds_kbdc_include_stack_free(our_include_stack), our_include_stack = NULL; + + /* Pop variable-stack. */ + variables_stack_pop(); + +done: + /* Pop call-stack. */ + mds_kbdc_call_stack_pop(); + + last_value_statement = NULL; + break_level = 0; + mds_kbdc_tree_free(arg); + return 0; + FAIL_BEGIN; + mds_kbdc_call_stack_pop(); + mds_kbdc_tree_free(arg); + mds_kbdc_include_stack_free(our_include_stack); + FAIL_END; } @@ -2537,64 +2502,64 @@ static int compile_macro_call(mds_kbdc_tree_macro_call_t* restrict tree) * @param tree The tree to compile * @return Zero on success, -1 on error */ -static int compile_subtree(mds_kbdc_tree_t* restrict tree) +static int +compile_subtree(mds_kbdc_tree_t *restrict tree) { -#define t(expr) fail_if ((expr) < 0) -#define c(type) t (compile_##type(&(tree->type))) -#define c_(type) t (compile_##type(&(tree->type##_))) - again: - if (tree == NULL) - return 0; - - if (tree->processed == PROCESS_LEVEL) - /* An error has occurred here before, let's skip it so - * we do not deluge the user with errors. */ - goto next; - - switch (tree->type) - { - case C(INFORMATION): - t (compile_subtree(tree->information.inner)); - break; - case C(INFORMATION_LANGUAGE): c (language); break; - case C(INFORMATION_COUNTRY): c (country); break; - case C(INFORMATION_VARIANT): c (variant); break; - case C(INCLUDE): c (include); break; - case C(FUNCTION): c (function); break; - case C(MACRO): c (macro); break; - case C(ASSUMPTION): - if (includes_ptr == 0) - fail_if (compile_subtree(tree->assumption.inner)); - break; - case C(ASSUMPTION_HAVE): c (have); break; - case C(ASSUMPTION_HAVE_CHARS): c (have_chars); break; - case C(ASSUMPTION_HAVE_RANGE): c (have_range); break; - case C(FOR): c_ (for); break; - case C(IF): c_ (if); break; - case C(LET): c (let); break; - case C(KEYS): c (keys); break; - case C(STRING): c (string); break; - case C(ARRAY): c (array); break; - case C(MAP): c (map); break; - case C(MACRO_CALL): c (macro_call); break; - case C(RETURN): break_level = 3; break; - case C(BREAK): break_level = 2; break; - case C(CONTINUE): break_level = 1; break; - default: - break; - } - +#define t(expr) fail_if ((expr) < 0) +#define c(type) t (compile_##type(&tree->type)) +#define c_(type) t (compile_##type(&tree->type##_)) +again: + if (!tree) + return 0; + + if (tree->processed == PROCESS_LEVEL) + /* An error has occurred here before, let's skip it so + * we do not deluge the user with errors. */ + goto next; + + switch (tree->type) { + case C(INFORMATION): + t (compile_subtree(tree->information.inner)); + break; + case C(INFORMATION_LANGUAGE): c (language); break; + case C(INFORMATION_COUNTRY): c (country); break; + case C(INFORMATION_VARIANT): c (variant); break; + case C(INCLUDE): c (include); break; + case C(FUNCTION): c (function); break; + case C(MACRO): c (macro); break; + case C(ASSUMPTION): + if (!includes_ptr) + fail_if (compile_subtree(tree->assumption.inner)); + break; + case C(ASSUMPTION_HAVE): c (have); break; + case C(ASSUMPTION_HAVE_CHARS): c (have_chars); break; + case C(ASSUMPTION_HAVE_RANGE): c (have_range); break; + case C(FOR): c_ (for); break; + case C(IF): c_ (if); break; + case C(LET): c (let); break; + case C(KEYS): c (keys); break; + case C(STRING): c (string); break; + case C(ARRAY): c (array); break; + case C(MAP): c (map); break; + case C(MACRO_CALL): c (macro_call); break; + case C(RETURN): break_level = 3; break; + case C(BREAK): break_level = 2; break; + case C(CONTINUE): break_level = 1; break; + default: + break; + } + next: - if (break_level) - /* If a `continue`, `break` or `return` has been encountered, - * we are done here and should return to whence we came and - * let the subcompiler of that construct deal with it. */ - return 0; - - tree = tree->next; - goto again; - fail: - return -1; + if (break_level) + /* If a `continue`, `break` or `return` has been encountered, + * we are done here and should return to whence we came and + * let the subcompiler of that construct deal with it. */ + return 0; + + tree = tree->next; + goto again; +fail: + return -1; #undef c_ #undef c #undef t @@ -2607,23 +2572,24 @@ static int compile_subtree(mds_kbdc_tree_t* restrict tree) * @param result_ `result` from `eliminate_dead_code`, will be updated * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise */ -int compile_layout(mds_kbdc_parsed_t* restrict result_) +int +compile_layout(mds_kbdc_parsed_t *restrict result_) { - int r, saved_errno; - result = result_; - mds_kbdc_include_stack_begin(result_); - mds_kbdc_call_stack_begin(result_); - r = compile_subtree(result_->tree); - saved_errno = errno; - mds_kbdc_call_stack_end(); - mds_kbdc_include_stack_end(); - variables_terminate(); - callables_terminate(); - errno = saved_errno; - fail_if (r); - return 0; - fail: - return -1; + int r, saved_errno; + result = result_; + mds_kbdc_include_stack_begin(result_); + mds_kbdc_call_stack_begin(result_); + r = compile_subtree(result_->tree); + saved_errno = errno; + mds_kbdc_call_stack_end(); + mds_kbdc_include_stack_end(); + variables_terminate(); + callables_terminate(); + errno = saved_errno; + fail_if (r); + return 0; +fail: + return -1; } @@ -2633,4 +2599,3 @@ int compile_layout(mds_kbdc_parsed_t* restrict result_) #undef NEW_ERROR #undef C #undef PROCESS_LEVEL - diff --git a/src/mds-kbdc/compile-layout.h b/src/mds-kbdc/compile-layout.h index 6911a71..86604e0 100644 --- a/src/mds-kbdc/compile-layout.h +++ b/src/mds-kbdc/compile-layout.h @@ -28,8 +28,7 @@ * @param result `result` from `eliminate_dead_code`, will be updated * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise */ -int compile_layout(mds_kbdc_parsed_t* restrict result); +int compile_layout(mds_kbdc_parsed_t *restrict result); #endif - diff --git a/src/mds-kbdc/eliminate-dead-code.c b/src/mds-kbdc/eliminate-dead-code.c index 039b6a8..5a8102f 100644 --- a/src/mds-kbdc/eliminate-dead-code.c +++ b/src/mds-kbdc/eliminate-dead-code.c @@ -27,7 +27,7 @@ /** * Tree type constant shortener */ -#define C(TYPE) MDS_KBDC_TREE_TYPE_##TYPE +#define C(TYPE) MDS_KBDC_TREE_TYPE_##TYPE /** * Add an error with “included from here”-notes to the error list @@ -38,20 +38,20 @@ * @param ...:const char*, ... Error description format string and arguments * @scope error:mds_kbdc_parse_error_t* Variable where the new error will be stored */ -#define NEW_ERROR(NODE, PTR, SEVERITY, ...) \ - NEW_ERROR_WITH_INCLUDES(NODE, PTR, SEVERITY, __VA_ARGS__) +#define NEW_ERROR(NODE, PTR, SEVERITY, ...)\ + NEW_ERROR_WITH_INCLUDES(NODE, PTR, SEVERITY, __VA_ARGS__) /** * Variable whether the latest created error is stored */ -static mds_kbdc_parse_error_t* error; +static mds_kbdc_parse_error_t *error; /** * The parameter of `eliminate_dead_code` */ -static mds_kbdc_parsed_t* restrict result; +static mds_kbdc_parsed_t *restrict result; /** * 2: Eliminating because of a return-statement @@ -68,7 +68,7 @@ static int elimination_level = 0; * @param tree The tree to reduce * @return Zero on success, -1 on error */ -static int eliminate_subtree(mds_kbdc_tree_t* restrict tree); +static int eliminate_subtree(mds_kbdc_tree_t *restrict tree); @@ -78,17 +78,18 @@ static int eliminate_subtree(mds_kbdc_tree_t* restrict tree); * @param tree The tree to reduce * @return Zero on success, -1 on error */ -static int eliminate_include(mds_kbdc_tree_include_t* restrict tree) +static int +eliminate_include(mds_kbdc_tree_include_t *restrict tree) { - void* data; - int r; - fail_if (mds_kbdc_include_stack_push(tree, &data)); - r = eliminate_subtree(tree->inner); - mds_kbdc_include_stack_pop(data); - fail_if (r); - return 0; - fail: - return -1; + void *data; + int r; + fail_if (mds_kbdc_include_stack_push(tree, &data)); + r = eliminate_subtree(tree->inner); + mds_kbdc_include_stack_pop(data); + fail_if (r); + return 0; +fail: + return -1; } @@ -98,17 +99,18 @@ static int eliminate_include(mds_kbdc_tree_include_t* restrict tree) * @param tree The tree to reduce * @return Zero on success, -1 on error */ -static int eliminate_if(mds_kbdc_tree_if_t* restrict tree) +static int +eliminate_if(mds_kbdc_tree_if_t *restrict tree) { - int elimination; - fail_if (eliminate_subtree(tree->inner)); - elimination = elimination_level, elimination_level = 0; - fail_if (eliminate_subtree(tree->otherwise)); - if (elimination > elimination_level) - elimination = elimination_level; - return 0; - fail: - return -1; + int elimination; + fail_if (eliminate_subtree(tree->inner)); + elimination = elimination_level, elimination_level = 0; + fail_if (eliminate_subtree(tree->otherwise)); + if (elimination > elimination_level) + elimination = elimination_level; + return 0; +fail: + return -1; } @@ -118,46 +120,51 @@ static int eliminate_if(mds_kbdc_tree_if_t* restrict tree) * @param tree The tree to reduce * @return Zero on success, -1 on error */ -static int eliminate_subtree(mds_kbdc_tree_t* restrict tree) +static int +eliminate_subtree(mds_kbdc_tree_t *restrict tree) { -#define e(type) fail_if (eliminate_##type(&(tree->type))) -#define E(type) fail_if (eliminate_##type(&(tree->type##_))) - again: - if (tree == NULL) - return 0; +#define e(type) fail_if (eliminate_##type(&tree->type)) +#define E(type) fail_if (eliminate_##type(&tree->type##_)) +again: + if (!tree) + return 0; - switch (tree->type) - { - case C(INCLUDE): e(include); break; - case C(IF): E(if); break; - case C(INFORMATION): - case C(FUNCTION): - case C(MACRO): - case C(ASSUMPTION): - case C(FOR): - fail_if (eliminate_subtree(tree->information.inner)); - if ((tree->type == C(FUNCTION)) || (tree->type == C(MACRO))) elimination_level = 0; - else if ((tree->type == C(FOR)) && (elimination_level == 1)) elimination_level = 0; - break; - case C(RETURN): - case C(BREAK): - case C(CONTINUE): - elimination_level = tree->type == C(RETURN) ? 2 : 1; - break; - default: - break; - } - - if (tree->next && elimination_level) - { - NEW_ERROR(tree->next, includes_ptr, WARNING, "statement is unreachable"); - mds_kbdc_tree_free(tree->next), tree->next = NULL; - } - - tree = tree->next; - goto again; - fail: - return -1; + switch (tree->type) { + case C(INCLUDE): + e(include); + break; + case C(IF): + E(if); + break; + case C(INFORMATION): + case C(FUNCTION): + case C(MACRO): + case C(ASSUMPTION): + case C(FOR): + fail_if (eliminate_subtree(tree->information.inner)); + if (tree->type == C(FUNCTION) || tree->type == C(MACRO)) + elimination_level = 0; + else if (tree->type == C(FOR) && elimination_level == 1) + elimination_level = 0; + break; + case C(RETURN): + case C(BREAK): + case C(CONTINUE): + elimination_level = tree->type == C(RETURN) ? 2 : 1; + break; + default: + break; + } + + if (tree->next && elimination_level) { + NEW_ERROR(tree->next, includes_ptr, WARNING, "statement is unreachable"); + mds_kbdc_tree_free(tree->next), tree->next = NULL; + } + + tree = tree->next; + goto again; +fail: + return -1; #undef E #undef e } @@ -169,20 +176,20 @@ static int eliminate_subtree(mds_kbdc_tree_t* restrict tree) * @param result_ `result` from `validate_tree`, will be updated * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise */ -int eliminate_dead_code(mds_kbdc_parsed_t* restrict result_) +int +eliminate_dead_code(mds_kbdc_parsed_t *restrict result_) { - int r; - mds_kbdc_include_stack_begin(result = result_); - r = eliminate_subtree(result_->tree); - mds_kbdc_include_stack_end(); - fail_if (r); - return 0; - fail: - return -1; + int r; + mds_kbdc_include_stack_begin(result = result_); + r = eliminate_subtree(result_->tree); + mds_kbdc_include_stack_end(); + fail_if (r); + return 0; +fail: + return -1; } #undef NEW_ERROR #undef C - diff --git a/src/mds-kbdc/eliminate-dead-code.h b/src/mds-kbdc/eliminate-dead-code.h index cbdf731..84bc3b6 100644 --- a/src/mds-kbdc/eliminate-dead-code.h +++ b/src/mds-kbdc/eliminate-dead-code.h @@ -28,8 +28,7 @@ * @param result `result` from `validate_tree`, will be updated * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise */ -int eliminate_dead_code(mds_kbdc_parsed_t* restrict result); +int eliminate_dead_code(mds_kbdc_parsed_t *restrict result); #endif - diff --git a/src/mds-kbdc/globals.c b/src/mds-kbdc/globals.c index 8e17020..01feca9 100644 --- a/src/mds-kbdc/globals.c +++ b/src/mds-kbdc/globals.c @@ -26,10 +26,9 @@ int argc; /** * The command line arguments */ -char** argv; +char **argv; /** * Whether ‘--force’ is used */ int argv_force = 0; - diff --git a/src/mds-kbdc/globals.h b/src/mds-kbdc/globals.h index b2b5cf1..1acf4bc 100644 --- a/src/mds-kbdc/globals.h +++ b/src/mds-kbdc/globals.h @@ -27,7 +27,7 @@ extern int argc; /** * The command line arguments */ -extern char** argv; +extern char **argv; /** * Whether ‘--force’ is used @@ -36,4 +36,3 @@ extern int argv_force; #endif - diff --git a/src/mds-kbdc/include-stack.c b/src/mds-kbdc/include-stack.c index 18b13d7..8ba787f 100644 --- a/src/mds-kbdc/include-stack.c +++ b/src/mds-kbdc/include-stack.c @@ -27,27 +27,27 @@ /** * Variable whether the latest created error is stored */ -static mds_kbdc_parse_error_t* error; +static mds_kbdc_parse_error_t *error; /** * The `result` parameter of root procedure that requires the include-stack */ -static mds_kbdc_parsed_t* result; +static mds_kbdc_parsed_t *result; /** * The original value of `result->pathname` */ -static char* original_pathname; +static char *original_pathname; /** * The original value of `result->source_code` */ -static mds_kbdc_source_code_t* original_source_code; +static mds_kbdc_source_code_t *original_source_code; /** * Stack of visited include-statements */ -static const mds_kbdc_tree_include_t** restrict includes = NULL; +static const mds_kbdc_tree_include_t **restrict includes = NULL; /** * The number elements allocated for `includes` @@ -62,7 +62,7 @@ size_t includes_ptr = 0; /** * The latest saved include-stack */ -static mds_kbdc_include_stack_t* latest_save = NULL; +static mds_kbdc_include_stack_t *latest_save = NULL; @@ -72,23 +72,23 @@ static mds_kbdc_include_stack_t* latest_save = NULL; * @param ptr The number of “included from here”-notes * @return Zero on success, -1 on error */ -int mds_kbdc_include_stack_dump(size_t ptr) +int +mds_kbdc_include_stack_dump(size_t ptr) { - char* old_pathname = result->pathname; - mds_kbdc_source_code_t* old_source_code = result->source_code; - while (ptr--) - { - result->pathname = ptr ? includes[ptr - 1]->filename : original_pathname; - result->source_code = ptr ? includes[ptr - 1]->source_code : original_source_code; - NEW_ERROR_WITHOUT_INCLUDES(includes[ptr], NOTE, "included from here"); - } - result->pathname = old_pathname; - result->source_code = old_source_code; - return 0; - fail: - result->pathname = old_pathname; - result->source_code = old_source_code; - return -1; + char *old_pathname = result->pathname; + mds_kbdc_source_code_t *old_source_code = result->source_code; + while (ptr--) { + result->pathname = ptr ? includes[ptr - 1]->filename : original_pathname; + result->source_code = ptr ? includes[ptr - 1]->source_code : original_source_code; + NEW_ERROR_WITHOUT_INCLUDES(includes[ptr], NOTE, "included from here"); + } + result->pathname = old_pathname; + result->source_code = old_source_code; + return 0; +fail: + result->pathname = old_pathname; + result->source_code = old_source_code; + return -1; } @@ -97,11 +97,12 @@ int mds_kbdc_include_stack_dump(size_t ptr) * * @param result_ The `result` parameter of root procedure that requires the include-stack */ -void mds_kbdc_include_stack_begin(mds_kbdc_parsed_t* restrict result_) +void +mds_kbdc_include_stack_begin(mds_kbdc_parsed_t *restrict result_) { - result = result_; - original_pathname = result_->pathname; - original_source_code = result_->source_code; + result = result_; + original_pathname = result_->pathname; + original_source_code = result_->source_code; } @@ -109,13 +110,14 @@ void mds_kbdc_include_stack_begin(mds_kbdc_parsed_t* restrict result_) * Mark the root of the tree as no longer being visited, * and release clean up after the use of this module */ -void mds_kbdc_include_stack_end(void) +void +mds_kbdc_include_stack_end(void) { - latest_save = NULL; - result->pathname = original_pathname; - result->source_code = original_source_code; - free(includes), includes = NULL; - includes_size = includes_ptr = 0; + latest_save = NULL; + result->pathname = original_pathname; + result->source_code = original_source_code; + free(includes), includes = NULL; + includes_size = includes_ptr = 0; } @@ -128,30 +130,31 @@ void mds_kbdc_include_stack_end(void) * is undefined on error * @return Zero on success, -1 on error */ -int mds_kbdc_include_stack_push(const mds_kbdc_tree_include_t* restrict tree, void** data) +int +mds_kbdc_include_stack_push(const mds_kbdc_tree_include_t *restrict tree, void **data) { - const mds_kbdc_tree_include_t** old = NULL; - int saved_errno; - - if (includes_ptr == includes_size) - fail_if (xxrealloc(old, includes, includes_size += 4, const mds_kbdc_tree_include_t*)); - - fail_if (xmalloc(*data, 3, void*)); - - ((char**)(*data))[0] = result->pathname; - ((mds_kbdc_source_code_t**)(*data))[1] = result->source_code; - ((mds_kbdc_include_stack_t**)(*data))[2] = latest_save; - - includes[includes_ptr++] = tree; - result->pathname = tree->filename; - result->source_code = tree->source_code; - latest_save = NULL; - - return 0; - fail: - saved_errno = errno; - free(old); - return errno = saved_errno, -1; + const mds_kbdc_tree_include_t **old = NULL; + int saved_errno; + + if (includes_ptr == includes_size) + fail_if (xxrealloc(old, includes, includes_size += 4, const mds_kbdc_tree_include_t*)); + + fail_if (xmalloc(*data, 3, void*)); + + ((char **)(*data))[0] = result->pathname; + ((mds_kbdc_source_code_t **)(*data))[1] = result->source_code; + ((mds_kbdc_include_stack_t **)(*data))[2] = latest_save; + + includes[includes_ptr++] = tree; + result->pathname = tree->filename; + result->source_code = tree->source_code; + latest_save = NULL; + + return 0; +fail: + saved_errno = errno; + free(old); + return errno = saved_errno, -1; } @@ -162,15 +165,16 @@ int mds_kbdc_include_stack_push(const mds_kbdc_tree_include_t* restrict tree, vo * * @param data `*data` from `mds_kbdc_include_stack_push` */ -void mds_kbdc_include_stack_pop(void* data) +void +mds_kbdc_include_stack_pop(void *data) { - int saved_errno = errno; - result->pathname = ((char**)data)[0]; - result->source_code = ((mds_kbdc_source_code_t**)data)[1]; - latest_save = ((mds_kbdc_include_stack_t**)data)[2]; - includes_ptr--; - free(data); - errno = saved_errno; + int saved_errno = errno; + result->pathname = ((char **)data)[0]; + result->source_code = ((mds_kbdc_source_code_t **)data)[1]; + latest_save = ((mds_kbdc_include_stack_t **)data)[2]; + includes_ptr--; + free(data); + errno = saved_errno; } @@ -179,34 +183,34 @@ void mds_kbdc_include_stack_pop(void* data) * * @return The include-stack, `NULL` on error */ -mds_kbdc_include_stack_t* mds_kbdc_include_stack_save(void) +mds_kbdc_include_stack_t * +mds_kbdc_include_stack_save(void) { - int saved_errno; - - if (latest_save) - { - latest_save->duplicates++; - return latest_save; - } - - fail_if (xmalloc(latest_save, 1, mds_kbdc_include_stack_t)); - - latest_save->stack = NULL; - latest_save->ptr = includes_ptr; - latest_save->duplicates = 0; - - if (latest_save->ptr == 0) - return latest_save; - - fail_if (xmemdup(latest_save->stack, includes, latest_save->ptr, const mds_kbdc_tree_include_t*)); - - return latest_save; - fail: - saved_errno = errno; - if (latest_save) - free(latest_save->stack), latest_save = NULL; - errno = saved_errno; - return NULL; + int saved_errno; + + if (latest_save) { + latest_save->duplicates++; + return latest_save; + } + + fail_if (xmalloc(latest_save, 1, mds_kbdc_include_stack_t)); + + latest_save->stack = NULL; + latest_save->ptr = includes_ptr; + latest_save->duplicates = 0; + + if (!latest_save->ptr) + return latest_save; + + fail_if (xmemdup(latest_save->stack, includes, latest_save->ptr, const mds_kbdc_tree_include_t*)); + + return latest_save; +fail: + saved_errno = errno; + if (latest_save) + free(latest_save->stack), latest_save = NULL; + errno = saved_errno; + return NULL; } @@ -216,23 +220,23 @@ mds_kbdc_include_stack_t* mds_kbdc_include_stack_save(void) * @param stack The include-stack * @return Zero on success, -1 on error */ -int mds_kbdc_include_stack_restore(mds_kbdc_include_stack_t* restrict stack) +int +mds_kbdc_include_stack_restore(mds_kbdc_include_stack_t *restrict stack) { - const mds_kbdc_tree_include_t** tmp; - - latest_save = stack; - - if (stack->ptr > includes_size) - { - fail_if (yrealloc(tmp, includes, stack->ptr, const mds_kbdc_tree_include_t*)); - includes_size = stack->ptr; - } - - memcpy(includes, stack->stack, stack->ptr * sizeof(const mds_kbdc_tree_include_t*)); - includes_ptr = stack->ptr; - return 0; - fail: - return -1; + const mds_kbdc_tree_include_t **tmp; + + latest_save = stack; + + if (stack->ptr > includes_size) { + fail_if (yrealloc(tmp, includes, stack->ptr, const mds_kbdc_tree_include_t *)); + includes_size = stack->ptr; + } + + memcpy(includes, stack->stack, stack->ptr * sizeof(const mds_kbdc_tree_include_t *)); + includes_ptr = stack->ptr; + return 0; +fail: + return -1; } @@ -241,13 +245,13 @@ int mds_kbdc_include_stack_restore(mds_kbdc_include_stack_t* restrict stack) * * @param stack The include-stack */ -void mds_kbdc_include_stack_free(mds_kbdc_include_stack_t* restrict stack) +void +mds_kbdc_include_stack_free(mds_kbdc_include_stack_t *restrict stack) { - if ((stack == NULL) || (stack->duplicates--)) - return; - free(stack->stack); - free(stack); - if (latest_save == stack) - latest_save = NULL; + if (!stack || stack->duplicates--) + return; + free(stack->stack); + free(stack); + if (latest_save == stack) + latest_save = NULL; } - diff --git a/src/mds-kbdc/include-stack.h b/src/mds-kbdc/include-stack.h index c077e2b..284bb02 100644 --- a/src/mds-kbdc/include-stack.h +++ b/src/mds-kbdc/include-stack.h @@ -31,17 +31,17 @@ * @param ...:const char*, ... Error description format string and arguments * @scope error:mds_kbdc_parse_error_t* Variable where the new error will be stored */ -#define NEW_ERROR_WITHOUT_INCLUDES(NODE, SEVERITY, ...) \ - NEW_ERROR_(result, SEVERITY, 1, (NODE)->loc_line, \ - (NODE)->loc_start, (NODE)->loc_end, 1, __VA_ARGS__) +#define NEW_ERROR_WITHOUT_INCLUDES(NODE, SEVERITY, ...)\ + NEW_ERROR_(result, SEVERITY, 1, (NODE)->loc_line,\ + (NODE)->loc_start, (NODE)->loc_end, 1, __VA_ARGS__) /** * Add “included from here”-notes * * @param PTR:size_t The number of “included from here”-notes */ -#define DUMP_INCLUDE_STACK(PTR) \ - fail_if (mds_kbdc_include_stack_dump(PTR)) +#define DUMP_INCLUDE_STACK(PTR)\ + fail_if (mds_kbdc_include_stack_dump(PTR)) /** * Add an error with “included from here”-notes to the error list @@ -52,36 +52,32 @@ * @param ...:const char*, ... Error description format string and arguments * @scope error:mds_kbdc_parse_error_t* Variable where the new error will be stored */ -#define NEW_ERROR_WITH_INCLUDES(NODE, PTR, SEVERITY, ...) \ - do \ - { \ - NEW_ERROR_WITHOUT_INCLUDES(NODE, SEVERITY, __VA_ARGS__); \ - DUMP_INCLUDE_STACK(PTR); \ - } \ - while (0) +#define NEW_ERROR_WITH_INCLUDES(NODE, PTR, SEVERITY, ...)\ + do {\ + NEW_ERROR_WITHOUT_INCLUDES(NODE, SEVERITY, __VA_ARGS__);\ + DUMP_INCLUDE_STACK(PTR);\ + } while (0) /** * A saved state of the include-stack */ -typedef struct mds_kbdc_include_stack -{ - /** - * Stack of visited include-statements - */ - const mds_kbdc_tree_include_t** stack; - - /** - * The number elements stored in `stack` (do not edit) - */ - size_t ptr; - - /** - * The number of duplicates there are of this object - */ - size_t duplicates; - +typedef struct mds_kbdc_include_stack { + /** + * Stack of visited include-statements + */ + const mds_kbdc_tree_include_t **stack; + + /** + * The number elements stored in `stack` (do not edit) + */ + size_t ptr; + + /** + * The number of duplicates there are of this object + */ + size_t duplicates; } mds_kbdc_include_stack_t; @@ -107,7 +103,7 @@ int mds_kbdc_include_stack_dump(size_t ptr); * * @param result The `result` parameter of root procedure that requires the include-stack */ -void mds_kbdc_include_stack_begin(mds_kbdc_parsed_t* restrict result); +void mds_kbdc_include_stack_begin(mds_kbdc_parsed_t *restrict result); /** * Mark the root of the tree as no longer being visited, @@ -124,7 +120,7 @@ void mds_kbdc_include_stack_end(void); * is undefined on error * @return Zero on success, -1 on error */ -int mds_kbdc_include_stack_push(const mds_kbdc_tree_include_t* restrict tree, void** data); +int mds_kbdc_include_stack_push(const mds_kbdc_tree_include_t *restrict tree, void **data); /** * Undo the lasted not-undone call to `mds_kbdc_include_stack_push` @@ -133,7 +129,7 @@ int mds_kbdc_include_stack_push(const mds_kbdc_tree_include_t* restrict tree, vo * * @param data `*data` from `mds_kbdc_include_stack_push` */ -void mds_kbdc_include_stack_pop(void* data); +void mds_kbdc_include_stack_pop(void *data); /** * Save the current include-stack @@ -148,15 +144,14 @@ mds_kbdc_include_stack_t* mds_kbdc_include_stack_save(void); * @param stack The include-stack * @return Zero on success, -1 on error */ -int mds_kbdc_include_stack_restore(mds_kbdc_include_stack_t* restrict stack); +int mds_kbdc_include_stack_restore(mds_kbdc_include_stack_t *restrict stack); /** * Destroy a previous include-stack and free its allocation * * @param stack The include-stack */ -void mds_kbdc_include_stack_free(mds_kbdc_include_stack_t* restrict stack); +void mds_kbdc_include_stack_free(mds_kbdc_include_stack_t *restrict stack); #endif - diff --git a/src/mds-kbdc/make-tree.c b/src/mds-kbdc/make-tree.c index 1b5e8a5..f5bdf55 100644 --- a/src/mds-kbdc/make-tree.c +++ b/src/mds-kbdc/make-tree.c @@ -31,7 +31,7 @@ #ifndef DEBUG # define DEBUG_PROC(statements) #else -# define DEBUG_PROC(statements) statements +# define DEBUG_PROC(statements) statements #endif @@ -40,16 +40,14 @@ * as a compiler debugging feature and should be used from * inside `DEBUG_PROC` */ -#define PRINT_STACK \ - do \ - { \ - size_t i = stack_ptr; \ - fprintf(stderr, "stack {\n"); \ - while (i--) \ - fprintf(stderr, " %s\n", keyword_stack[i]); \ - fprintf(stderr, "}\n"); \ - } \ - while (0) +#define PRINT_STACK\ + do {\ + size_t i = stack_ptr;\ + fprintf(stderr, "stack {\n");\ + while (i--)\ + fprintf(stderr, " %s\n", keyword_stack[i]);\ + fprintf(stderr, "}\n");\ + } while (0) /** @@ -60,8 +58,8 @@ * @param UPPER:¿T? The upper bound, inclusive * @return :int 1 if `LOWER` ≤ `VALUE` ≤ `UPPER`, otherwise 0 */ -#define in_range(LOWER, VALUE, UPPER) \ - (((LOWER) <= (VALUE)) && ((VALUE) <= (UPPER))) +#define in_range(LOWER, VALUE, UPPER)\ + ((LOWER) <= (VALUE) && (VALUE) <= (UPPER)) /** @@ -70,23 +68,23 @@ * @param C:char The character * @return :int Zero if `C` is a valid callable name character or a forward slash, otherwise 0 */ -#define is_name_char(C) \ - (in_range('a', C, 'z') || in_range('A', C, 'Z') || strchr("0123456789_/", C)) +#define is_name_char(C)\ + (in_range('a', C, 'z') || in_range('A', C, 'Z') || strchr("0123456789_/", C)) /** * Pointer to the beginning of the current line */ -#define LINE \ - (result->source_code->lines[line_i]) +#define LINE\ + (result->source_code->lines[line_i]) /** * Update the tip of the stack to point to the address * of the current stack's tip's `next`-member */ -#define NEXT \ - tree_stack[stack_ptr] = &(tree_stack[stack_ptr][0]->next) +#define NEXT\ + tree_stack[stack_ptr] = &(tree_stack[stack_ptr][0]->next) /** @@ -97,9 +95,9 @@ * @param ...:const char*, ... Error description format string and arguments * @scope error:mds_kbdc_parse_error_t* Variable where the new error will be stored */ -#define NEW_ERROR(ERROR_IS_IN_FILE, SEVERITY, ...) \ - NEW_ERROR_(result, SEVERITY, ERROR_IS_IN_FILE, line_i, \ - (size_t)(line - LINE), (size_t)(end - LINE), 1, __VA_ARGS__) +#define NEW_ERROR(ERROR_IS_IN_FILE, SEVERITY, ...)\ + NEW_ERROR_(result, SEVERITY, ERROR_IS_IN_FILE, line_i,\ + (size_t)(line - LINE), (size_t)(end - LINE), 1, __VA_ARGS__) /** @@ -108,13 +106,13 @@ * @param LOWERCASE:identifier The keyword, for the node type, in lower case * @param UPPERCASE:identifier The keyword, for the node type, in upper case */ -#define NEW_NODE(LOWERCASE, UPPERCASE) \ - mds_kbdc_tree_##LOWERCASE##_t* node; \ - fail_if (xcalloc(node, 1, mds_kbdc_tree_##LOWERCASE##_t)); \ - node->type = MDS_KBDC_TREE_TYPE_##UPPERCASE; \ - node->loc_line = line_i; \ - node->loc_start = (size_t)(line - LINE); \ - node->loc_end = (size_t)(end - LINE) +#define NEW_NODE(LOWERCASE, UPPERCASE)\ + mds_kbdc_tree_##LOWERCASE##_t *node;\ + fail_if (xcalloc(node, 1, mds_kbdc_tree_##LOWERCASE##_t));\ + node->type = MDS_KBDC_TREE_TYPE_##UPPERCASE;\ + node->loc_line = line_i;\ + node->loc_start = (size_t)(line - LINE);\ + node->loc_end = (size_t)(end - LINE) /** @@ -123,13 +121,13 @@ * @param LOWERCASE:identifier The keyword, for the node type, in lower case * @param UPPERCASE:identifier The keyword, for the node type, in upper case */ -#define NEW_SUBNODE(LOWERCASE, UPPERCASE) \ - mds_kbdc_tree_##LOWERCASE##_t* subnode; \ - fail_if (xcalloc(subnode, 1, mds_kbdc_tree_##LOWERCASE##_t)); \ - subnode->type = MDS_KBDC_TREE_TYPE_##UPPERCASE; \ - subnode->loc_line = line_i; \ - subnode->loc_start = (size_t)(line - LINE); \ - subnode->loc_end = (size_t)(end - LINE) +#define NEW_SUBNODE(LOWERCASE, UPPERCASE)\ + mds_kbdc_tree_##LOWERCASE##_t *subnode;\ + fail_if (xcalloc(subnode, 1, mds_kbdc_tree_##LOWERCASE##_t));\ + subnode->type = MDS_KBDC_TREE_TYPE_##UPPERCASE;\ + subnode->loc_line = line_i;\ + subnode->loc_start = (size_t)(line - LINE);\ + subnode->loc_end = (size_t)(end - LINE) /** @@ -142,10 +140,10 @@ * * @param KEYWORD:const char* The keyword for the current node's type */ -#define BRANCH(KEYWORD) \ - (*(tree_stack[stack_ptr]) = (mds_kbdc_tree_t*)node, \ - tree_stack[stack_ptr + 1] = &(node->inner), \ - keyword_stack[stack_ptr++] = KEYWORD) +#define BRANCH(KEYWORD)\ + (*(tree_stack[stack_ptr]) = (mds_kbdc_tree_t *)node,\ + tree_stack[stack_ptr + 1] = &(node->inner),\ + keyword_stack[stack_ptr++] = KEYWORD) /** @@ -156,9 +154,9 @@ * This is what should be done when a leaf node has been * created and should be added to the result tree */ -#define LEAF \ - (*(tree_stack[stack_ptr]) = (mds_kbdc_tree_t*)node, \ - NEXT) +#define LEAF\ + (*(tree_stack[stack_ptr]) = (mds_kbdc_tree_t*)node,\ + NEXT) /** @@ -166,9 +164,9 @@ * * @param var:const char* The variable */ -#define SKIP_SPACES(var) \ - while (*var && (*var == ' ')) \ - var++ +#define SKIP_SPACES(var)\ + while (*var && *var == ' ')\ + var++ /** @@ -176,8 +174,8 @@ * * @param KEYWORD:const char* The keyword */ -#define NO_PARAMETERS(KEYWORD) \ - fail_if (no_parameters(KEYWORD)) +#define NO_PARAMETERS(KEYWORD)\ + fail_if (no_parameters(KEYWORD)) /** @@ -187,18 +185,18 @@ * @param var:identifier The name of the member variable, for the current * node, where the parameter should be stored */ -#define NAMES_1(var) \ - fail_if (names_1(&(node->var))) +#define NAMES_1(var)\ + fail_if (names_1(&node->var)) /** * Suppress the next `line = STREND(line)` */ -#define NO_JUMP \ - (*end = prev_end_char, \ - end = line, \ - prev_end_char = *end, \ - *end = '\0') +#define NO_JUMP\ + (*end = prev_end_char,\ + end = line,\ + prev_end_char = *end,\ + *end = '\0') /** @@ -206,8 +204,8 @@ * * @param c:char The character */ -#define IS_END(c) \ - strchr(" >}])", c) +#define IS_END(c)\ + strchr(" >}])", c) /** @@ -217,31 +215,28 @@ * @param var:identifier The name of the member variable, for the current * node, where the parameter should be stored */ -#define CHARS(var) \ - fail_if (chars(&(node->var))) +#define CHARS(var)\ + fail_if (chars(&node->var)) /** * Test that there are no more parameters */ -#define END \ - do \ - { \ - SKIP_SPACES(line); \ - if (*line) \ - { \ - NEW_ERROR(1, ERROR, "too many parameters"); \ - error->end = strlen(LINE); \ - } \ - } \ - while (0) +#define END\ + do {\ + SKIP_SPACES(line);\ + if (*line) {\ + NEW_ERROR(1, ERROR, "too many parameters");\ + error->end = strlen(LINE);\ + }\ + } while (0) /** * Test that the next parameter is in quotes */ -#define QUOTES \ - fail_if (quotes()) +#define QUOTES\ + fail_if (quotes()) /** @@ -251,14 +246,12 @@ * @param var:identifier The name of the member variable, for the current * node, where the parameter should be stored */ -#define QUOTES_1(var) \ - do \ - { \ - QUOTES; \ - CHARS(var); \ - END; \ - } \ - while (0) +#define QUOTES_1(var)\ + do {\ + QUOTES;\ + CHARS(var);\ + END;\ + } while (0) /** @@ -266,8 +259,8 @@ * * @param KEYWORD:const char* The keyword */ -#define TEST_FOR_KEYWORD(KEYWORD) \ - fail_if (test_for_keyword(KEYWORD)) +#define TEST_FOR_KEYWORD(KEYWORD)\ + fail_if (test_for_keyword(KEYWORD)) /** @@ -277,8 +270,8 @@ * @param var:identifier The name of the member variable, for the current * node, where the parameter should be stored */ -#define KEYS(var) \ - fail_if (keys(&(node->var))) +#define KEYS(var)\ + fail_if (keys(&node->var)) /** @@ -288,8 +281,8 @@ * @param var:identifier The name of the member variable, for the current * node, where the parameter should be stored */ -#define PURE_KEYS(var) \ - fail_if (pure_keys(&(node->var))) +#define PURE_KEYS(var)\ + fail_if (pure_keys(&node->var)) @@ -299,23 +292,21 @@ * @param mapseq:int Whether this is a mapping sequence, otherwise * it is treated as macro call arguments */ -#define SEQUENCE(mapseq) \ - do /* for(;;) */ \ - { \ - *end = prev_end_char; \ - SKIP_SPACES(line); \ - if ((*line == '\0') || (*line == (mapseq ? ':' : ')'))) \ - break; \ - fail_if (sequence(mapseq, stack_orig)); \ - } \ - while (1) +#define SEQUENCE(mapseq)\ + do /* for(;;) */ {\ + *end = prev_end_char;\ + SKIP_SPACES(line);\ + if (!*line || *line == (mapseq ? ':' : ')'))\ + break;\ + fail_if (sequence(mapseq, stack_orig));\ + } while (1) /** * Check that the scopes created in `SEQUENCE` has all been popped */ -#define SEQUENCE_FULLY_POPPED \ - fail_if (sequence_fully_popped(stack_orig)) +#define SEQUENCE_FULLY_POPPED\ + fail_if (sequence_fully_popped(stack_orig)) /** @@ -325,14 +316,12 @@ * @param UPPERCASE:identifier The keyword, for the node type, in upper case * @param PARSE:expression Statement, without final semicolon, to retrieve members */ -#define MAKE_LEAF(LOWERCASE, UPPERCASE, PARSE) \ - do \ - { \ - NEW_NODE(LOWERCASE, UPPERCASE); \ - PARSE; \ - LEAF; \ - } \ - while (0) +#define MAKE_LEAF(LOWERCASE, UPPERCASE, PARSE)\ + do {\ + NEW_NODE(LOWERCASE, UPPERCASE);\ + PARSE;\ + LEAF;\ + } while (0) /** @@ -342,26 +331,24 @@ * @param UPPERCASE:identifier The keyword, for the node type, in upper case * @param PARSE:expression Statement, without final semicolon, to retrieve members */ -#define MAKE_BRANCH(LOWERCASE, UPPERCASE, PARSE) \ - do \ - { \ - NEW_NODE(LOWERCASE, UPPERCASE); \ - PARSE; \ - BRANCH(#LOWERCASE); \ - } \ - while (0) +#define MAKE_BRANCH(LOWERCASE, UPPERCASE, PARSE)\ + do {\ + NEW_NODE(LOWERCASE, UPPERCASE);\ + PARSE;\ + BRANCH(#LOWERCASE);\ + } while (0) /** * Variable whether the latest created error is stored */ -static mds_kbdc_parse_error_t* error; +static mds_kbdc_parse_error_t *error; /** * Output parameter for the parsing result */ -static mds_kbdc_parsed_t* restrict result; +static mds_kbdc_parsed_t *restrict result; /** * The head of the parsing-stack @@ -371,12 +358,12 @@ static size_t stack_ptr; /** * The keyword portion of the parsing-stack */ -static const char** restrict keyword_stack; +static const char **restrict keyword_stack; /** * The tree portion of the parsing-stack */ -static mds_kbdc_tree_t*** restrict tree_stack; +static mds_kbdc_tree_t ***restrict tree_stack; /** * The index of the currently parsed line @@ -392,12 +379,12 @@ static int in_array; * The beginning of what has not get been parsed * on the current line */ -static char* line = NULL; +static char *line = NULL; /** * The end of what has been parsed on the current line */ -static char* end = NULL; +static char *end = NULL; /** * The previous value of `*end` @@ -408,7 +395,7 @@ static char prev_end_char; * Pointer to the first non-whitespace character * on the current line */ -static char* original; +static char *original; /** * Whether it has been identified that the @@ -427,40 +414,39 @@ static int too_few; * @param filename The filename of the parsed file * @return The value the caller should return, or 1 if the caller should not return, -1 on error */ -static int get_pathname(const char* restrict filename) +static int +get_pathname(const char *restrict filename) { - char* cwd = NULL; - int saved_errno; - - /* Get a non-relative pathname for the file, relative filenames - * can be misleading as the program can have changed working - * directory to be able to resolve filenames. */ - result->pathname = abspath(filename); - if (result->pathname == NULL) - { - fail_if (errno != ENOENT); - saved_errno = errno; - fail_if (cwd = curpath(), cwd == NULL); - fail_if (xstrdup(result->pathname, filename)); - NEW_ERROR_(result, ERROR, 0, 0, 0, 0, 1, "no such file or directory in ‘%s’", cwd); - free(cwd); - return 0; - } - - /* Check that the file exists and can be read. */ - if (access(result->pathname, R_OK) < 0) - { - saved_errno = errno; - NEW_ERROR_(result, ERROR, 0, 0, 0, 0, 0, NULL); - fail_if (xstrdup(error->description, strerror(saved_errno))); - return 0; - } - - return 1; - fail: - saved_errno = errno; - free(cwd); - return errno = saved_errno, -1; + char *cwd = NULL; + int saved_errno; + + /* Get a non-relative pathname for the file, relative filenames + * can be misleading as the program can have changed working + * directory to be able to resolve filenames. */ + result->pathname = abspath(filename); + if (!result->pathname) { + fail_if (errno != ENOENT); + saved_errno = errno; + fail_if (!(cwd = curpath())); + fail_if (xstrdup(result->pathname, filename)); + NEW_ERROR_(result, ERROR, 0, 0, 0, 0, 1, "no such file or directory in ‘%s’", cwd); + free(cwd); + return 0; + } + + /* Check that the file exists and can be read. */ + if (access(result->pathname, R_OK) < 0) { + saved_errno = errno; + NEW_ERROR_(result, ERROR, 0, 0, 0, 0, 0, NULL); + fail_if (xstrdup(error->description, strerror(saved_errno))); + return 0; + } + + return 1; +fail: + saved_errno = errno; + free(cwd); + return errno = saved_errno, -1; } @@ -469,25 +455,25 @@ static int get_pathname(const char* restrict filename) * * @return Zero on success, -1 on error */ -static int allocate_stacks(void) +static int +allocate_stacks(void) { - size_t max_line_length = 0, cur_line_length, line_n; - - /* The maximum line-length is needed because lines can have there own stacking, - * like sequence mapping lines, additionally, let statements can have one array. */ - for (line_i = 0, line_n = result->source_code->line_count; line_i < line_n; line_i++) - { - cur_line_length = strlen(LINE); - if (max_line_length < cur_line_length) - max_line_length = cur_line_length; - } - - fail_if (xmalloc(keyword_stack, line_n + max_line_length, const char*)); - fail_if (xmalloc(tree_stack, line_n + max_line_length + 1, mds_kbdc_tree_t**)); - - return 0; - fail: - return -1; + size_t max_line_length = 0, cur_line_length, line_n; + + /* The maximum line-length is needed because lines can have there own stacking, + * like sequence mapping lines, additionally, let statements can have one array. */ + for (line_i = 0, line_n = result->source_code->line_count; line_i < line_n; line_i++) { + cur_line_length = strlen(LINE); + if (max_line_length < cur_line_length) + max_line_length = cur_line_length; + } + + fail_if (xmalloc(keyword_stack, line_n + max_line_length, const char*)); + fail_if (xmalloc(tree_stack, line_n + max_line_length + 1, mds_kbdc_tree_t**)); + + return 0; +fail: + return -1; } @@ -496,14 +482,15 @@ static int allocate_stacks(void) * * @return Zero on success, -1 on error */ -static int read_source_code(void) +static int +read_source_code(void) { - /* Read the file and simplify it a bit. */ - fail_if (read_source_lines(result->pathname, result->source_code) < 0); - - return 0; - fail: - return -1; + /* Read the file and simplify it a bit. */ + fail_if (read_source_lines(result->pathname, result->source_code) < 0); + + return 0; +fail: + return -1; } @@ -517,34 +504,32 @@ static int read_source_code(void) * * @return Zero on success, -1 on error */ -static int check_for_premature_end_of_file(void) +static int +check_for_premature_end_of_file(void) { - /* Check that all scopes have been popped. */ - if (stack_ptr) - { - while (stack_ptr && keyword_stack[stack_ptr - 1] == NULL) - stack_ptr--; - if (stack_ptr) - { - NEW_ERROR(0, ERROR, "premature end of file"); - while (stack_ptr--) - { - if (keyword_stack[stack_ptr] == NULL) - continue; - line_i = tree_stack[stack_ptr][0]->loc_line; - line = LINE + tree_stack[stack_ptr][0]->loc_start; - end = LINE + tree_stack[stack_ptr][0]->loc_end; - if (!strcmp(keyword_stack[stack_ptr], "}")) - NEW_ERROR(1, NOTE, "missing associated ‘%s’", keyword_stack[stack_ptr]); - else - NEW_ERROR(1, NOTE, "missing associated ‘end %s’", keyword_stack[stack_ptr]); - } + /* Check that all scopes have been popped. */ + if (stack_ptr) { + while (stack_ptr && !keyword_stack[stack_ptr - 1]) + stack_ptr--; + if (stack_ptr) { + NEW_ERROR(0, ERROR, "premature end of file"); + while (stack_ptr--) { + if (!keyword_stack[stack_ptr]) + continue; + line_i = tree_stack[stack_ptr][0]->loc_line; + line = LINE + tree_stack[stack_ptr][0]->loc_start; + end = LINE + tree_stack[stack_ptr][0]->loc_end; + if (!strcmp(keyword_stack[stack_ptr], "}")) + NEW_ERROR(1, NOTE, "missing associated ‘%s’", keyword_stack[stack_ptr]); + else + NEW_ERROR(1, NOTE, "missing associated ‘end %s’", keyword_stack[stack_ptr]); + } + } } - } - - return 0; - fail: - return -1; + + return 0; +fail: + return -1; } @@ -555,16 +540,16 @@ static int check_for_premature_end_of_file(void) * * @return Zero on success, -1 on error */ -static int check_whether_file_is_empty(void) +static int +check_whether_file_is_empty(void) { - /* Warn about empty files. */ - if (result->tree == NULL) - if (result->errors_ptr == 0) - NEW_ERROR(0, WARNING, "file is empty"); - - return 0; - fail: - return -1; + /* Warn about empty files. */ + if (!result->tree && !result->errors_ptr) + NEW_ERROR(0, WARNING, "file is empty"); + + return 0; +fail: + return -1; } @@ -578,20 +563,20 @@ static int check_whether_file_is_empty(void) * @param keyword The keyword * @return Zero on success, -1 on error */ -static int no_parameters(const char* restrict keyword) +static int +no_parameters(const char *restrict keyword) { - line = STREND(line); - *end = prev_end_char, prev_end_char = '\0'; - SKIP_SPACES(line); - if (*line) - { - end = STREND(line); - NEW_ERROR(1, ERROR, "extra token after ‘%s’", keyword); - } - - return 0; - fail: - return -1; + line = STREND(line); + *end = prev_end_char, prev_end_char = '\0'; + SKIP_SPACES(line); + if (*line) { + end = STREND(line); + NEW_ERROR(1, ERROR, "extra token after ‘%s’", keyword); + } + + return 0; +fail: + return -1; } @@ -604,55 +589,51 @@ static int no_parameters(const char* restrict keyword) * node, where the parameter should be stored * @return Zero on success, -1 on error */ -static int names_1(char** restrict var) +static int +names_1(char **restrict var) { - char* name_end; - char* test; - int stray_char = 0; - char* end_end; - - line = STREND(line); - *end = prev_end_char, prev_end_char = '\0'; - SKIP_SPACES(line); - if (*line == '\0') - { - line = original, end = STREND(line); - NEW_ERROR(1, ERROR, "a name is expected"); - } - else - { - name_end = line; - while (*name_end && is_name_char(*name_end)) - name_end++; - if (*name_end && (*name_end != ' ')) - { - end_end = name_end + 1; - while ((*end_end & 0xC0) == 0x80) - end_end++; - prev_end_char = *end_end, *end_end = '\0'; - NEW_ERROR(1, ERROR, "stray ‘%s’ character", name_end); - error->start = (size_t)(name_end - LINE); - error->end = (size_t)(end_end - LINE); - *end_end = prev_end_char; - stray_char = 1; + char *name_end; + char *test; + int stray_char = 0; + char *end_end; + + line = STREND(line); + *end = prev_end_char, prev_end_char = '\0'; + SKIP_SPACES(line); + if (!*line) { + line = original, end = STREND(line); + NEW_ERROR(1, ERROR, "a name is expected"); + } else { + name_end = line; + while (*name_end && is_name_char(*name_end)) + name_end++; + if (*name_end && (*name_end != ' ')) { + end_end = name_end + 1; + while ((*end_end & 0xC0) == 0x80) + end_end++; + prev_end_char = *end_end, *end_end = '\0'; + NEW_ERROR(1, ERROR, "stray ‘%s’ character", name_end); + error->start = (size_t)(name_end - LINE); + error->end = (size_t)(end_end - LINE); + *end_end = prev_end_char; + stray_char = 1; + } + test = name_end; + SKIP_SPACES(test); + if (*test && !stray_char) { + NEW_ERROR(1, ERROR, "too many parameters"); + error->start = (size_t)(test - LINE); + error->end = strlen(LINE); + } + end = name_end; + prev_end_char = *end; + *end = '\0'; + fail_if (xstrdup(*var, line)); } - test = name_end; - SKIP_SPACES(test); - if (*test && !stray_char) - { - NEW_ERROR(1, ERROR, "too many parameters"); - error->start = (size_t)(test - LINE); - error->end = strlen(LINE); - } - end = name_end; - prev_end_char = *end; - *end = '\0'; - fail_if (xstrdup(*var, line)); - } - - return 0; - fail: - return -1; + + return 0; +fail: + return -1; } @@ -664,46 +645,49 @@ static int names_1(char** restrict var) * node, where the parameter should be stored * @return Zero on success, -1 on error */ -static int chars(char** restrict var) +static int +chars(char **restrict var) { - if (too_few) - return 0; - line = STREND(line); - *end = prev_end_char, prev_end_char = '\0'; - SKIP_SPACES(line); - if (*line == '\0') - { - line = original, end = STREND(line); - NEW_ERROR(1, ERROR, "too few parameters"); - line = end, too_few = 1; - } - else - { - char* arg_end = line; - char* call_end = arg_end; - int escape = 0, quote = 0; - while (*arg_end) - { - char c = *arg_end++; - if (escape) escape = 0; - else if (arg_end <= call_end) ; - else if (c == '\\') - { - escape = 1; - call_end = arg_end + get_end_of_call(arg_end, 0, strlen(arg_end)); - } - else if (quote) quote = (c != '"'); - else if (IS_END(c)) { arg_end--; break; } - else quote = (c == '"'); + char *arg_end, *call_end, c; + int escape, quote; + if (too_few) + return 0; + line = STREND(line); + *end = prev_end_char, prev_end_char = '\0'; + SKIP_SPACES(line); + if (!*line) { + line = original, end = STREND(line); + NEW_ERROR(1, ERROR, "too few parameters"); + line = end, too_few = 1; + } else { + arg_end = line; + call_end = arg_end; + escape = quote = 0; + while (*arg_end) { + c = *arg_end++; + if (escape) { + escape = 0; + } else if (arg_end <= call_end) { ; + } else if (c == '\\') { + escape = 1; + call_end = arg_end + get_end_of_call(arg_end, 0, strlen(arg_end)); + } else if (quote) { + quote = c != '"'; + } else if (IS_END(c)) { + arg_end--; + break; + } else { + quote = c == '"'; + } + } + prev_end_char = *arg_end, *arg_end = '\0', end = arg_end; + fail_if (xstrdup(*var, line)); + line = end; } - prev_end_char = *arg_end, *arg_end = '\0', end = arg_end; - fail_if (xstrdup(*var, line)); - line = end; - } - - return 0; - fail: - return -1; + + return 0; +fail: + return -1; } @@ -712,25 +696,25 @@ static int chars(char** restrict var) * * @return Zero on success, -1 on error */ -static int quotes(void) +static int +quotes(void) { - char* line_ = line; - line = STREND(line); - *end = prev_end_char; - SKIP_SPACES(line); - if (*line && (*line != '"')) - { - char* arg_end = line; - SKIP_SPACES(arg_end); - NEW_ERROR(1, ERROR, "parameter must be in quotes"); - error->end = (size_t)(arg_end - LINE); - } - *end = '\0'; - line = line_; - - return 0; - fail: - return -1; + char *line_ = line, *arg_end; + line = STREND(line); + *end = prev_end_char; + SKIP_SPACES(line); + if (*line && *line != '"') { + arg_end = line; + SKIP_SPACES(arg_end); + NEW_ERROR(1, ERROR, "parameter must be in quotes"); + error->end = (size_t)(arg_end - LINE); + } + *end = '\0'; + line = line_; + + return 0; +fail: + return -1; } @@ -739,23 +723,23 @@ static int quotes(void) * * @return Whether the currently line has unparsed parameters, -1 on error */ -static int have_more_parameters(void) +static int +have_more_parameters(void) { - if (too_few) - return 0; - line = STREND(line); - *end = prev_end_char, prev_end_char = '\0'; - SKIP_SPACES(line); - if (*line == '\0') - { - line = original, end = STREND(line); - NEW_ERROR(1, ERROR, "too few parameters"); - line = end, too_few = 1; - return 0; - } - return 1; - fail: - return -1; + if (too_few) + return 0; + line = STREND(line); + *end = prev_end_char, prev_end_char = '\0'; + SKIP_SPACES(line); + if (!*line) { + line = original, end = STREND(line); + NEW_ERROR(1, ERROR, "too few parameters"); + line = end, too_few = 1; + return 0; + } + return 1; +fail: + return -1; } @@ -765,32 +749,33 @@ static int have_more_parameters(void) * @param keyword The keyword * @return Zero on success, -1 on error */ -static int test_for_keyword(const char* restrict keyword) +static int +test_for_keyword(const char *restrict keyword) { - int ok, r = have_more_parameters(); - fail_if (r < 0); - if (r == 0) - return 0; - - ok = (strstr(line, keyword) == line); - line += strlen(keyword); - ok = ok && ((*line == '\0') || (*line == ' ')); - if (ok) - { - end = line; - prev_end_char = *end, *end = '\0'; - return 0; - } - line -= strlen(keyword); - end = line; - SKIP_SPACES(end); - prev_end_char = *end, *end = '\0'; - NEW_ERROR(1, ERROR, "expecting keyword ‘%s’", keyword); - error->end = error->start + 1; - - return 0; - fail: - return -1; + int ok, r = have_more_parameters(); + fail_if (r < 0); + if (!r) + return 0; + + ok = (strstr(line, keyword) == line); + line += strlen(keyword); + ok = ok && (!*line || *line == ' '); + if (ok) { + end = line; + prev_end_char = *end; + *end = '\0'; + return 0; + } + line -= strlen(keyword); + end = line; + SKIP_SPACES(end); + prev_end_char = *end, *end = '\0'; + NEW_ERROR(1, ERROR, "expecting keyword ‘%s’", keyword); + error->end = error->start + 1; + + return 0; +fail: + return -1; } @@ -802,52 +787,53 @@ static int test_for_keyword(const char* restrict keyword) * node, where the parameter should be stored * @return Zero on success, -1 on error */ -static int keys(mds_kbdc_tree_t** restrict var) +static int +keys(mds_kbdc_tree_t **restrict var) { - char* arg_end; - char* call_end; - int r, escape = 0, quote = 0, triangle; - r = have_more_parameters(); - fail_if (r < 0); - if (r == 0) - return 0; - - arg_end = line; - call_end = arg_end; - triangle = (*arg_end == '<'); - while (*arg_end) - { - char c = *arg_end++ ; - if (escape) escape = 0; - else if (arg_end <= call_end) ; - else if (c == '\\') - { - escape = 1; - call_end = arg_end + get_end_of_call(arg_end, 0, strlen(arg_end)); + char *arg_end, *call_end, c; + int r, escape = 0, quote = 0, triangle; + r = have_more_parameters(); + fail_if (r < 0); + if (!r) + return 0; + + arg_end = line; + call_end = arg_end; + triangle = *arg_end == '<'; + while (*arg_end) { + c = *arg_end++; + if (escape) { + escape = 0; + } else if (arg_end <= call_end) { ; + } else if (c == '\\') { + escape = 1; + call_end = arg_end + get_end_of_call(arg_end, 0, strlen(arg_end)); + } else if (quote) { + quote = c != '"'; + } else if (c == '\"') { + quote = 1; + } else if (c == '>') { + triangle = 0; + } else if (IS_END(c) && !triangle) { + arg_end--; + break; + } } - else if (quote) quote = (c != '"'); - else if (c == '\"') quote = 1; - else if (c == '>') triangle = 0; - else if (IS_END(c) && !triangle) { arg_end--; break; } - } - prev_end_char = *arg_end, *arg_end = '\0', end = arg_end; - if (*line == '<') - { - NEW_SUBNODE(keys, KEYS); - *var = (mds_kbdc_tree_t*)subnode; - fail_if (xstrdup(subnode->keys, line)); - } - else - { - NEW_SUBNODE(string, STRING); - *var = (mds_kbdc_tree_t*)subnode; - fail_if (xstrdup(subnode->string, line)); - } - line = end; - - return 0; - fail: - return -1; + prev_end_char = *arg_end, *arg_end = '\0', end = arg_end; + if (*line == '<') { + NEW_SUBNODE(keys, KEYS); + *var = (mds_kbdc_tree_t *)subnode; + fail_if (xstrdup(subnode->keys, line)); + } else { + NEW_SUBNODE(string, STRING); + *var = (mds_kbdc_tree_t *)subnode; + fail_if (xstrdup(subnode->string, line)); + } + line = end; + + return 0; +fail: + return -1; } @@ -860,41 +846,45 @@ static int keys(mds_kbdc_tree_t** restrict var) * node, where the parameter should be stored * @return Zero on success, -1 on error */ -static int pure_keys(char** restrict var) +static int +pure_keys(char **restrict var) { - char* arg_end; - char* call_end; - int r, escape = 0, quote = 0, triangle; - r = have_more_parameters(); - fail_if (r < 0); - if (r == 0) - return 0; - - arg_end = line; - call_end = arg_end; - triangle = (*arg_end == '<'); - while (*arg_end) - { - char c = *arg_end++ ; - if (escape) escape = 0; - else if (arg_end <= call_end) ; - else if (c == '\\') - { - escape = 1; - call_end = arg_end + get_end_of_call(arg_end, 0, strlen(arg_end)); + char *arg_end, *call_end, c; + int r, escape = 0, quote = 0, triangle; + r = have_more_parameters(); + fail_if (r < 0); + if (!r) + return 0; + + arg_end = line; + call_end = arg_end; + triangle = *arg_end == '<'; + while (*arg_end) { + c = *arg_end++; + if (escape) { + escape = 0; + } else if (arg_end <= call_end) { ; + } else if (c == '\\') { + escape = 1; + call_end = arg_end + get_end_of_call(arg_end, 0, strlen(arg_end)); + } else if (quote) { + quote = c != '"'; + } else if (c == '\"') { + quote = 1; + } else if (c == '>') { + triangle = 0; + } else if (IS_END(c) && !triangle) { + arg_end--; + break; + } } - else if (quote) quote = (c != '"'); - else if (c == '\"') quote = 1; - else if (c == '>') triangle = 0; - else if (IS_END(c) && !triangle) { arg_end--; break; } - } - prev_end_char = *arg_end, *arg_end = '\0'; - fail_if (xstrdup(*var, line)); - end = arg_end, line = end; - - return 0; - fail: - return -1; + prev_end_char = *arg_end, *arg_end = '\0'; + fail_if (xstrdup(*var, line)); + end = arg_end, line = end; + + return 0; +fail: + return -1; } @@ -906,65 +896,54 @@ static int pure_keys(char** restrict var) * @param stack_orig The size of the stack when `SEQUENCE` was called * @return Zero on success, -1 on error */ -static int sequence(int mapseq, size_t stack_orig) +static int +sequence(int mapseq, size_t stack_orig) { - if (mapseq && (*line == '(')) - { - NEW_NODE(unordered, UNORDERED); - node->loc_end = node->loc_start + 1; - BRANCH(")"); - line++; - } - else if (*line == '[') - { - NEW_NODE(alternation, ALTERNATION); - node->loc_end = node->loc_start + 1; - BRANCH("]"); - line++; - } - else if (*line == '.') - { - NEW_NODE(nothing, NOTHING); - node->loc_end = node->loc_start + 1; - LEAF; - line++; - } - else if (strchr("])", *line)) - { - end = line + 1; - prev_end_char = *end, *end = '\0'; - if (stack_ptr == stack_orig) - NEW_ERROR(1, ERROR, "runaway ‘%s’", line); - else - { - stack_ptr--; - if (strcmp(line, keyword_stack[stack_ptr])) - NEW_ERROR(1, ERROR, "expected ‘%s’ but got ‘%s’", keyword_stack[stack_ptr], line); - NEXT; + if (mapseq && *line == '(') { + NEW_NODE(unordered, UNORDERED); + node->loc_end = node->loc_start + 1; + BRANCH(")"); + line++; + } else if (*line == '[') { + NEW_NODE(alternation, ALTERNATION); + node->loc_end = node->loc_start + 1; + BRANCH("]"); + line++; + } else if (*line == '.') { + NEW_NODE(nothing, NOTHING); + node->loc_end = node->loc_start + 1; + LEAF; + line++; + } else if (strchr("])", *line)) { + end = line + 1; + prev_end_char = *end, *end = '\0'; + if (stack_ptr == stack_orig) { + NEW_ERROR(1, ERROR, "runaway ‘%s’", line); + } else { + stack_ptr--; + if (strcmp(line, keyword_stack[stack_ptr])) + NEW_ERROR(1, ERROR, "expected ‘%s’ but got ‘%s’", keyword_stack[stack_ptr], line); + NEXT; + } + *end = prev_end_char; + line++; + } else if (*line == '<') { + NEW_NODE(keys, KEYS); + NO_JUMP; + PURE_KEYS(keys); + LEAF; + node->loc_end = (size_t)(line - LINE); + } else { + NEW_NODE(string, STRING); + NO_JUMP; + CHARS(string); + LEAF; + node->loc_end = (size_t)(line - LINE); } - *end = prev_end_char; - line++; - } - else if (*line == '<') - { - NEW_NODE(keys, KEYS); - NO_JUMP; - PURE_KEYS(keys); - LEAF; - node->loc_end = (size_t)(line - LINE); - } - else - { - NEW_NODE(string, STRING); - NO_JUMP; - CHARS(string); - LEAF; - node->loc_end = (size_t)(line - LINE); - } - - return 0; + + return 0; fail: - return -1; + return -1; } @@ -973,23 +952,23 @@ static int sequence(int mapseq, size_t stack_orig) * * @param stack_orig The size of the stack when `SEQUENCE` was called */ -static int sequence_fully_popped(size_t stack_orig) +static int +sequence_fully_popped(size_t stack_orig) { - if (stack_ptr == stack_orig) - return 0; - end = line + 1; - NEW_ERROR(1, ERROR, "premature end of sequence"); - while (stack_ptr > stack_orig) - { - stack_ptr--; - NEW_ERROR(1, NOTE, "missing associated ‘%s’", keyword_stack[stack_ptr]); - error->start = tree_stack[stack_ptr][0]->loc_start; - error->end = tree_stack[stack_ptr][0]->loc_end; - } - - return 0; - fail: - return -1; + if (stack_ptr == stack_orig) + return 0; + end = line + 1; + NEW_ERROR(1, ERROR, "premature end of sequence"); + while (stack_ptr > stack_orig) { + stack_ptr--; + NEW_ERROR(1, NOTE, "missing associated ‘%s’", keyword_stack[stack_ptr]); + error->start = tree_stack[stack_ptr][0]->loc_start; + error->end = tree_stack[stack_ptr][0]->loc_end; + } + + return 0; +fail: + return -1; } @@ -1002,62 +981,54 @@ static int sequence_fully_popped(size_t stack_orig) * * @return Zero on success, -1 on error, 1 if the caller should go to `redo` */ -static int parse_else(void) +static int +parse_else(void) { - size_t i; - if (stack_ptr == 0) - { - NEW_ERROR(1, ERROR, "runaway ‘else’ statement"); - return 0; - } - line = STREND(line); - *end = prev_end_char, prev_end_char = '\0'; - end = STREND(line); - SKIP_SPACES(line); - i = stack_ptr - 1; - while (keyword_stack[i] == NULL) - i--; - if (strcmp(keyword_stack[i], "if")) - { - stack_ptr--; - line = original, end = STREND(line); - NEW_ERROR(1, ERROR, "runaway ‘else’ statement"); - } - else if (*line == '\0') - { - /* else */ - mds_kbdc_tree_if_t* supernode = &(tree_stack[stack_ptr - 1][0]->if_); - if (supernode->otherwise) - { - line = strstr(LINE, "else"); - end = line + 4, prev_end_char = *end; - NEW_ERROR(1, ERROR, "multiple ‘else’ statements"); - mds_kbdc_tree_free(supernode->otherwise); - supernode->otherwise = NULL; + size_t i; + if (!stack_ptr) { + NEW_ERROR(1, ERROR, "runaway ‘else’ statement"); + return 0; } - tree_stack[stack_ptr] = &(supernode->otherwise); - } - else if ((strstr(line, "if") == line) && ((line[2] == ' ') || (line[2] == '\0'))) - { - /* else if */ - mds_kbdc_tree_if_t* supernode = &(tree_stack[stack_ptr - 1][0]->if_); - NEW_NODE(if, IF); - node->loc_end = node->loc_start + 2; - end = line += 2, prev_end_char = *end, *end = '\0'; - CHARS(condition); - END; - tree_stack[stack_ptr] = &(supernode->otherwise); - BRANCH(NULL); - } - else - { - NEW_ERROR(1, ERROR, "expecting nothing or ‘if’"); - stack_ptr--; - } - - return 0; - fail: - return -1; + line = STREND(line); + *end = prev_end_char, prev_end_char = '\0'; + end = STREND(line); + SKIP_SPACES(line); + i = stack_ptr - 1; + while (!keyword_stack[i]) + i--; + if (strcmp(keyword_stack[i], "if")) { + stack_ptr--; + line = original, end = STREND(line); + NEW_ERROR(1, ERROR, "runaway ‘else’ statement"); + } else if (!*line) { + /* else */ + mds_kbdc_tree_if_t *supernode = &tree_stack[stack_ptr - 1][0]->if_; + if (supernode->otherwise) { + line = strstr(LINE, "else"); + end = line + 4, prev_end_char = *end; + NEW_ERROR(1, ERROR, "multiple ‘else’ statements"); + mds_kbdc_tree_free(supernode->otherwise); + supernode->otherwise = NULL; + } + tree_stack[stack_ptr] = &supernode->otherwise; + } else if (strstr(line, "if") == line && (line[2] == ' ' || !line[2])) { + /* else if */ + mds_kbdc_tree_if_t *supernode = &tree_stack[stack_ptr - 1][0]->if_; + NEW_NODE(if, IF); + node->loc_end = node->loc_start + 2; + end = line += 2, prev_end_char = *end, *end = '\0'; + CHARS(condition); + END; + tree_stack[stack_ptr] = &(supernode->otherwise); + BRANCH(NULL); + } else { + NEW_ERROR(1, ERROR, "expecting nothing or ‘if’"); + stack_ptr--; + } + + return 0; +fail: + return -1; } @@ -1066,20 +1037,21 @@ static int parse_else(void) * * @return Zero on success, -1 on error, 1 if the caller should go to `redo` */ -static int parse_for(void) +static int +parse_for(void) { - NEW_NODE(for, FOR); - CHARS(first); - TEST_FOR_KEYWORD("to"); - CHARS(last); - TEST_FOR_KEYWORD("as"); - CHARS(variable); - END; - BRANCH("for"); - - return 0; - fail: - return -1; + NEW_NODE(for, FOR); + CHARS(first); + TEST_FOR_KEYWORD("to"); + CHARS(last); + TEST_FOR_KEYWORD("as"); + CHARS(variable); + END; + BRANCH("for"); + + return 0; +fail: + return -1; } @@ -1088,52 +1060,48 @@ static int parse_for(void) * * @return Zero on success, -1 on error, 1 if the caller should go to `redo` */ -static int parse_let(void) +static int +parse_let(void) { - NEW_NODE(let, LET); - CHARS(variable); - TEST_FOR_KEYWORD(":"); - *end = prev_end_char; - SKIP_SPACES(line); - if (*line == '{') + NEW_NODE(let, LET); + CHARS(variable); + TEST_FOR_KEYWORD(":"); + *end = prev_end_char; + SKIP_SPACES(line); + if (*line == '{') #define inner value - BRANCH(NULL); + BRANCH(NULL); #undef inner - else - LEAF; - if (*line == '\0') - { - line = original, end = STREND(line), prev_end_char = '\0'; - NEW_ERROR(1, ERROR, "too few parameters"); - } - else if (*line != '{') - { + else + LEAF; + if (!*line) { + line = original, end = STREND(line), prev_end_char = '\0'; + NEW_ERROR(1, ERROR, "too few parameters"); + } else if (*line != '{') { #define node subnode - NEW_NODE(string, STRING); - NO_JUMP; - CHARS(string); - node->loc_end = (size_t)(end - LINE); + NEW_NODE(string, STRING); + NO_JUMP; + CHARS(string); + node->loc_end = (size_t)(end - LINE); #undef node - node->value = (mds_kbdc_tree_t*)subnode; - END; - } - else - { + node->value = (mds_kbdc_tree_t*)subnode; + END; + } else { #define node subnode #define inner elements - NEW_NODE(array, ARRAY); - BRANCH("}"); - node->loc_end = node->loc_start + 1; + NEW_NODE(array, ARRAY); + BRANCH("}"); + node->loc_end = node->loc_start + 1; #undef inner #undef node - in_array = 1; - line++; - return 1; - } - - return 0; - fail: - return -1; + in_array = 1; + line++; + return 1; + } + + return 0; +fail: + return -1; } @@ -1142,29 +1110,28 @@ static int parse_let(void) * * @return Zero on success, -1 on error, 1 if the caller should go to `redo` */ -static int parse_end(void) +static int +parse_end(void) { - if (stack_ptr == 0) - { - NEW_ERROR(1, ERROR, "runaway ‘end’ statement"); - return 0; - } - line = STREND(line); - *end = prev_end_char, prev_end_char = '\0'; - SKIP_SPACES(line); - while (keyword_stack[--stack_ptr] == NULL); - if (*line == '\0') - { - line = original, end = STREND(line); - NEW_ERROR(1, ERROR, "expecting a keyword after ‘end’"); - } - else if (strcmp(line, keyword_stack[stack_ptr])) - NEW_ERROR(1, ERROR, "expected ‘%s’ but got ‘%s’", keyword_stack[stack_ptr], line); - NEXT; - - return 0; - fail: - return -1; + if (!stack_ptr) { + NEW_ERROR(1, ERROR, "runaway ‘end’ statement"); + return 0; + } + line = STREND(line); + *end = prev_end_char, prev_end_char = '\0'; + SKIP_SPACES(line); + while (!keyword_stack[--stack_ptr]); + if (!*line) { + line = original, end = STREND(line); + NEW_ERROR(1, ERROR, "expecting a keyword after ‘end’"); + } else if (strcmp(line, keyword_stack[stack_ptr])) { + NEW_ERROR(1, ERROR, "expected ‘%s’ but got ‘%s’", keyword_stack[stack_ptr], line); + } + NEXT; + + return 0; +fail: + return -1; } @@ -1173,57 +1140,56 @@ static int parse_end(void) * * @return Zero on success, -1 on error, 1 if the caller should go to `redo` */ -static int parse_map(void) +static int +parse_map(void) { - size_t stack_orig = stack_ptr + 1; - char* colon; + size_t stack_orig = stack_ptr + 1; + char *colon; #define node supernode #define inner sequence - NEW_NODE(map, MAP); - node->loc_end = node->loc_start; - BRANCH(":"); + NEW_NODE(map, MAP); + node->loc_end = node->loc_start; + BRANCH(":"); #undef inner #undef node - SEQUENCE(1); - SEQUENCE_FULLY_POPPED; + SEQUENCE(1); + SEQUENCE_FULLY_POPPED; #define node supernode #define inner result - stack_ptr--; - *end = prev_end_char; - supernode->loc_end = (size_t)(end - LINE); - SKIP_SPACES(line); - if (colon = line, *line++ != ':') - { - LEAF; - prev_end_char = *end; - return 0; /* Not an error in functions, or if \set is access, even indirectly. */ - } - BRANCH(":"); + stack_ptr--; + *end = prev_end_char; + supernode->loc_end = (size_t)(end - LINE); + SKIP_SPACES(line); + if (colon = line, *line++ != ':') { + LEAF; + prev_end_char = *end; + return 0; /* Not an error in functions, or if \set is access, even indirectly. */ + } + BRANCH(":"); #undef inner #undef node - SEQUENCE(1); - SEQUENCE_FULLY_POPPED; - stack_ptr--; - *end = prev_end_char; - supernode->loc_end = (size_t)(end - LINE); - SKIP_SPACES(line); + SEQUENCE(1); + SEQUENCE_FULLY_POPPED; + stack_ptr--; + *end = prev_end_char; + supernode->loc_end = (size_t)(end - LINE); + SKIP_SPACES(line); #define node supernode - LEAF; + LEAF; #undef node - if (supernode->result == NULL) - { - NEW_ERROR(1, ERROR, "output missing"); - error->start = (size_t)(colon - LINE); - error->end = error->start + 1; - } - if (*line == '\0') - return prev_end_char = *end, 0; - end = STREND(line), prev_end_char = *end; - NEW_ERROR(1, ERROR, "too many parameters"); - - return 0; - fail: - return -1; + if (!supernode->result) { + NEW_ERROR(1, ERROR, "output missing"); + error->start = (size_t)(colon - LINE); + error->end = error->start + 1; + } + if (!*line) + return prev_end_char = *end, 0; + end = STREND(line), prev_end_char = *end; + NEW_ERROR(1, ERROR, "too many parameters"); + + return 0; +fail: + return -1; } @@ -1232,63 +1198,59 @@ static int parse_map(void) * * @return Zero on success, -1 on error, 1 if the caller should go to `redo` */ -static int parse_macro_call(void) +static int +parse_macro_call(void) { - char* old_end = end; - char old_prev_end_char = prev_end_char; - size_t stack_orig = stack_ptr + 1; - *end = prev_end_char; - end = strchrnul(line, '('); - prev_end_char = *end, *end = '\0'; - if (prev_end_char) - { + char *old_end = end; + char old_prev_end_char = prev_end_char; + size_t stack_orig = stack_ptr + 1; + *end = prev_end_char; + end = strchrnul(line, '('); + prev_end_char = *end, *end = '\0'; + if (prev_end_char) { #define node supernode #define inner arguments - NEW_NODE(macro_call, MACRO_CALL); - old_end = end, old_prev_end_char = prev_end_char; - NO_JUMP; - *old_end = '\0'; - CHARS(name); - BRANCH(NULL); - end = old_end, prev_end_char = old_prev_end_char; - line++; + NEW_NODE(macro_call, MACRO_CALL); + old_end = end, old_prev_end_char = prev_end_char; + NO_JUMP; + *old_end = '\0'; + CHARS(name); + BRANCH(NULL); + end = old_end, prev_end_char = old_prev_end_char; + line++; #undef inner #undef node - SEQUENCE(0); - SEQUENCE_FULLY_POPPED; + SEQUENCE(0); + SEQUENCE_FULLY_POPPED; #define node supernode - if (*line == ')') - { - line++; - SKIP_SPACES(line); - if (*line) - { - NEW_ERROR(1, ERROR, "extra token after macro call"); - error->end = strlen(LINE); - } - } - else - { - NEW_ERROR(1, ERROR, "missing ‘)’"); - error->start = (size_t)(strchr(LINE, '(') - LINE); - error->end = error->start + 1; - } - stack_ptr--; - NEXT; - return 0; + if (*line == ')') { + line++; + SKIP_SPACES(line); + if (*line) { + NEW_ERROR(1, ERROR, "extra token after macro call"); + error->end = strlen(LINE); + } + } else { + NEW_ERROR(1, ERROR, "missing ‘)’"); + error->start = (size_t)(strchr(LINE, '(') - LINE); + error->end = error->start + 1; + } + stack_ptr--; + NEXT; + return 0; #undef node - } - *old_end = '\0'; - end = old_end; - prev_end_char = old_prev_end_char; - if (strchr("}", *line)) - NEW_ERROR(1, ERROR, "runaway ‘%c’", *line); - else - NEW_ERROR(1, ERROR, "invalid syntax ‘%s’", line); - - return 0; - fail: - return -1; + } + *old_end = '\0'; + end = old_end; + prev_end_char = old_prev_end_char; + if (strchr("}", *line)) + NEW_ERROR(1, ERROR, "runaway ‘%c’", *line); + else + NEW_ERROR(1, ERROR, "invalid syntax ‘%s’", line); + + return 0; +fail: + return -1; } @@ -1297,48 +1259,44 @@ static int parse_macro_call(void) * * @return Zero on success, -1 on error, 1 if the caller should go to `redo` */ -static int parse_array_elements(void) +static int +parse_array_elements(void) { - for (;;) - { - SKIP_SPACES(line); - if (*line == '\0') - return 0; - else if (*line == '}') - { - line++; - end = STREND(line); - END; - line = end, prev_end_char = '\0'; - goto done; + for (;;) { + SKIP_SPACES(line); + if (!*line) { + return 0; + } else if (*line == '}') { + line++; + end = STREND(line); + END; + line = end, prev_end_char = '\0'; + goto done; + } else { + NEW_NODE(string, STRING); + if (strchr("[]()<>{}", *line)) { + mds_kbdc_tree_free((mds_kbdc_tree_t*)node); + NEW_ERROR(1, ERROR, "x-stray ‘%c’", *line); + error->end = error->start + 1; + goto done; + } + NO_JUMP; + CHARS(string); + LEAF; + node->loc_end = (size_t)(end - LINE); + *end = prev_end_char; + line = end; + } } - else - { - NEW_NODE(string, STRING); - if (strchr("[]()<>{}", *line)) - { - mds_kbdc_tree_free((mds_kbdc_tree_t*)node); - NEW_ERROR(1, ERROR, "x-stray ‘%c’", *line); - error->end = error->start + 1; - goto done; - } - NO_JUMP; - CHARS(string); - LEAF; - node->loc_end = (size_t)(end - LINE); - *end = prev_end_char; - line = end; - } - } - - fail: - return -1; - - done: - in_array = 0; - stack_ptr -= 2; - NEXT; - return 0; + +fail: + return -1; + +done: + in_array = 0; + stack_ptr -= 2; + NEXT; + return 0; } @@ -1347,50 +1305,47 @@ static int parse_array_elements(void) * * @return Zero on success, -1 on error */ -static int parse_line(void) +static int +parse_line(void) { -#define p(function) \ - do \ - { \ - fail_if (r = function(), r < 0); \ - if (r > 0) \ - goto redo; \ - } \ - while (0) - - int r; - - redo: - if (in_array) p (parse_array_elements); - else if (!strcmp(line, "have_chars")) - MAKE_LEAF(assumption_have_chars, ASSUMPTION_HAVE_CHARS, QUOTES_1(chars)); - else if (!strcmp(line, "have_range")) - MAKE_LEAF(assumption_have_range, ASSUMPTION_HAVE_RANGE, CHARS(first); CHARS(last); END); - else if (!strcmp(line, "have")) MAKE_LEAF(assumption_have, ASSUMPTION_HAVE, KEYS(data); END); - else if (!strcmp(line, "information")) MAKE_BRANCH(information, INFORMATION, NO_PARAMETERS("information")); - else if (!strcmp(line, "assumption")) MAKE_BRANCH(assumption, ASSUMPTION, NO_PARAMETERS("assumption")); - else if (!strcmp(line, "return")) MAKE_LEAF(return, RETURN, NO_PARAMETERS("return")); - else if (!strcmp(line, "continue")) MAKE_LEAF(continue, CONTINUE, NO_PARAMETERS("continue")); - else if (!strcmp(line, "break")) MAKE_LEAF(break, BREAK, NO_PARAMETERS("break")); - else if (!strcmp(line, "language")) MAKE_LEAF(information_language, INFORMATION_LANGUAGE, QUOTES_1(data)); - else if (!strcmp(line, "country")) MAKE_LEAF(information_country, INFORMATION_COUNTRY, QUOTES_1(data)); - else if (!strcmp(line, "variant")) MAKE_LEAF(information_variant, INFORMATION_VARIANT, QUOTES_1(data)); - else if (!strcmp(line, "include")) MAKE_LEAF(include, INCLUDE, QUOTES_1(filename)); - else if (!strcmp(line, "function")) MAKE_BRANCH(function, FUNCTION, NAMES_1(name)); - else if (!strcmp(line, "macro")) MAKE_BRANCH(macro, MACRO, NAMES_1(name)); - else if (!strcmp(line, "if")) MAKE_BRANCH(if, IF, CHARS(condition); END); - else if (!strcmp(line, "else")) p (parse_else); - else if (!strcmp(line, "for")) p (parse_for); - else if (!strcmp(line, "let")) p (parse_let); - else if (!strcmp(line, "end")) p (parse_end); - else if (strchr("\\\"<([0123456789", *line)) p (parse_map); - else p (parse_macro_call); - - *end = prev_end_char; - - return 0; - fail: - return -1; +#define p(function)\ + do {\ + fail_if ((r = function()) < 0);\ + if (r > 0)\ + goto redo;\ + } while (0) + + int r; + +redo: + if (in_array) p (parse_array_elements); + else if (!strcmp(line, "have_chars")) MAKE_LEAF(assumption_have_chars, ASSUMPTION_HAVE_CHARS, QUOTES_1(chars)); + else if (!strcmp(line, "have_range")) MAKE_LEAF(assumption_have_range, ASSUMPTION_HAVE_RANGE, CHARS(first); CHARS(last); END); + else if (!strcmp(line, "have")) MAKE_LEAF(assumption_have, ASSUMPTION_HAVE, KEYS(data); END); + else if (!strcmp(line, "information")) MAKE_BRANCH(information, INFORMATION, NO_PARAMETERS("information")); + else if (!strcmp(line, "assumption")) MAKE_BRANCH(assumption, ASSUMPTION, NO_PARAMETERS("assumption")); + else if (!strcmp(line, "return")) MAKE_LEAF(return, RETURN, NO_PARAMETERS("return")); + else if (!strcmp(line, "continue")) MAKE_LEAF(continue, CONTINUE, NO_PARAMETERS("continue")); + else if (!strcmp(line, "break")) MAKE_LEAF(break, BREAK, NO_PARAMETERS("break")); + else if (!strcmp(line, "language")) MAKE_LEAF(information_language, INFORMATION_LANGUAGE, QUOTES_1(data)); + else if (!strcmp(line, "country")) MAKE_LEAF(information_country, INFORMATION_COUNTRY, QUOTES_1(data)); + else if (!strcmp(line, "variant")) MAKE_LEAF(information_variant, INFORMATION_VARIANT, QUOTES_1(data)); + else if (!strcmp(line, "include")) MAKE_LEAF(include, INCLUDE, QUOTES_1(filename)); + else if (!strcmp(line, "function")) MAKE_BRANCH(function, FUNCTION, NAMES_1(name)); + else if (!strcmp(line, "macro")) MAKE_BRANCH(macro, MACRO, NAMES_1(name)); + else if (!strcmp(line, "if")) MAKE_BRANCH(if, IF, CHARS(condition); END); + else if (!strcmp(line, "else")) p (parse_else); + else if (!strcmp(line, "for")) p (parse_for); + else if (!strcmp(line, "let")) p (parse_let); + else if (!strcmp(line, "end")) p (parse_end); + else if (strchr("\\\"<([0123456789", *line)) p (parse_map); + else p (parse_macro_call); + + *end = prev_end_char; + + return 0; +fail: + return -1; #undef p } @@ -1406,63 +1361,62 @@ static int parse_line(void) * @param result_ Output parameter for the parsing result * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise */ -int parse_to_tree(const char* restrict filename, mds_kbdc_parsed_t* restrict result_) +int +parse_to_tree(const char *restrict filename, mds_kbdc_parsed_t *restrict result_) { - size_t line_n; - int r, saved_errno; - - - /* Prepare parsing. */ - result = result_; - stack_ptr = 0; - keyword_stack = NULL; - tree_stack = NULL; - in_array = 0; - - fail_if (xmalloc(result->source_code, 1, mds_kbdc_source_code_t)); - mds_kbdc_source_code_initialise(result->source_code); - - r = get_pathname(filename); - fail_if (r < 0); - if (r == 0) - return 0; - - fail_if (read_source_code()); - fail_if (allocate_stacks()); - - - /* Create a node-slot for the tree root. */ - *tree_stack = &(result->tree); - - /* Parse the file. */ - for (line_i = 0, line_n = result->source_code->line_count; line_i < line_n; line_i++) - { - line = LINE; - SKIP_SPACES(line); - if (end = strchrnul(line, ' '), end == line) - continue; - prev_end_char = *end, *end = '\0'; - original = line; - too_few = 0; - - parse_line(); - } - - - /* Check parsing state. */ - fail_if (check_for_premature_end_of_file()); - fail_if (check_whether_file_is_empty()); - - /* Clean up. */ - free(keyword_stack); - free(tree_stack); - return 0; - - fail: - saved_errno = errno; - free(keyword_stack); - free(tree_stack); - return errno = saved_errno, -1; + size_t line_n; + int r, saved_errno; + + + /* Prepare parsing. */ + result = result_; + stack_ptr = 0; + keyword_stack = NULL; + tree_stack = NULL; + in_array = 0; + + fail_if (xmalloc(result->source_code, 1, mds_kbdc_source_code_t)); + mds_kbdc_source_code_initialise(result->source_code); + + fail_if ((r = get_pathname(filename)) < 0); + if (!r) + return 0; + + fail_if (read_source_code()); + fail_if (allocate_stacks()); + + + /* Create a node-slot for the tree root. */ + *tree_stack = &(result->tree); + + /* Parse the file. */ + for (line_i = 0, line_n = result->source_code->line_count; line_i < line_n; line_i++) { + line = LINE; + SKIP_SPACES(line); + if ((end = strchrnul(line, ' ')) == line) + continue; + prev_end_char = *end, *end = '\0'; + original = line; + too_few = 0; + + parse_line(); + } + + + /* Check parsing state. */ + fail_if (check_for_premature_end_of_file()); + fail_if (check_whether_file_is_empty()); + + /* Clean up. */ + free(keyword_stack); + free(tree_stack); + return 0; + +fail: + saved_errno = errno; + free(keyword_stack); + free(tree_stack); + return errno = saved_errno, -1; } @@ -1493,4 +1447,3 @@ int parse_to_tree(const char* restrict filename, mds_kbdc_parsed_t* restrict res #undef in_range #undef PRINT_STACK #undef DEBUG_PROC - diff --git a/src/mds-kbdc/make-tree.h b/src/mds-kbdc/make-tree.h index c645d94..0878414 100644 --- a/src/mds-kbdc/make-tree.h +++ b/src/mds-kbdc/make-tree.h @@ -29,8 +29,7 @@ * @param result Output parameter for the parsing result * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise */ -int parse_to_tree(const char* restrict filename, mds_kbdc_parsed_t* restrict result); +int parse_to_tree(const char *restrict filename, mds_kbdc_parsed_t *restrict result); #endif - diff --git a/src/mds-kbdc/mds-kbdc.c b/src/mds-kbdc/mds-kbdc.c index 1c5a6e8..0f668e4 100644 --- a/src/mds-kbdc/mds-kbdc.c +++ b/src/mds-kbdc/mds-kbdc.c @@ -37,15 +37,13 @@ /** * Parse command line arguments */ -static void parse_cmdline(void) +static void +parse_cmdline(void) { - int i; - for (i = 0; i < argc; i++) - { - char* arg = argv[i]; - if (strequals(arg, "--force")) - argv_force = 1; - } + int i; + for (i = 0; i < argc; i++) + if (strequals(argv[i], "--force")) + argv_force = 1; } @@ -56,39 +54,39 @@ static void parse_cmdline(void) * @param argv_ The command line arguments * @return Zero on and only one success */ -int main(int argc_, char** argv_) +int +main(int argc_, char **argv_) { -#define process(expr) \ - fail_if ((expr) < 0); \ - if (fatal = mds_kbdc_parsed_is_fatal(&result), fatal) \ - goto stop; - - mds_kbdc_parsed_t result; - int fatal; - - argc = argc_; - argv = argv_; - - parse_cmdline(); - - mds_kbdc_parsed_initialise(&result); - process (parse_to_tree(argv[1], &result)); - process (simplify_tree(&result)); - process (process_includes(&result)); - process (validate_tree(&result)); - process (eliminate_dead_code(&result)); - process (compile_layout(&result)); - /* TODO process (assemble_layout(&result)); */ - stop: - /* mds_kbdc_tree_print(result.tree, stderr); // for testing passes parse_to_tree–eliminate_dead_code */ - mds_kbdc_parsed_print_errors(&result, stderr); - mds_kbdc_parsed_destroy(&result); - return fatal; - - fail: - xperror(*argv); - mds_kbdc_parsed_destroy(&result); - return 1; +#define process(expr)\ + fail_if ((expr) < 0);\ + if ((fatal = mds_kbdc_parsed_is_fatal(&result)))\ + goto stop; + + mds_kbdc_parsed_t result; + int fatal; + + argc = argc_; + argv = argv_; + + parse_cmdline(); + + mds_kbdc_parsed_initialise(&result); + process (parse_to_tree(argv[1], &result)); + process (simplify_tree(&result)); + process (process_includes(&result)); + process (validate_tree(&result)); + process (eliminate_dead_code(&result)); + process (compile_layout(&result)); + /* TODO process (assemble_layout(&result)); */ +stop: + /* mds_kbdc_tree_print(result.tree, stderr); // for testing passes parse_to_tree–eliminate_dead_code */ + mds_kbdc_parsed_print_errors(&result, stderr); + mds_kbdc_parsed_destroy(&result); + return fatal; + +fail: + xperror(*argv); + mds_kbdc_parsed_destroy(&result); + return 1; #undef process } - diff --git a/src/mds-kbdc/mds-kbdc.h b/src/mds-kbdc/mds-kbdc.h index a0f0d0f..8cf6204 100644 --- a/src/mds-kbdc/mds-kbdc.h +++ b/src/mds-kbdc/mds-kbdc.h @@ -23,4 +23,3 @@ #endif - diff --git a/src/mds-kbdc/parse-error.c b/src/mds-kbdc/parse-error.c index 242b730..6a31424 100644 --- a/src/mds-kbdc/parse-error.c +++ b/src/mds-kbdc/parse-error.c @@ -32,46 +32,45 @@ * @param output The output file * @param desc The description of the error */ -static void print(const mds_kbdc_parse_error_t* restrict this, FILE* restrict output, const char* restrict desc) +static void +print(const mds_kbdc_parse_error_t *restrict this, FILE *restrict output, const char *restrict desc) { - size_t i, n, start = 0, end = 0; - const char* restrict code = this->code; - char* restrict path = relpath(this->pathname, NULL); - - /* Convert bytes count to character count for the code position. */ - for (i = 0, n = this->start; i < n; i++) - if ((code[i] & 0xC0) != 0x80) - start++; - for (n = this->end; i < n; i++) - if ((code[i] & 0xC0) != 0x80) - end++; - end += start; - - /* Print error information. */ - fprintf(output, "\033[01m%s\033[21m:", path ? path : this->pathname); - free(path); - if (this->error_is_in_file) - fprintf(output, "%zu:%zu–%zu:", this->line + 1, start, end); - switch (this->severity) - { - case MDS_KBDC_PARSE_ERROR_NOTE: fprintf(output, " \033[01;36mnote:\033[00m "); break; - case MDS_KBDC_PARSE_ERROR_WARNING: fprintf(output, " \033[01;35mwarning:\033[00m "); break; - case MDS_KBDC_PARSE_ERROR_ERROR: fprintf(output, " \033[01;31merror:\033[00m "); break; - case MDS_KBDC_PARSE_ERROR_INTERNAL_ERROR: fprintf(output, " \033[01;31minternal error:\033[00m "); break; - default: - abort(); - break; - } - if (this->error_is_in_file) - { - fprintf(output, "%s\n %s\n \033[01;32m", desc, code); - i = 0; - for (n = start; i < n; i++) fputc(' ', output); - for (n = end; i < n; i++) fputc('^', output); - } - else - fprintf(output, "%s\n", desc); - fprintf(output, "\033[00m\n"); + size_t i, n, start = 0, end = 0; + const char *restrict code = this->code; + char *restrict path = relpath(this->pathname, NULL); + + /* Convert bytes count to character count for the code position. */ + for (i = 0, n = this->start; i < n; i++) + if ((code[i] & 0xC0) != 0x80) + start++; + for (n = this->end; i < n; i++) + if ((code[i] & 0xC0) != 0x80) + end++; + end += start; + + /* Print error information. */ + fprintf(output, "\033[01m%s\033[21m:", path ? path : this->pathname); + free(path); + if (this->error_is_in_file) + fprintf(output, "%zu:%zu–%zu:", this->line + 1, start, end); + switch (this->severity) { + case MDS_KBDC_PARSE_ERROR_NOTE: fprintf(output, " \033[01;36mnote:\033[00m "); break; + case MDS_KBDC_PARSE_ERROR_WARNING: fprintf(output, " \033[01;35mwarning:\033[00m "); break; + case MDS_KBDC_PARSE_ERROR_ERROR: fprintf(output, " \033[01;31merror:\033[00m "); break; + case MDS_KBDC_PARSE_ERROR_INTERNAL_ERROR: fprintf(output, " \033[01;31minternal error:\033[00m "); break; + default: + abort(); + break; + } + if (this->error_is_in_file) { + fprintf(output, "%s\n %s\n \033[01;32m", desc, code); + i = 0; + for (n = start; i < n; i++) fputc(' ', output); + for (n = end; i < n; i++) fputc('^', output); + } else { + fprintf(output, "%s\n", desc); + } + fprintf(output, "\033[00m\n"); } @@ -81,49 +80,57 @@ static void print(const mds_kbdc_parse_error_t* restrict this, FILE* restrict ou * @param this The error structure * @param output The output file */ -void mds_kbdc_parse_error_print(const mds_kbdc_parse_error_t* restrict this, FILE* restrict output) +void +mds_kbdc_parse_error_print(const mds_kbdc_parse_error_t *restrict this, FILE *restrict output) { - ssize_t m; - size_t n; - char* desc; - char* dend = this->description + strlen(this->description); - char* dstart; - char* dptr; - char* p; - char* q; - - /* Count the number points in the description we should modify to format it. */ - for (p = this->description, n = 0;;) - { - if (q = strstr(p, "‘"), q == NULL) q = dend; - if (p = strstr(p, "’"), p == NULL) p = dend; - if (q < p) p = q; - if (*p++) n++; - else break; - } - - /* Allocate string for the formatted description. */ - n = 1 + strlen(this->description) + strlen("\033[xxm’") * n; - dptr = desc = alloca(n * sizeof(char)); - - /* Format description. */ - for (p = this->description;;) - { - dstart = p; - if (q = strstr(p, "‘"), q == NULL) q = dend; - if (p = strstr(p, "’"), p == NULL) p = dend; - if (q < p) p = q; - if ((n = (size_t)(p - dstart))) - memcpy(dptr, dstart, n), dptr += n; - if (p == dend) - break; - if (strstr(p, "‘") == p) sprintf(dptr, "\033[01m‘%zn", &m), dptr += (size_t)m, p += strlen("‘"); - else sprintf(dptr, "’\033[21m%zn", &m), dptr += (size_t)m, p += strlen("’"); - } - *dptr = '\0'; - - /* Print the error. */ - print(this, output, desc); + size_t n; + char *desc; + char *dend = this->description + strlen(this->description); + char *dstart; + char *dptr; + char *p; + char *q; + + /* Count the number points in the description we should modify to format it. */ + for (p = this->description, n = 0;;) { + if (!(q = strstr(p, "‘"))) + q = dend; + if (!(p = strstr(p, "’"))) + p = dend; + if (q < p) + p = q; + if (*p++) + n++; + else + break; + } + + /* Allocate string for the formatted description. */ + n = 1 + strlen(this->description) + strlen("\033[xxm’") * n; + dptr = desc = alloca(n * sizeof(char)); + + /* Format description. */ + for (p = this->description;;) { + dstart = p; + if (!(q = strstr(p, "‘"))) + q = dend; + if (!(p = strstr(p, "’"))) + p = dend; + if (q < p) + p = q; + if ((n = (size_t)(p - dstart))) + memcpy(dptr, dstart, n), dptr += n; + if (p == dend) + break; + if (strstr(p, "‘") == p) + dptr += sprintf(dptr, "\033[01m‘"), p += strlen("‘"); + else + dptr += sprintf(dptr, "’\033[21m"), p += strlen("’"); + } + *dptr = '\0'; + + /* Print the error. */ + print(this, output, desc); } @@ -133,13 +140,14 @@ void mds_kbdc_parse_error_print(const mds_kbdc_parse_error_t* restrict this, FIL * * @param this The error structure */ -void mds_kbdc_parse_error_destroy(mds_kbdc_parse_error_t* restrict this) +void +mds_kbdc_parse_error_destroy(mds_kbdc_parse_error_t *restrict this) { - if (this == NULL) - return; - free(this->pathname), this->pathname = NULL; - free(this->code), this->code = NULL; - free(this->description), this->description = NULL; + if (!this) + return; + free(this->pathname), this->pathname = NULL; + free(this->code), this->code = NULL; + free(this->description), this->description = NULL; } @@ -149,10 +157,11 @@ void mds_kbdc_parse_error_destroy(mds_kbdc_parse_error_t* restrict this) * * @param this The error structure */ -void mds_kbdc_parse_error_free(mds_kbdc_parse_error_t* restrict this) +void +mds_kbdc_parse_error_free(mds_kbdc_parse_error_t *restrict this) { - mds_kbdc_parse_error_destroy(this); - free(this); + mds_kbdc_parse_error_destroy(this); + free(this); } @@ -162,13 +171,14 @@ void mds_kbdc_parse_error_free(mds_kbdc_parse_error_t* restrict this) * * @param this The group of error structures */ -void mds_kbdc_parse_error_destroy_all(mds_kbdc_parse_error_t** restrict these) +void +mds_kbdc_parse_error_destroy_all(mds_kbdc_parse_error_t **restrict these) { - mds_kbdc_parse_error_t* restrict that; - if (these == NULL) - return; - while (that = *these, that != NULL) - mds_kbdc_parse_error_free(that), *these++ = NULL; + mds_kbdc_parse_error_t *restrict that; + if (!these) + return; + while ((that = *these)) + mds_kbdc_parse_error_free(that), *these++ = NULL; } @@ -178,9 +188,9 @@ void mds_kbdc_parse_error_destroy_all(mds_kbdc_parse_error_t** restrict these) * * @param this The group of error structures */ -void mds_kbdc_parse_error_free_all(mds_kbdc_parse_error_t** restrict these) +void +mds_kbdc_parse_error_free_all(mds_kbdc_parse_error_t**restrict these) { - mds_kbdc_parse_error_destroy_all(these); - free(these); + mds_kbdc_parse_error_destroy_all(these); + free(these); } - diff --git a/src/mds-kbdc/parse-error.h b/src/mds-kbdc/parse-error.h index b7e879c..9668f8f 100644 --- a/src/mds-kbdc/parse-error.h +++ b/src/mds-kbdc/parse-error.h @@ -27,74 +27,72 @@ /** * Not an error, simply a note about the previous error or warning */ -#define MDS_KBDC_PARSE_ERROR_NOTE 1 +#define MDS_KBDC_PARSE_ERROR_NOTE 1 /** * A warning, must likely an error that is not fatal to the compilation */ -#define MDS_KBDC_PARSE_ERROR_WARNING 2 +#define MDS_KBDC_PARSE_ERROR_WARNING 2 /** * An error, the compilation will halt */ -#define MDS_KBDC_PARSE_ERROR_ERROR 3 +#define MDS_KBDC_PARSE_ERROR_ERROR 3 /** * Internal compiler error or system error, compilation halts */ -#define MDS_KBDC_PARSE_ERROR_INTERNAL_ERROR 4 +#define MDS_KBDC_PARSE_ERROR_INTERNAL_ERROR 4 /** * Description of an parsing error */ -typedef struct mds_kbdc_parse_error -{ - /** - * Either of: - * - `MDS_KBDC_PARSE_ERROR_NOTE` - * - `MDS_KBDC_PARSE_ERROR_WARNING` - * - `MDS_KBDC_PARSE_ERROR_ERROR` - * - `MDS_KBDC_PARSE_ERROR_INTERNAL_ERROR` - */ - int severity; - - /** - * If zero, disregard `.line`, `.start`, `.end` and `.code` - */ - int error_is_in_file; - - /** - * The pathname of the file with the error - */ - char* pathname; - - /** - * The line where the error occurred, zero-based - */ - size_t line; - - /** - * The byte where the error started, inclusive, zero-based - */ - size_t start; - - /** - * The byte where the error ended, exclusive, zero-based - */ - size_t end; - - /** - * The code on the line where the error occurred - */ - char* code; - - /** - * Description of the error - */ - char* description; - +typedef struct mds_kbdc_parse_error { + /** + * Either of: + * - `MDS_KBDC_PARSE_ERROR_NOTE` + * - `MDS_KBDC_PARSE_ERROR_WARNING` + * - `MDS_KBDC_PARSE_ERROR_ERROR` + * - `MDS_KBDC_PARSE_ERROR_INTERNAL_ERROR` + */ + int severity; + + /** + * If zero, disregard `.line`, `.start`, `.end` and `.code` + */ + int error_is_in_file; + + /** + * The pathname of the file with the error + */ + char *pathname; + + /** + * The line where the error occurred, zero-based + */ + size_t line; + + /** + * The byte where the error started, inclusive, zero-based + */ + size_t start; + + /** + * The byte where the error ended, exclusive, zero-based + */ + size_t end; + + /** + * The code on the line where the error occurred + */ + char *code; + + /** + * Description of the error + */ + char *description; } mds_kbdc_parse_error_t; @@ -105,7 +103,7 @@ typedef struct mds_kbdc_parse_error * @param this The error structure * @param output The output file */ -void mds_kbdc_parse_error_print(const mds_kbdc_parse_error_t* restrict this, FILE* restrict output); +void mds_kbdc_parse_error_print(const mds_kbdc_parse_error_t *restrict this, FILE *restrict output); /** @@ -113,7 +111,7 @@ void mds_kbdc_parse_error_print(const mds_kbdc_parse_error_t* restrict this, FIL * * @param this The error structure */ -void mds_kbdc_parse_error_destroy(mds_kbdc_parse_error_t* restrict this); +void mds_kbdc_parse_error_destroy(mds_kbdc_parse_error_t *restrict this); /** * Release all resources allocated in a `mds_kbdc_parse_error_t*` @@ -121,7 +119,7 @@ void mds_kbdc_parse_error_destroy(mds_kbdc_parse_error_t* restrict this); * * @param this The error structure */ -void mds_kbdc_parse_error_free(mds_kbdc_parse_error_t* restrict this); +void mds_kbdc_parse_error_free(mds_kbdc_parse_error_t *restrict this); /** * Release all resources allocated in a `NULL`-terminated group @@ -129,7 +127,7 @@ void mds_kbdc_parse_error_free(mds_kbdc_parse_error_t* restrict this); * * @param this The group of error structures */ -void mds_kbdc_parse_error_destroy_all(mds_kbdc_parse_error_t** restrict these); +void mds_kbdc_parse_error_destroy_all(mds_kbdc_parse_error_t **restrict these); /** * Release all resources allocated in a `NULL`-terminated group of @@ -137,9 +135,8 @@ void mds_kbdc_parse_error_destroy_all(mds_kbdc_parse_error_t** restrict these); * * @param this The group of error structures */ -void mds_kbdc_parse_error_free_all(mds_kbdc_parse_error_t** restrict these); +void mds_kbdc_parse_error_free_all(mds_kbdc_parse_error_t **restrict these); #endif - diff --git a/src/mds-kbdc/parsed.c b/src/mds-kbdc/parsed.c index d9c8f23..e4c23dc 100644 --- a/src/mds-kbdc/parsed.c +++ b/src/mds-kbdc/parsed.c @@ -28,9 +28,10 @@ * * @param this The `mds_kbdc_parsed_t*` */ -void mds_kbdc_parsed_initialise(mds_kbdc_parsed_t* restrict this) +void +mds_kbdc_parsed_initialise(mds_kbdc_parsed_t *restrict this) { - memset(this, 0, sizeof(mds_kbdc_parsed_t)); + memset(this, 0, sizeof(mds_kbdc_parsed_t)); } @@ -39,27 +40,28 @@ void mds_kbdc_parsed_initialise(mds_kbdc_parsed_t* restrict this) * * @param this The `mds_kbdc_parsed_t*` */ -void mds_kbdc_parsed_destroy(mds_kbdc_parsed_t* restrict this) +void +mds_kbdc_parsed_destroy(mds_kbdc_parsed_t *restrict this) { - mds_kbdc_tree_free(this->tree); - mds_kbdc_source_code_destroy(this->source_code); - free(this->source_code); - free(this->pathname); - mds_kbdc_parse_error_free_all(this->errors); - while (this->languages_ptr--) - free(this->languages[this->languages_ptr]); - free(this->languages); - while (this->countries_ptr--) - free(this->countries[this->countries_ptr]); - free(this->countries); - free(this->variant); - while (this->assumed_strings_ptr--) - free(this->assumed_strings[this->assumed_strings_ptr]); - free(this->assumed_strings); - while (this->assumed_keys_ptr--) - free(this->assumed_keys[this->assumed_keys_ptr]); - free(this->assumed_keys); - memset(this, 0, sizeof(mds_kbdc_parsed_t)); + mds_kbdc_tree_free(this->tree); + mds_kbdc_source_code_destroy(this->source_code); + free(this->source_code); + free(this->pathname); + mds_kbdc_parse_error_free_all(this->errors); + while (this->languages_ptr--) + free(this->languages[this->languages_ptr]); + free(this->languages); + while (this->countries_ptr--) + free(this->countries[this->countries_ptr]); + free(this->countries); + free(this->variant); + while (this->assumed_strings_ptr--) + free(this->assumed_strings[this->assumed_strings_ptr]); + free(this->assumed_strings); + while (this->assumed_keys_ptr--) + free(this->assumed_keys[this->assumed_keys_ptr]); + free(this->assumed_keys); + memset(this, 0, sizeof(mds_kbdc_parsed_t)); } @@ -69,9 +71,10 @@ void mds_kbdc_parsed_destroy(mds_kbdc_parsed_t* restrict this) * @param this The parsing result * @return Whether a fatal errors has occurred */ -int mds_kbdc_parsed_is_fatal(mds_kbdc_parsed_t* restrict this) +int +mds_kbdc_parsed_is_fatal(mds_kbdc_parsed_t *restrict this) { - return this->severest_error_level >= MDS_KBDC_PARSE_ERROR_ERROR; + return this->severest_error_level >= MDS_KBDC_PARSE_ERROR_ERROR; } @@ -81,23 +84,22 @@ int mds_kbdc_parsed_is_fatal(mds_kbdc_parsed_t* restrict this) * @param this The parsing result * @param output The output file */ -void mds_kbdc_parsed_print_errors(mds_kbdc_parsed_t* restrict this, FILE* output) +void +mds_kbdc_parsed_print_errors(mds_kbdc_parsed_t *restrict this, FILE *output) { - mds_kbdc_parse_error_t** errors = this->errors; - char* env = getenv("MDS_KBDC_ERRORS_ORDER"); - if (errors == NULL) - return; - if (env && (strcasecmp(env, "reversed") || strcasecmp(env, "reverse"))) - { - while (*errors) - errors++; - while (errors-- != this->errors) - mds_kbdc_parse_error_print(*errors, output); - } - else - while (*errors) - mds_kbdc_parse_error_print(*errors++, output); - + mds_kbdc_parse_error_t **errors = this->errors; + char *env = getenv("MDS_KBDC_ERRORS_ORDER"); + if (!errors) { + return; + } else if (env && (strcasecmp(env, "reversed") || strcasecmp(env, "reverse"))) { + while (*errors) + errors++; + while (errors-- != this->errors) + mds_kbdc_parse_error_print(*errors, output); + } else { + while (*errors) + mds_kbdc_parse_error_print(*errors++, output); + } } @@ -112,49 +114,47 @@ void mds_kbdc_parsed_print_errors(mds_kbdc_parsed_t* restrict this, FILE* output * @param end The byte where the error ended, on the line, exclusive, zero-based * @return The new error on success, `NULL` on error */ -mds_kbdc_parse_error_t* mds_kbdc_parsed_new_error(mds_kbdc_parsed_t* restrict this, int severity, - int error_is_in_file, size_t line, size_t start, size_t end) +mds_kbdc_parse_error_t * +mds_kbdc_parsed_new_error(mds_kbdc_parsed_t *restrict this, int severity, + int error_is_in_file, size_t line, size_t start, size_t end) { - mds_kbdc_parse_error_t* error = NULL; - size_t old_errors_ptr = this->errors_ptr; - int saved_errno; - - if (this->errors_ptr + 1 >= this->errors_size) - { - size_t new_errors_size = this->errors_size ? (this->errors_size << 1) : 2; - mds_kbdc_parse_error_t** new_errors = this->errors; - - fail_if (xrealloc(new_errors, new_errors_size, mds_kbdc_parse_error_t*)); - this->errors = new_errors; - this->errors_size = new_errors_size; - } - - fail_if (xcalloc(error, 1, mds_kbdc_parse_error_t)); - this->errors[this->errors_ptr + 0] = error; - this->errors[this->errors_ptr + 1] = NULL; - this->errors_ptr++; - - error->severity = severity; - if (this->severest_error_level < severity) - this->severest_error_level = severity; - - fail_if (xstrdup(error->pathname, this->pathname)); - - if ((error->error_is_in_file = error_is_in_file)) - { - error->line = line; - error->start = start; - error->end = end; - fail_if (xstrdup(error->code, this->source_code->real_lines[line])); - } - - return error; - fail: - saved_errno = errno; - free(error); - this->errors_ptr = old_errors_ptr; - this->errors[this->errors_ptr] = NULL; - errno = saved_errno; - return NULL; -} + mds_kbdc_parse_error_t *error = NULL, **new_errors; + size_t old_errors_ptr = this->errors_ptr, new_errors_size; + int saved_errno; + + if (this->errors_ptr + 1 >= this->errors_size) { + new_errors_size = this->errors_size ? (this->errors_size << 1) : 2; + new_errors = this->errors; + + fail_if (xrealloc(new_errors, new_errors_size, mds_kbdc_parse_error_t*)); + this->errors = new_errors; + this->errors_size = new_errors_size; + } + + fail_if (xcalloc(error, 1, mds_kbdc_parse_error_t)); + this->errors[this->errors_ptr + 0] = error; + this->errors[this->errors_ptr + 1] = NULL; + this->errors_ptr++; + error->severity = severity; + if (this->severest_error_level < severity) + this->severest_error_level = severity; + + fail_if (xstrdup(error->pathname, this->pathname)); + + if ((error->error_is_in_file = error_is_in_file)) { + error->line = line; + error->start = start; + error->end = end; + fail_if (xstrdup(error->code, this->source_code->real_lines[line])); + } + + return error; +fail: + saved_errno = errno; + free(error); + this->errors_ptr = old_errors_ptr; + this->errors[this->errors_ptr] = NULL; + errno = saved_errno; + return NULL; +} diff --git a/src/mds-kbdc/parsed.h b/src/mds-kbdc/parsed.h index 7d01695..58ad6fa 100644 --- a/src/mds-kbdc/parsed.h +++ b/src/mds-kbdc/parsed.h @@ -42,15 +42,13 @@ * @param ...:const char*, ... Error description format string and arguments * @scope error:mds_kbdc_parse_error_t* Variable where the new error will be stored */ -#define NEW_ERROR_(RESULT, SEVERITY, ERROR_IS_IN_FILE, LINE, START, END, WITH_DESCRIPTION, ...) \ - do \ - { \ - error = mds_kbdc_parsed_new_error(RESULT, MDS_KBDC_PARSE_ERROR_##SEVERITY, \ - ERROR_IS_IN_FILE, LINE, START, END); \ - fail_if (error == NULL); \ - fail_if (WITH_DESCRIPTION && xasprintf(error->description, __VA_ARGS__)); \ - } \ - while (0) +#define NEW_ERROR_(RESULT, SEVERITY, ERROR_IS_IN_FILE, LINE, START, END, WITH_DESCRIPTION, ...)\ + do {\ + error = mds_kbdc_parsed_new_error(RESULT, MDS_KBDC_PARSE_ERROR_##SEVERITY,\ + ERROR_IS_IN_FILE, LINE, START, END);\ + fail_if (!error);\ + fail_if (WITH_DESCRIPTION && xasprintf(error->description, __VA_ARGS__));\ + } while (0) @@ -58,115 +56,113 @@ * Structure with parsed tree, error list * source code and the file's pathname */ -typedef struct mds_kbdc_parsed -{ - /** - * The parsed tree - */ - mds_kbdc_tree_t* tree; - - /** - * The source code of the parsed file - */ - mds_kbdc_source_code_t* source_code; - - /** - * A non-relative pathname to the parsed file. - * Relative filenames can be misleading as the - * program can have changed working directory - * to be able to resolve filenames. - */ - char* pathname; - - /** - * `NULL`-terminated list of found errors - * `NULL` if no errors that could be listed - * were found - */ - mds_kbdc_parse_error_t** errors; - - /** - * The number of elements allocated to `errors` - */ - size_t errors_size; - - /** - * The number of elements stored in `errors` - */ - size_t errors_ptr; - - /** - * The level of the severest countered error, - * 0 if none has been encountered. - */ - int severest_error_level; - - /** - * List of languages for which the layout is designed - */ - char** languages; - - /** - * The number of elements allocated to `languages` - */ - size_t languages_size; - - /** - * The number of elements stored in `languages` - */ - size_t languages_ptr; - - /** - * List of countries for which the layout is designed - */ - char** countries; - - /** - * The number of elements allocated to `countries` - */ - size_t countries_size; - - /** - * The number of elements stored in `countries` - */ - size_t countries_ptr; - - /** - * The variant of the keyboard for the languages/countries, - * `NULL` if not specified - */ - char* variant; - - /** - * List of strings the assembler should assume are provided - */ - char32_t** assumed_strings; - - /** - * The number of elements allocated to `assumed_strings` - */ - size_t assumed_strings_size; - - /** - * The number of elements stored in `assumed_strings` - */ - size_t assumed_strings_ptr; - - /** - * List of keys the assembler should assume are provided - */ - char32_t** assumed_keys; - - /** - * The number of elements allocated to `assumed_keys` - */ - size_t assumed_keys_size; - - /** - * The number of elements stored in `assumed_keys` - */ - size_t assumed_keys_ptr; - +typedef struct mds_kbdc_parsed { + /** + * The parsed tree + */ + mds_kbdc_tree_t *tree; + + /** + * The source code of the parsed file + */ + mds_kbdc_source_code_t *source_code; + + /** + * A non-relative pathname to the parsed file. + * Relative filenames can be misleading as the + * program can have changed working directory + * to be able to resolve filenames. + */ + char *pathname; + + /** + * `NULL`-terminated list of found errors + * `NULL` if no errors that could be listed + * were found + */ + mds_kbdc_parse_error_t **errors; + + /** + * The number of elements allocated to `errors` + */ + size_t errors_size; + + /** + * The number of elements stored in `errors` + */ + size_t errors_ptr; + + /** + * The level of the severest countered error, + * 0 if none has been encountered. + */ + int severest_error_level; + + /** + * List of languages for which the layout is designed + */ + char **languages; + + /** + * The number of elements allocated to `languages` + */ + size_t languages_size; + + /** + * The number of elements stored in `languages` + */ + size_t languages_ptr; + + /** + * List of countries for which the layout is designed + */ + char **countries; + + /** + * The number of elements allocated to `countries` + */ + size_t countries_size; + + /** + * The number of elements stored in `countries` + */ + size_t countries_ptr; + + /** + * The variant of the keyboard for the languages/countries, + * `NULL` if not specified + */ + char *variant; + + /** + * List of strings the assembler should assume are provided + */ + char32_t **assumed_strings; + + /** + * The number of elements allocated to `assumed_strings` + */ + size_t assumed_strings_size; + + /** + * The number of elements stored in `assumed_strings` + */ + size_t assumed_strings_ptr; + + /** + * List of keys the assembler should assume are provided + */ + char32_t **assumed_keys; + + /** + * The number of elements allocated to `assumed_keys` + */ + size_t assumed_keys_size; + + /** + * The number of elements stored in `assumed_keys` + */ + size_t assumed_keys_ptr; } mds_kbdc_parsed_t; @@ -176,14 +172,14 @@ typedef struct mds_kbdc_parsed * * @param this The `mds_kbdc_parsed_t*` */ -void mds_kbdc_parsed_initialise(mds_kbdc_parsed_t* restrict this); +void mds_kbdc_parsed_initialise(mds_kbdc_parsed_t *restrict this); /** * Release all resources allocated in a `mds_kbdc_parsed_t*` * * @param this The `mds_kbdc_parsed_t*` */ -void mds_kbdc_parsed_destroy(mds_kbdc_parsed_t* restrict this); +void mds_kbdc_parsed_destroy(mds_kbdc_parsed_t *restrict this); /** * Check whether a fatal errors has occurred @@ -191,7 +187,8 @@ void mds_kbdc_parsed_destroy(mds_kbdc_parsed_t* restrict this); * @param this The parsing result * @return Whether a fatal errors has occurred */ -int mds_kbdc_parsed_is_fatal(mds_kbdc_parsed_t* restrict this) __attribute__((pure)); +__attribute__((pure)) +int mds_kbdc_parsed_is_fatal(mds_kbdc_parsed_t *restrict this); /** * Print all encountered errors @@ -199,7 +196,7 @@ int mds_kbdc_parsed_is_fatal(mds_kbdc_parsed_t* restrict this) __attribute__((pu * @param this The parsing result * @param output The output file */ -void mds_kbdc_parsed_print_errors(mds_kbdc_parsed_t* restrict this, FILE* output); +void mds_kbdc_parsed_print_errors(mds_kbdc_parsed_t *restrict this, FILE *output); /** * Add a new error to the list @@ -212,9 +209,8 @@ void mds_kbdc_parsed_print_errors(mds_kbdc_parsed_t* restrict this, FILE* output * @param end The byte where the error ended, on the line, exclusive, zero-based * @return The new error on success, `NULL` on error */ -mds_kbdc_parse_error_t* mds_kbdc_parsed_new_error(mds_kbdc_parsed_t* restrict this, int severity, - int error_is_in_file, size_t line, size_t start, size_t end); +mds_kbdc_parse_error_t *mds_kbdc_parsed_new_error(mds_kbdc_parsed_t *restrict this, int severity, + int error_is_in_file, size_t line, size_t start, size_t end); #endif - diff --git a/src/mds-kbdc/paths.c b/src/mds-kbdc/paths.c index 53ae6fa..70bddf1 100644 --- a/src/mds-kbdc/paths.c +++ b/src/mds-kbdc/paths.c @@ -31,32 +31,32 @@ * * @return The current working directory */ -char* curpath(void) +char * +curpath(void) { - static size_t cwd_size = 4096; - char* cwd = NULL; - char* old = NULL; - int saved_errno; - - /* glibc offers ways to do this in just one function call, - * but we will not assume that glibc is used here. */ - for (;;) - { - fail_if (xxrealloc(old, cwd, cwd_size + 1, char)); - if (getcwd(cwd, cwd_size)) - break; - else - fail_if (errno != ERANGE); - cwd_size <<= 1; - } - - return cwd; - fail: - saved_errno = errno; - free(old); - free(cwd); - errno = saved_errno; - return NULL; + static size_t cwd_size = 4096; + char *cwd = NULL; + char *old = NULL; + int saved_errno; + + /* glibc offers ways to do this in just one function call, + * but we will not assume that glibc is used here. */ + for (;;) { + fail_if (xxrealloc(old, cwd, cwd_size + 1, char)); + if (getcwd(cwd, cwd_size)) + break; + else + fail_if (errno != ERANGE); + cwd_size <<= 1; + } + + return cwd; +fail: + saved_errno = errno; + free(old); + free(cwd); + errno = saved_errno; + return NULL; } @@ -66,53 +66,51 @@ char* curpath(void) * @param path The filename of the file * @return The file's absolute path, `NULL` on error */ -char* abspath(const char* path) +char * +abspath(const char *path) { - char* cwd = NULL; - char* buf = NULL; - int saved_errno, slash = 1; - size_t size, p; - - if (*path == '/') - { - fail_if (xstrdup(buf, path)); - return buf; - } - - fail_if (cwd = curpath(), cwd == NULL); - size = (p = strlen(cwd)) + strlen(path) + 2; - fail_if (xmalloc(buf, size + 1, char)); - memcpy(buf, cwd, (p + 1) * sizeof(char)); - if (buf[p - 1] != '/') - buf[p++] = '/'; - - while (*path) - if (slash && (path[0] == '/')) - path += 1; - else if (slash && (path[0] == '.') && (path[1] == '/')) - path += 2; - else if (slash && (path[0] == '.') && (path[1] == '.') && (path[2] == '/')) - { - path += 3; - p--; - while (p && (buf[--p] != '/')); - p++; - } - else - { - buf[p++] = *path; - slash = (*path++ == '/'); - } - - buf[p] = '\0'; - - free(cwd); - return buf; - fail: - saved_errno = errno; - free(cwd); - errno = saved_errno; - return NULL; + char *cwd = NULL; + char *buf = NULL; + int saved_errno, slash = 1; + size_t size, p; + + if (*path == '/') { + fail_if (xstrdup(buf, path)); + return buf; + } + + fail_if (!(cwd = curpath())); + size = (p = strlen(cwd)) + strlen(path) + 2; + fail_if (xmalloc(buf, size + 1, char)); + memcpy(buf, cwd, (p + 1) * sizeof(char)); + if (buf[p - 1] != '/') + buf[p++] = '/'; + + while (*path) { + if (slash && path[0] == '/') { + path += 1; + } else if (slash && path[0] == '.' && path[1] == '/') { + path += 2; + } else if (slash && path[0] == '.' && path[1] == '.' && path[2] == '/') { + path += 3; + p--; + while (p && buf[--p] != '/'); + p++; + } else { + buf[p++] = *path; + slash = *path++ == '/'; + } + } + + buf[p] = '\0'; + + free(cwd); + return buf; +fail: + saved_errno = errno; + free(cwd); + errno = saved_errno; + return NULL; } @@ -124,46 +122,46 @@ char* abspath(const char* path) * `NULL` for the current working directroy * @return The file's relative path, `NULL` on error */ -char* relpath(const char* path, const char* base) +char * +relpath(const char *path, const char *base) { - char* abs = abspath(path); - char* absbase = NULL; - char* buf = NULL; - char* old = NULL; - int saved_errno; - size_t p, slash = 1, back = 0; - - fail_if (abs == NULL); - absbase = base ? abspath(base) : curpath(); - fail_if (absbase == NULL); - - if (absbase[strlen(absbase) - 1] != '/') - /* Both `abspath` and `curpath` (and `relpath`) allocates one extra slot. */ - absbase[strlen(absbase) + 1] = '\0', absbase[strlen(absbase)] = '/'; - - for (p = 1; abs[p] && absbase[p] && (abs[p] == absbase[p]); p++) - if (abs[p] == '/') - slash = p + 1; - - for (p = slash; absbase[p]; p++) - if (absbase[p] == '/') - back++; - - fail_if (xmalloc(buf, back * 3 + strlen(abs + slash) + 2, char)); - - for (p = 0; back--;) - buf[p++] = '.', buf[p++] = '.', buf[p++] = '/'; - memcpy(buf + p, abs + slash, (strlen(abs + slash) + 1) * sizeof(char)); - - free(abs); - free(absbase); - return buf; - fail: - saved_errno = errno; - free(abs); - free(absbase); - free(old); - errno = saved_errno; - return NULL; -} + char *abs = abspath(path); + char *absbase = NULL; + char *buf = NULL; + char *old = NULL; + int saved_errno; + size_t p, slash = 1, back = 0; + fail_if (!abs); + absbase = base ? abspath(base) : curpath(); + fail_if (!absbase); + + if (absbase[strlen(absbase) - 1] != '/') + /* Both `abspath` and `curpath` (and `relpath`) allocates one extra slot. */ + absbase[strlen(absbase) + 1] = '\0', absbase[strlen(absbase)] = '/'; + + for (p = 1; abs[p] && absbase[p] && abs[p] == absbase[p]; p++) + if (abs[p] == '/') + slash = p + 1; + + for (p = slash; absbase[p]; p++) + if (absbase[p] == '/') + back++; + + fail_if (xmalloc(buf, back * 3 + strlen(abs + slash) + 2, char)); + + for (p = 0; back--;) + buf[p++] = '.', buf[p++] = '.', buf[p++] = '/'; + memcpy(buf + p, abs + slash, (strlen(abs + slash) + 1) * sizeof(char)); + + free(abs); + free(absbase); + return buf; +fail: + saved_errno = errno; + free(abs); + free(absbase); + free(old); + errno = saved_errno; + return NULL; +} diff --git a/src/mds-kbdc/paths.h b/src/mds-kbdc/paths.h index 6c24042..6dbe007 100644 --- a/src/mds-kbdc/paths.h +++ b/src/mds-kbdc/paths.h @@ -24,7 +24,7 @@ * * @return The current working directory */ -char* curpath(void); +char *curpath(void); /** * Get the absolute path of a file @@ -32,7 +32,7 @@ char* curpath(void); * @param path The filename of the file * @return The file's absolute path, `NULL` on error */ -char* abspath(const char* path); +char *abspath(const char *path); /** * Get a relative path of a file @@ -42,8 +42,7 @@ char* abspath(const char* path); * `NULL` for the current working directroy * @return The file's relative path, `NULL` on error */ -char* relpath(const char* path, const char* base); +char *relpath(const char* path, const char *base); #endif - diff --git a/src/mds-kbdc/process-includes.c b/src/mds-kbdc/process-includes.c index 69b9c73..a46533c 100644 --- a/src/mds-kbdc/process-includes.c +++ b/src/mds-kbdc/process-includes.c @@ -32,7 +32,7 @@ /** * Tree type constant shortener */ -#define C(TYPE) MDS_KBDC_TREE_TYPE_##TYPE +#define C(TYPE) MDS_KBDC_TREE_TYPE_##TYPE /** * Add an error to the error list @@ -42,26 +42,26 @@ * @param ...:const char*, ... Error description format string and arguments * @scope error:mds_kbdc_parse_error_t* Variable where the new error will be stored */ -#define NEW_ERROR(NODE, SEVERITY, ...) \ - NEW_ERROR_(result, SEVERITY, 1, (NODE)->loc_line, \ - (NODE)->loc_start, (NODE)->loc_end, 1, __VA_ARGS__) +#define NEW_ERROR(NODE, SEVERITY, ...)\ + NEW_ERROR_(result, SEVERITY, 1, (NODE)->loc_line,\ + (NODE)->loc_start, (NODE)->loc_end, 1, __VA_ARGS__) /** * Variable whether the latest created error is stored */ -static mds_kbdc_parse_error_t* error; +static mds_kbdc_parse_error_t *error; /** * The parameter of `process_includes` */ -static mds_kbdc_parsed_t* restrict result; +static mds_kbdc_parsed_t *restrict result; /** * Stack of attributes of already included files */ -static struct stat* restrict included; +static struct stat *restrict included; /** * The number elements allocated for `included` @@ -81,66 +81,62 @@ static size_t included_ptr = 0; * @param subresult The results of the processed include * @param tree The include statement */ -static int transfer_errors(mds_kbdc_parsed_t* restrict subresult, mds_kbdc_tree_include_t* restrict tree) +static int +transfer_errors(mds_kbdc_parsed_t *restrict subresult, mds_kbdc_tree_include_t *restrict tree) { - mds_kbdc_parse_error_t** errors = NULL; - mds_kbdc_parse_error_t* suberror; - size_t errors_ptr = 0; - int saved_errno, annotated = 0; - - /* Allocate temporary list for errors. */ - if (subresult->errors_ptr == 0) - return 0; - fail_if (xmalloc(errors, subresult->errors_ptr * 2, mds_kbdc_parse_error_t*)); - - /* List errors backwards, so that we can easily handle errors and add “included from here”-note. */ - while (subresult->errors_ptr--) - { - suberror = subresult->errors[subresult->errors_ptr]; - - /* If it is more severe than a note, we want to say there it was included. */ - if (annotated == 0) - { - NEW_ERROR(tree, NOTE, "included from here"); - errors[errors_ptr++] = error; - result->errors[--(result->errors_ptr)] = NULL; - annotated = 1; + mds_kbdc_parse_error_t **errors = NULL, *suberror, **new_errors; + size_t errors_ptr = 0, new_errors_size; + int saved_errno, annotated = 0; + + /* Allocate temporary list for errors. */ + if (!subresult->errors_ptr) + return 0; + fail_if (xmalloc(errors, subresult->errors_ptr * 2, mds_kbdc_parse_error_t*)); + + /* List errors backwards, so that we can easily handle errors and add “included from here”-note. */ + while (subresult->errors_ptr--) { + suberror = subresult->errors[subresult->errors_ptr]; + + /* If it is more severe than a note, we want to say there it was included. */ + if (!annotated) { + NEW_ERROR(tree, NOTE, "included from here"); + errors[errors_ptr++] = error; + result->errors[--(result->errors_ptr)] = NULL; + annotated = 1; + } + + /* Include error. */ + errors[errors_ptr++] = suberror; + subresult->errors[subresult->errors_ptr] = NULL; + + /* Make sure when there are nested inclusions that the outermost inclusion * is annotated last. */ + if (suberror->severity > MDS_KBDC_PARSE_ERROR_NOTE) + annotated = 0; } - - /* Include error. */ - errors[errors_ptr++] = suberror; - subresult->errors[subresult->errors_ptr] = NULL; - - /* Make sure when there are nested inclusions that the outermost inclusion * is annotated last. */ - if (suberror->severity > MDS_KBDC_PARSE_ERROR_NOTE) - annotated = 0; - } - - /* Append errors. */ - for (; errors_ptr--; errors[errors_ptr] = NULL) - { - if (result->errors_ptr + 1 >= result->errors_size) - { - size_t new_errors_size = result->errors_size ? (result->errors_size << 1) : 2; - mds_kbdc_parse_error_t** new_errors = result->errors; - - fail_if (xrealloc(new_errors, new_errors_size, mds_kbdc_parse_error_t*)); - result->errors = new_errors; - result->errors_size = new_errors_size; + + /* Append errors. */ + for (; errors_ptr--; errors[errors_ptr] = NULL) { + if (result->errors_ptr + 1 >= result->errors_size) { + new_errors_size = result->errors_size ? (result->errors_size << 1) : 2; + new_errors = result->errors; + + fail_if (xrealloc(new_errors, new_errors_size, mds_kbdc_parse_error_t*)); + result->errors = new_errors; + result->errors_size = new_errors_size; + } + + result->errors[result->errors_ptr++] = errors[errors_ptr]; + result->errors[result->errors_ptr] = NULL; } - - result->errors[result->errors_ptr++] = errors[errors_ptr]; - result->errors[result->errors_ptr] = NULL; - } - - free(errors); - return 0; - fail: - saved_errno = errno; - while (errors_ptr--) - mds_kbdc_parse_error_free(errors[errors_ptr]); - free(errors); - return errno = saved_errno, -1; + + free(errors); + return 0; +fail: + saved_errno = errno; + while (errors_ptr--) + mds_kbdc_parse_error_free(errors[errors_ptr]); + free(errors); + return errno = saved_errno, -1; } @@ -150,86 +146,83 @@ static int transfer_errors(mds_kbdc_parsed_t* restrict subresult, mds_kbdc_tree_ * @param tree The include-statement * @return Zero on success, -1 on error */ -static int process_include(mds_kbdc_tree_include_t* restrict tree) +static int +process_include(mds_kbdc_tree_include_t *restrict tree) { -#define process(expr) \ - fail_if ((expr) < 0); \ - if (mds_kbdc_parsed_is_fatal(&subresult)) \ - goto stop; - - mds_kbdc_parsed_t subresult; - mds_kbdc_parsed_t* our_result; - char* dirname = NULL; - char* cwd = NULL; - char* old = NULL; - size_t cwd_size = 4096 >> 1; - int saved_errno; - - /* Initialise result structure for the included file. */ - mds_kbdc_parsed_initialise(&subresult); - - /* Get dirname of current file. */ - fail_if (xstrdup(dirname, result->pathname)); - *(strrchr(dirname, '/')) = '\0'; - - /* Get the current working directory. */ - /* glibc offers ways to do this in just one function call, - * but we will not assume that glibc is used here. */ - for (;;) - { - fail_if (xxrealloc(old, cwd, cwd_size <<= 1, char)); - if (getcwd(cwd, cwd_size)) - break; - else - fail_if (errno != ERANGE); - } - - /* Switch working directory. */ - fail_if (chdir(dirname)); - free(dirname), dirname = NULL; - - /* Store `result` as it will be switched by the inner `process_includes`. */ - our_result = result; - - /* Process include. */ - old = tree->filename, tree->filename = NULL; - tree->filename = parse_raw_string(old); - fail_if (tree->filename == NULL); - free(old), old = NULL; - process (parse_to_tree(tree->filename, &subresult)); - process (simplify_tree(&subresult)); - process (process_includes(&subresult)); - stop: - - /* Switch back `result`. */ - result = our_result; - - /* Switch back to the old working directory. */ - fail_if (chdir(cwd)); - free(cwd), cwd = NULL; - - /* Move over data to our result. */ - free(tree->filename); - tree->filename = subresult.pathname, subresult.pathname = NULL; - tree->source_code = subresult.source_code, subresult.source_code = NULL; - tree->inner = subresult.tree, subresult.tree = NULL; - if (result->severest_error_level < subresult.severest_error_level) - result->severest_error_level = subresult.severest_error_level; - - /* Move over errors. */ - fail_if (transfer_errors(&subresult, tree)); - - /* Release resources. */ - mds_kbdc_parsed_destroy(&subresult); - - return 0; - fail: - saved_errno = errno; - free(dirname); - free(cwd); - free(old); - mds_kbdc_parsed_destroy(&subresult); - return errno = saved_errno, -1; +#define process(expr)\ + fail_if ((expr) < 0);\ + if (mds_kbdc_parsed_is_fatal(&subresult))\ + goto stop; + + mds_kbdc_parsed_t subresult, *our_result; + char *dirname = NULL, *cwd = NULL, *old = NULL; + size_t cwd_size = 4096 >> 1; + int saved_errno; + + /* Initialise result structure for the included file. */ + mds_kbdc_parsed_initialise(&subresult); + + /* Get dirname of current file. */ + fail_if (xstrdup(dirname, result->pathname)); + *(strrchr(dirname, '/')) = '\0'; + + /* Get the current working directory. */ + /* glibc offers ways to do this in just one function call, + * but we will not assume that glibc is used here. */ + for (;;) { + fail_if (xxrealloc(old, cwd, cwd_size <<= 1, char)); + if (getcwd(cwd, cwd_size)) + break; + else + fail_if (errno != ERANGE); + } + + /* Switch working directory. */ + fail_if (chdir(dirname)); + free(dirname), dirname = NULL; + + /* Store `result` as it will be switched by the inner `process_includes`. */ + our_result = result; + + /* Process include. */ + old = tree->filename, tree->filename = NULL; + tree->filename = parse_raw_string(old); + fail_if (tree->filename == NULL); + free(old), old = NULL; + process (parse_to_tree(tree->filename, &subresult)); + process (simplify_tree(&subresult)); + process (process_includes(&subresult)); +stop: + + /* Switch back `result`. */ + result = our_result; + + /* Switch back to the old working directory. */ + fail_if (chdir(cwd)); + free(cwd), cwd = NULL; + + /* Move over data to our result. */ + free(tree->filename); + tree->filename = subresult.pathname, subresult.pathname = NULL; + tree->source_code = subresult.source_code, subresult.source_code = NULL; + tree->inner = subresult.tree, subresult.tree = NULL; + if (result->severest_error_level < subresult.severest_error_level) + result->severest_error_level = subresult.severest_error_level; + + /* Move over errors. */ + fail_if (transfer_errors(&subresult, tree)); + + /* Release resources. */ + mds_kbdc_parsed_destroy(&subresult); + + return 0; +fail: + saved_errno = errno; + free(dirname); + free(cwd); + free(old); + mds_kbdc_parsed_destroy(&subresult); + return errno = saved_errno, -1; #undef process } @@ -240,32 +233,32 @@ static int process_include(mds_kbdc_tree_include_t* restrict tree) * @param tree The tree * @return Zero on success, -1 on error */ -static int process_includes_in_tree(mds_kbdc_tree_t* restrict tree) +static int +process_includes_in_tree(mds_kbdc_tree_t *restrict tree) { -#define p(expr) fail_if (process_includes_in_tree(tree->expr)) - again: - if (tree == NULL) - return 0; - - switch (tree->type) - { - case C(INFORMATION): p (information.inner); break; - case C(FUNCTION): p (function.inner); break; - case C(MACRO): p (macro.inner); break; - case C(ASSUMPTION): p (assumption.inner); break; - case C(FOR): p (for_.inner); break; - case C(IF): p (if_.inner); p (if_.otherwise); break; - case C(INCLUDE): - fail_if (process_include(&(tree->include))); - break; - default: - break; - } - - tree = tree->next; - goto again; - fail: - return -1; +#define p(expr) fail_if (process_includes_in_tree(tree->expr)) +again: + if (!tree) + return 0; + + switch (tree->type) { + case C(INFORMATION): p (information.inner); break; + case C(FUNCTION): p (function.inner); break; + case C(MACRO): p (macro.inner); break; + case C(ASSUMPTION): p (assumption.inner); break; + case C(FOR): p (for_.inner); break; + case C(IF): p (if_.inner); p (if_.otherwise); break; + case C(INCLUDE): + fail_if (process_include(&(tree->include))); + break; + default: + break; + } + + tree = tree->next; + goto again; +fail: + return -1; #undef p } @@ -276,45 +269,43 @@ static int process_includes_in_tree(mds_kbdc_tree_t* restrict tree) * @param result_ `result` from `simplify_tree`, will be updated * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise */ -int process_includes(mds_kbdc_parsed_t* restrict result_) +int +process_includes(mds_kbdc_parsed_t *restrict result_) { - int r, saved_errno; - struct stat attr; - size_t i; - - result = result_; - - fail_if (stat(result->pathname, &attr)); - - if (included_ptr == included_size) - { - struct stat* old; - if (xxrealloc(old, included, included_size += 4, struct stat)) - fail_if (included = old, 1); - } - - for (i = 0; i < included_ptr; i++) - if ((included[i].st_dev == attr.st_dev) && (included[i].st_ino == attr.st_ino)) - { - NEW_ERROR_(result, ERROR, 0, 0, 0, 0, 1, "resursive inclusion"); - return 0; - } - - included[included_ptr++] = attr; - - r = process_includes_in_tree(result_->tree); - saved_errno = errno; - - if (--included_ptr == 0) - free(included), included_size = 0; - - return errno = saved_errno, r; - fail: - return -1; + int r, saved_errno; + struct stat attr, *old; + size_t i; + + result = result_; + + fail_if (stat(result->pathname, &attr)); + + if (included_ptr == included_size) { + if (xxrealloc(old, included, included_size += 4, struct stat)) + fail_if (included = old, 1); + } + + for (i = 0; i < included_ptr; i++) { + if ((included[i].st_dev == attr.st_dev) && (included[i].st_ino == attr.st_ino)) { + NEW_ERROR_(result, ERROR, 0, 0, 0, 0, 1, "resursive inclusion"); + return 0; + } + } + + included[included_ptr++] = attr; + + r = process_includes_in_tree(result_->tree); + saved_errno = errno; + + if (!--included_ptr) + free(included), included_size = 0; + + return errno = saved_errno, r; +fail: + return -1; } #undef NEW_ERROR #undef C - diff --git a/src/mds-kbdc/process-includes.h b/src/mds-kbdc/process-includes.h index 5644dd9..6146600 100644 --- a/src/mds-kbdc/process-includes.h +++ b/src/mds-kbdc/process-includes.h @@ -28,8 +28,7 @@ * @param result `result` from `simplify_tree`, will be updated * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise */ -int process_includes(mds_kbdc_parsed_t* restrict result); +int process_includes(mds_kbdc_parsed_t *restrict result); #endif - diff --git a/src/mds-kbdc/raw-data.c b/src/mds-kbdc/raw-data.c index e40be68..2b89840 100644 --- a/src/mds-kbdc/raw-data.c +++ b/src/mds-kbdc/raw-data.c @@ -39,14 +39,15 @@ * * @param this The `mds_kbdc_source_code_t*` */ -void mds_kbdc_source_code_initialise(mds_kbdc_source_code_t* restrict this) +void +mds_kbdc_source_code_initialise(mds_kbdc_source_code_t *restrict this) { - this->lines = NULL; - this->real_lines = NULL; - this->content = NULL; - this->real_content = NULL; - this->line_count = 0; - this->duplicates = 0; + this->lines = NULL; + this->real_lines = NULL; + this->content = NULL; + this->real_content = NULL; + this->line_count = 0; + this->duplicates = 0; } @@ -55,16 +56,17 @@ void mds_kbdc_source_code_initialise(mds_kbdc_source_code_t* restrict this) * * @param this The `mds_kbdc_source_code_t*` */ -void mds_kbdc_source_code_destroy(mds_kbdc_source_code_t* restrict this) +void +mds_kbdc_source_code_destroy(mds_kbdc_source_code_t *restrict this) { - if (this == NULL) - return; - if (this->duplicates--) - return; - free(this->lines), this->lines = NULL; - free(this->real_lines), this->real_lines = NULL; - free(this->content), this->content = NULL; - free(this->real_content), this->real_content = NULL; + if (!this) + return; + if (this->duplicates--) + return; + free(this->lines), this->lines = NULL; + free(this->real_lines), this->real_lines = NULL; + free(this->content), this->content = NULL; + free(this->real_content), this->real_content = NULL; } @@ -73,17 +75,18 @@ void mds_kbdc_source_code_destroy(mds_kbdc_source_code_t* restrict this) * * @param this The `mds_kbdc_source_code_t*` */ -void mds_kbdc_source_code_free(mds_kbdc_source_code_t* restrict this) +void +mds_kbdc_source_code_free(mds_kbdc_source_code_t *restrict this) { - if (this == NULL) - return; - if (this->duplicates--) - return; - free(this->lines); - free(this->real_lines); - free(this->content); - free(this->real_content); - free(this); + if (!this) + return; + if (this->duplicates--) + return; + free(this->lines); + free(this->real_lines); + free(this->content); + free(this->real_content); + free(this); } /** @@ -92,10 +95,11 @@ void mds_kbdc_source_code_free(mds_kbdc_source_code_t* restrict this) * @param this The `mds_kbdc_source_code_t*` * @return `this` is returned */ -mds_kbdc_source_code_t* mds_kbdc_source_code_dup(mds_kbdc_source_code_t* restrict this) +mds_kbdc_source_code_t * +mds_kbdc_source_code_dup(mds_kbdc_source_code_t *restrict this) { - this->duplicates++; - return this; + this->duplicates++; + return this; } @@ -107,51 +111,51 @@ mds_kbdc_source_code_t* mds_kbdc_source_code_dup(mds_kbdc_source_code_t* restric * @param size Output parameter for the size of the read content, in char:s * @return The read content, `NULL` on error */ -static char* read_file(const char* restrict pathname, size_t* restrict size) +static char * +read_file(const char *restrict pathname, size_t *restrict size) { - size_t buf_size = 8096; - size_t buf_ptr = 0; - char* restrict content = NULL; - char* restrict old = NULL; - int fd = -1; - ssize_t got; - - /* Allocate buffer for the file's content. */ - fail_if (xmalloc(content, buf_size, char)); - /* Open the file to compile. */ - fail_if ((fd = open(pathname, O_RDONLY)) < 0); - - /* Read the file to compile. */ - for (;;) - { - /* Make sure the buffer is not small. */ - if (buf_size - buf_ptr < 2048) - fail_if (xxrealloc(old, content, buf_size <<= 1, char)); - /* Read a chunk of the file. */ - got = read(fd, content + buf_ptr, (buf_size - buf_ptr) * sizeof(char)); - if ((got < 0) && (errno == EINTR)) continue; - if (got == 0) break; - fail_if (got < 0); - buf_ptr += (size_t)got; - } - - /* Shrink the buffer so it is not excessively large. */ - if (buf_ptr) /* Simplest way to handle empty files: let the have the initial allocation size. */ - fail_if (xxrealloc(old, content, buf_ptr, char)); - - /* Close file decriptor for the file. */ - xclose(fd); - - *size = buf_ptr; - return content; - - fail: - xperror(*argv); - free(old); - free(content); - if (fd >= 0) - xclose(fd); - return NULL; + size_t buf_size = 8096; + size_t buf_ptr = 0; + char *restrict content = NULL; + char *restrict old = NULL; + int fd = -1; + ssize_t got; + + /* Allocate buffer for the file's content. */ + fail_if (xmalloc(content, buf_size, char)); + /* Open the file to compile. */ + fail_if ((fd = open(pathname, O_RDONLY)) < 0); + + /* Read the file to compile. */ + for (;;) { + /* Make sure the buffer is not small. */ + if (buf_size - buf_ptr < 2048) + fail_if (xxrealloc(old, content, buf_size <<= 1, char)); + /* Read a chunk of the file. */ + got = read(fd, content + buf_ptr, (buf_size - buf_ptr) * sizeof(char)); + if (got < 0 && errno == EINTR) continue; + if (got == 0) break; + fail_if (got < 0); + buf_ptr += (size_t)got; + } + + /* Shrink the buffer so it is not excessively large. */ + if (buf_ptr) /* Simplest way to handle empty files: let the have the initial allocation size. */ + fail_if (xxrealloc(old, content, buf_ptr, char)); + + /* Close file decriptor for the file. */ + xclose(fd); + + *size = buf_ptr; + return content; + +fail: + xperror(*argv); + free(old); + free(content); + if (fd >= 0) + xclose(fd); + return NULL; } @@ -167,54 +171,59 @@ static char* read_file(const char* restrict pathname, size_t* restrict size) * or `size` if the call do not end (that is, the code ends * prematurely), or zero if there is no function call at `offset` */ -size_t get_end_of_call(const char* restrict content, size_t offset, size_t size) +size_t +get_end_of_call(const char *restrict content, size_t offset, size_t size) { -#define C content[ptr] -#define r(lower, upper) (((lower) <= C) && (C <= (upper))) - - size_t ptr = offset, call_end = 0; - int escape = 0, quote = 0; - - /* Skip to end of function name. */ - while ((ptr < size) && (r('a', 'z') || r('A', 'Z') || r('0', '9') || (C == '_'))) - ptr++; - - /* Check that it is a function call. */ - if ((ptr == size) || (ptr == offset) || (C != '(')) - return 0; - - /* Find the end of the function call. */ - while (ptr < size) - { - char c = content[ptr++]; - - /* Escapes may be longer than one character, - but only the first can affect the parsing. */ - if (escape) escape = 0; - /* Nested function and nested quotes can appear. */ - else if (ptr <= call_end) ; - /* Quotes end with the same symbols as they start with, - and quotes automatically escape brackets. */ - /* \ can either start a functon call or an escape. */ - else if (c == '\\') - { - /* It may not be an escape, but registering it - as an escape cannot harm us since we only - skip the first character, and a function call - cannot be that short. */ - escape = 1; - /* Nested quotes can appear at function calls. */ - call_end = get_end_of_call(content, ptr, size); +#define C content[ptr] +#define r(lower, upper) ((lower) <= C && C <= (upper)) + + size_t ptr = offset, call_end = 0; + int escape = 0, quote = 0; + char c; + + /* Skip to end of function name. */ + while (ptr < size && (r('a', 'z') || r('A', 'Z') || r('0', '9') || (C == '_'))) + ptr++; + + /* Check that it is a function call. */ + if (ptr == size || ptr == offset || C != '(') + return 0; + + /* Find the end of the function call. */ + while (ptr < size) { + c = content[ptr++]; + + if (escape) { + /* Escapes may be longer than one character, + but only the first can affect the parsing. */ + escape = 0; + } else if (ptr <= call_end) { + /* Nested function and nested quotes can appear. */; + } else if (c == '\\') { + /* Quotes end with the same symbols as they start with, + and quotes automatically escape brackets. */ + /* \ can either start a functon call or an escape. */ + + /* It may not be an escape, but registering it + as an escape cannot harm us since we only + skip the first character, and a function call + cannot be that short. */ + escape = 1; + /* Nested quotes can appear at function calls. */ + call_end = get_end_of_call(content, ptr, size); + } else if (quote) { + quote = (c != '"'); + } else if (c == ')') { + /* End of function call, end of fun. */ + break; + } else if (c == '"') { + /* " is the quote symbol. */ + quote = 1; + } } - else if (quote) quote = (c != '"'); - /* End of function call, end of fun. */ - else if (c == ')') break; - /* " is the quote symbol. */ - else if (c == '"') quote = 1; - } - - return ptr; - + + return ptr; + #undef r #undef C } @@ -227,55 +236,58 @@ size_t get_end_of_call(const char* restrict content, size_t offset, size_t size) * @param size The size of `content`, in char:s * @return The new size of `content`, in char:s; this function cannot fail */ -static size_t remove_comments(char* restrict content, size_t size) +static size_t +remove_comments(char *restrict content, size_t size) { -#define t content[n_ptr++] = c - - size_t n_ptr = 0, o_ptr = 0, call_end = 0; - int comment = 0, quote = 0, escape = 0; - - while (o_ptr < size) - { - char c = content[o_ptr++]; - /* Remove comment. */ - if (comment) - { - if (c == '\n') t, comment = 0; - } - /* Escapes may be longer than one character, - but only the first can affect the parsing. */ - else if (escape) t, escape = 0; - /* Nested quotes can appear at function calls. */ - else if (o_ptr <= call_end) t; - /* \ can either start a functon call or an escape. */ - else if (c == '\\') - { - t; - /* It may not be an escape, but registering it - as an escape cannot harm us since we only - skip the first character, and a function call - cannot be that short. */ - escape = 1; - /* Nested quotes can appear at function calls. */ - call_end = get_end_of_call(content, o_ptr, size); - } - /* Quotes end with the same symbols as they start with, - and quotes automatically escape comments. */ - else if (quote) - { - t; - if (strchr("\"\n", c)) quote = 0; +#define t content[n_ptr++] = c + + size_t n_ptr = 0, o_ptr = 0, call_end = 0; + int comment = 0, quote = 0, escape = 0; + char c; + + while (o_ptr < size) { + c = content[o_ptr++]; + if (comment) { + /* Remove comment. */ + if (c == '\n') + t, comment = 0; + } else if (escape) { + /* Escapes may be longer than one character, + but only the first can affect the parsing. */ + t, escape = 0; + } else if (o_ptr <= call_end) { + /* Nested quotes can appear at function calls. */ + t; + } else if (c == '\\') { + /* \ can either start a functon call or an escape. */ + t; + /* It may not be an escape, but registering it + as an escape cannot harm us since we only + skip the first character, and a function call + cannot be that short. */ + escape = 1; + /* Nested quotes can appear at function calls. */ + call_end = get_end_of_call(content, o_ptr, size); + } else if (quote) { + /* Quotes end with the same symbols as they start with, + and quotes automatically escape comments. */ + t; + if (strchr("\"\n", c)) + quote = 0; + } else if (c == '#') { + /* # is the comment symbol. */ + comment = 1; + } else if (c == '"') { + /* " is the quote symbol. */ + t, quote = 1; + } else { + /* Code and whitespace. */ + t; + } } - /* # is the comment symbol. */ - else if (c == '#') comment = 1; - /* " is the quote symbol. */ - else if (c == '"') t, quote = 1; - /* Code and whitespace. */ - else t; - } - - return n_ptr; - + + return n_ptr; + #undef t } @@ -298,36 +310,35 @@ static size_t remove_comments(char* restrict content, size_t size) * `NULL` is returned, and `content` will not * have been modified. */ -static char** line_split(char* content, size_t length) +static char ** +line_split(char *content, size_t length) { - char** restrict lines = NULL; - size_t count = 0; - size_t i, j; - int new_line = 1; - - for (i = 0; i < length; i++) - if (content[i] == '\n') - count++; - - fail_if (xmalloc(lines, count + 1, char*)); - lines[count] = NULL; - - for (i = j = 0; i < length; i++) - { - if (new_line) - new_line = 0, lines[j++] = content + i; - if (content[i] == '\n') - { - new_line = 1; - content[i] = '\0'; + char **restrict lines = NULL; + size_t count = 0; + size_t i, j; + int new_line = 1; + + for (i = 0; i < length; i++) + if (content[i] == '\n') + count++; + + fail_if (xmalloc(lines, count + 1, char*)); + lines[count] = NULL; + + for (i = j = 0; i < length; i++) { + if (new_line) + new_line = 0, lines[j++] = content + i; + if (content[i] == '\n') { + new_line = 1; + content[i] = '\0'; + } } - } - - return lines; - - fail: - xperror(*argv); - return NULL; + + return lines; + +fail: + xperror(*argv); + return NULL; } @@ -338,40 +349,44 @@ static char** line_split(char* content, size_t length) * @param content_size Input and output parameter for the size of the file's content * @return Zero on success, -1 on error */ -static int expand(char** restrict content, size_t* restrict content_size) +static int +expand(char **restrict content, size_t *restrict content_size) { - size_t extra = 0, added = 0, ptr, col, n = *content_size; - char* restrict data = *content; - - /* Calculate the new size of the file. */ - for (ptr = col = 0; ptr < n; ptr++) - if (data[ptr] == '\n') - col = 0; - else if (data[ptr] == '\t') - extra += 8 - (col % 8) - 1; - - /* Extend the allocation. */ - if (extra == 0) - return 0; - *content_size += extra; - fail_if (xrealloc(data, *content_size, char)); - *content = data; - - /* Expand tab spaces. */ - memmove(data + extra, data, n); - for (ptr = 0; ptr < n; ptr++, added--) - if (data[ptr + extra] == '\n') - data[ptr + added++] = data[ptr + extra], col = 0; - else if (data[ptr + extra] != '\t') - data[ptr + added++] = data[ptr + extra], col++; - else - do - data[ptr + added++] = ' '; - while (++col % 8); - - return 0; - fail: - return -1; + size_t extra = 0, added = 0, ptr, col, n = *content_size; + char *restrict data = *content; + + /* Calculate the new size of the file. */ + for (ptr = col = 0; ptr < n; ptr++) { + if (data[ptr] == '\n') + col = 0; + else if (data[ptr] == '\t') + extra += 8 - (col % 8) - 1; + } + + /* Extend the allocation. */ + if (!extra) + return 0; + *content_size += extra; + fail_if (xrealloc(data, *content_size, char)); + *content = data; + + /* Expand tab spaces. */ + memmove(data + extra, data, n); + for (ptr = 0; ptr < n; ptr++, added--) { + if (data[ptr + extra] == '\n') { + data[ptr + added++] = data[ptr + extra], col = 0; + } else if (data[ptr + extra] != '\t') { + data[ptr + added++] = data[ptr + extra], col++; + } else { + do + data[ptr + added++] = ' '; + while (++col % 8); + } + } + + return 0; +fail: + return -1; } @@ -382,60 +397,60 @@ static int expand(char** restrict content, size_t* restrict content_size) * @param source_code Output parameter for read data * @return Zero on success, -1 on error */ -int read_source_lines(const char* restrict pathname, mds_kbdc_source_code_t* restrict source_code) +int +read_source_lines(const char *restrict pathname, mds_kbdc_source_code_t *restrict source_code) { - char* content = NULL; - char* real_content = NULL; - char* old = NULL; - size_t content_size; - size_t real_content_size; - char** lines = NULL; - char** real_lines = NULL; - size_t line_count = 0; - - /* Read the file. */ - content = read_file(pathname, &content_size); - fail_if (content == NULL); - - /* Expand tab spaces. */ - fail_if (expand(&content, &content_size)); - - /* Make sure the content ends with a new line. */ - if (!content_size || (content[content_size - 1] != '\n')) - { - fail_if (xxrealloc(old, content, content_size + 1, char)); - content[content_size++] = '\n'; - } - - /* Simplify file. */ - fail_if (xmemdup(real_content, content, content_size, char)); - real_content_size = content_size; - content_size = remove_comments(content, content_size); - fail_if (xxrealloc(old, content, content_size, char)); - - /* Split by line. */ - fail_if ((lines = line_split(content, content_size)) == NULL); - fail_if ((real_lines = line_split(real_content, real_content_size)) == NULL); - - /* Count the number of lines. */ - while (lines[line_count] != NULL) - line_count++; - - source_code->lines = lines; - source_code->real_lines = real_lines; - source_code->content = content; - source_code->real_content = real_content; - source_code->line_count = line_count; - return 0; - - fail: - xperror(*argv); - free(old); - free(content); - free(real_content); - free(lines); - free(real_lines); - return -1; + char *content = NULL; + char *real_content = NULL; + char *old = NULL; + size_t content_size; + size_t real_content_size; + char **lines = NULL; + char **real_lines = NULL; + size_t line_count = 0; + + /* Read the file. */ + content = read_file(pathname, &content_size); + fail_if (!content); + + /* Expand tab spaces. */ + fail_if (expand(&content, &content_size)); + + /* Make sure the content ends with a new line. */ + if (!content_size || content[content_size - 1] != '\n') { + fail_if (xxrealloc(old, content, content_size + 1, char)); + content[content_size++] = '\n'; + } + + /* Simplify file. */ + fail_if (xmemdup(real_content, content, content_size, char)); + real_content_size = content_size; + content_size = remove_comments(content, content_size); + fail_if (xxrealloc(old, content, content_size, char)); + + /* Split by line. */ + fail_if (!(lines = line_split(content, content_size))); + fail_if (!(real_lines = line_split(real_content, real_content_size))); + + /* Count the number of lines. */ + while (lines[line_count]) + line_count++; + + source_code->lines = lines; + source_code->real_lines = real_lines; + source_code->content = content; + source_code->real_content = real_content; + source_code->line_count = line_count; + return 0; + +fail: + xperror(*argv); + free(old); + free(content); + free(real_content); + free(lines); + free(real_lines); + return -1; } @@ -446,24 +461,25 @@ int read_source_lines(const char* restrict pathname, mds_kbdc_source_code_t* res * @param character The character * @return The of the character in `buffer`, `NULL` on error */ -static char* encode_utf8(char* buffer, char32_t character) +static char * +encode_utf8(char *buffer, char32_t character) { - char32_t text[2]; - char* restrict str; - char* restrict str_; - - text[0] = character; - text[1] = -1; - - fail_if (str_ = str = string_encode(text), str == NULL); - - while (*str) - *buffer++ = *str++; - - free(str_); - return buffer; - fail: - return NULL; + char32_t text[2]; + char *restrict str; + char *restrict str_; + + text[0] = character; + text[1] = -1; + + fail_if (!(str_ = str = string_encode(text))); + + while (*str) + *buffer++ = *str++; + + free(str_); + return buffer; +fail: + return NULL; } @@ -473,53 +489,57 @@ static char* encode_utf8(char* buffer, char32_t character) * @param string The string * @return The string in machine-readable format, `NULL` on error */ -char* parse_raw_string(const char* restrict string) +char * +parse_raw_string(const char *restrict string) { -#define r(cond, lower, upper) ((cond) && ((lower) <= c) && (c <= (upper))) - char* rc; - char* p; - int escape = 0; - char32_t buf = 0; - char c; - - /* We know that the output string can only be shorter because - * it is surrounded by 2 quotes and escape can only be longer - * then what they escape, for example \uA0, is four characters, - * but when parsed it generateds 2 bytes in UTF-8, and their - * is not code point whose UTF-8 encoding is longer than its - * hexadecimal representation. */ - fail_if (xmalloc(p = rc, strlen(string), char)); - - while ((c = *string++)) - if (r(escape == 8, '0', '7')) buf = (buf << 3) | (c & 15); - else if (r(escape == 16, '0', '9')) buf = (buf << 4) | (c & 15); - else if (r(escape == 16, 'a', 'f')) buf = (buf << 4) | ((c & 15) + 9); - else if (r(escape == 16, 'A', 'F')) buf = (buf << 4) | ((c & 15) + 9); - else if (escape > 1) - { - escape = 0; - fail_if ((p = encode_utf8(p, buf), p == NULL)); - if (c != '.') - *p++ = c; - } - else if (escape == 1) - { - escape = 0, buf = 0; - switch (c) - { - case '0': escape = 8; break; - case 'u': escape = 16; break; - default: *p++ = c; break; - } - } - else if (c == '\\') escape = 1; - else if (c != '\"') *p++ = c; - - *p = '\0'; - return rc; - fail: - free(rc); - return NULL; +#define r(cond, lower, upper) ((cond) && ((lower) <= c) && (c <= (upper))) + char *rc, *p; + int escape = 0; + char32_t buf = 0; + char c; + + /* We know that the output string can only be shorter because + * it is surrounded by 2 quotes and escape can only be longer + * then what they escape, for example \uA0, is four characters, + * but when parsed it generateds 2 bytes in UTF-8, and their + * is not code point whose UTF-8 encoding is longer than its + * hexadecimal representation. */ + fail_if (xmalloc(p = rc, strlen(string), char)); + + while ((c = *string++)) { + if (r(escape == 8, '0', '7')) { + buf = (buf << 3) | (c & 15); + } else if (r(escape == 16, '0', '9')) { + buf = (buf << 4) | (c & 15); + } else if (r(escape == 16, 'a', 'f')) { + buf = (buf << 4) | ((c & 15) + 9); + } else if (r(escape == 16, 'A', 'F')) { + buf = (buf << 4) | ((c & 15) + 9); + } else if (escape > 1) { + escape = 0; + fail_if (!(p = encode_utf8(p, buf))); + if (c != '.') + *p++ = c; + } else if (escape == 1) { + escape = 0; + buf = 0; + if (c == '0') + escape = 8; + else if (c == 'u') + escape = 16; + else + *p++ = c; + } else if (c == '\\') { + escape = 1; + } else if (c != '\"') { + *p++ = c; + } + } + + *p = '\0'; + return rc; +fail: + free(rc); + return NULL; #undef r } - diff --git a/src/mds-kbdc/raw-data.h b/src/mds-kbdc/raw-data.h index 3638042..bdc1078 100644 --- a/src/mds-kbdc/raw-data.h +++ b/src/mds-kbdc/raw-data.h @@ -25,42 +25,40 @@ /** * Source code by lines, with and without comments */ -typedef struct mds_kbdc_source_code -{ - /** - * Source code by lines without comments, - * `NULL`-terminated. - */ - char** restrict lines; - - /** - * Source code by lines with comments, - * `NULL`-terminated. - */ - char** restrict real_lines; - - /** - * Data for `lines` (internal data) - */ - char* content; - - /** - * Data for `real_lines` (internal data) - */ - char* real_content; - - /** - * The number of lines, that is, the number of - * elements in `lines` and `real_lines`. - */ - size_t line_count; - - /** - * The number of duplicates there are of this - * structure that shared the memory - */ - size_t duplicates; - +typedef struct mds_kbdc_source_code { + /** + * Source code by lines without comments, + * `NULL`-terminated. + */ + char **restrict lines; + + /** + * Source code by lines with comments, + * `NULL`-terminated. + */ + char **restrict real_lines; + + /** + * Data for `lines` (internal data) + */ + char *content; + + /** + * Data for `real_lines` (internal data) + */ + char *real_content; + + /** + * The number of lines, that is, the number of + * elements in `lines` and `real_lines`. + */ + size_t line_count; + + /** + * The number of duplicates there are of this + * structure that shared the memory + */ + size_t duplicates; } mds_kbdc_source_code_t; @@ -69,21 +67,21 @@ typedef struct mds_kbdc_source_code * * @param this The `mds_kbdc_source_code_t*` */ -void mds_kbdc_source_code_initialise(mds_kbdc_source_code_t* restrict this); +void mds_kbdc_source_code_initialise(mds_kbdc_source_code_t *restrict this); /** * Release all data in a `mds_kbdc_source_code_t*` * * @param this The `mds_kbdc_source_code_t*` */ -void mds_kbdc_source_code_destroy(mds_kbdc_source_code_t* restrict this); +void mds_kbdc_source_code_destroy(mds_kbdc_source_code_t *restrict this); /** * Release all data in a `mds_kbdc_source_code_t*`, and free it * * @param this The `mds_kbdc_source_code_t*` */ -void mds_kbdc_source_code_free(mds_kbdc_source_code_t* restrict this); +void mds_kbdc_source_code_free(mds_kbdc_source_code_t *restrict this); /** * Create a duplicate of a `mds_kbdc_source_code_t*` @@ -91,7 +89,7 @@ void mds_kbdc_source_code_free(mds_kbdc_source_code_t* restrict this); * @param this The `mds_kbdc_source_code_t*` * @return `this` is returned */ -mds_kbdc_source_code_t* mds_kbdc_source_code_dup(mds_kbdc_source_code_t* restrict this); +mds_kbdc_source_code_t *mds_kbdc_source_code_dup(mds_kbdc_source_code_t *restrict this); /** @@ -106,7 +104,8 @@ mds_kbdc_source_code_t* mds_kbdc_source_code_dup(mds_kbdc_source_code_t* restric * or `size` if the call do not end (that is, the code ends * prematurely), or zero if there is no function call at `offset` */ -size_t get_end_of_call(const char* restrict content, size_t offset, size_t size) __attribute__((pure)); +__attribute__((pure)) +size_t get_end_of_call(const char *restrict content, size_t offset, size_t size); /** * Read lines of a source file @@ -115,7 +114,7 @@ size_t get_end_of_call(const char* restrict content, size_t offset, size_t size) * @param source_code Output parameter for read data * @return Zero on success, -1 on error */ -int read_source_lines(const char* restrict pathname, mds_kbdc_source_code_t* restrict source_code); +int read_source_lines(const char *restrict pathname, mds_kbdc_source_code_t *restrict source_code); /** @@ -124,8 +123,7 @@ int read_source_lines(const char* restrict pathname, mds_kbdc_source_code_t* res * @param string The string * @return The string in machine-readable format, `NULL` on error */ -char* parse_raw_string(const char* restrict string); +char *parse_raw_string(const char *restrict string); #endif - diff --git a/src/mds-kbdc/simplify-tree.c b/src/mds-kbdc/simplify-tree.c index d559e2e..b3f588c 100644 --- a/src/mds-kbdc/simplify-tree.c +++ b/src/mds-kbdc/simplify-tree.c @@ -27,13 +27,13 @@ /** * This process's value for `mds_kbdc_tree_t.processed` */ -#define PROCESS_LEVEL 2 +#define PROCESS_LEVEL 2 /** * Tree type constant shortener */ -#define C(TYPE) MDS_KBDC_TREE_TYPE_##TYPE +#define C(TYPE) MDS_KBDC_TREE_TYPE_##TYPE /** @@ -44,9 +44,9 @@ * @param ...:const char*, ... Error description format string and arguments * @scope error:mds_kbdc_parse_error_t* Variable where the new error will be stored */ -#define NEW_ERROR(NODE, SEVERITY, ...) \ - NEW_ERROR_(result, SEVERITY, 1, (NODE)->loc_line, \ - (NODE)->loc_start, (NODE)->loc_end, 1, __VA_ARGS__) +#define NEW_ERROR(NODE, SEVERITY, ...)\ + NEW_ERROR_(result, SEVERITY, 1, (NODE)->loc_line,\ + (NODE)->loc_start, (NODE)->loc_end, 1, __VA_ARGS__) @@ -58,25 +58,25 @@ * @scope here:mds_kbdc_tree_t** Help variable that must be available for use * @scope argument:mds_kbdc_tree_t* Help variable that must be available for use */ -#define REMOVE_NOTHING(START) \ - do \ - { \ - long processed = tree->processed; \ - tree->processed = PROCESS_LEVEL; \ - for (here = &(tree->START); *here;) \ - if ((*here)->type != C(NOTHING)) \ - here = &((*here)->next); \ - else \ - while (*here && (*here)->type == C(NOTHING)) \ - { \ - argument = (*here)->next, (*here)->next = NULL; \ - if ((processed != PROCESS_LEVEL) && ((*here)->processed != PROCESS_LEVEL)) \ - NEW_ERROR(*here, WARNING, "‘.’ outside alternation has no effect"); \ - mds_kbdc_tree_free(*here); \ - *here = argument; \ - } \ - } \ - while (0) +#define REMOVE_NOTHING(START)\ + do {\ + long int processed = tree->processed;\ + tree->processed = PROCESS_LEVEL;\ + for (here = &(tree->START); *here;) {\ + if ((*here)->type != C(NOTHING)) {\ + here = &((*here)->next);\ + } else {\ + while (*here && (*here)->type == C(NOTHING)) {\ + argument = (*here)->next;\ + (*here)->next = NULL;\ + if (processed != PROCESS_LEVEL && (*here)->processed != PROCESS_LEVEL)\ + NEW_ERROR(*here, WARNING, "‘.’ outside alternation has no effect");\ + mds_kbdc_tree_free(*here);\ + *here = argument;\ + }\ + }\ + }\ + } while (0) @@ -89,38 +89,36 @@ * @scope here:mds_kbdc_tree_t** Pointer to the space where the argument was found * @scope temp:mds_kbdc_tree_t* Help variable that must be available for use */ -#define FLATTEN(argument) \ - do \ - { \ - /* Remember the alternation/subsequence and the argument that follows it. */ \ - mds_kbdc_tree_t* eliminated_argument = argument; \ - temp = argument->next; \ - /* Find the last alternative/element. */ \ - for (argument->next = argument->ordered.inner; argument->next;) \ - argument = argument->next; \ - /* Attach the argument that was after the alternation/subsequence to the */ \ - /* end of the alternation/subsequence, that is, flatten the right side. */ \ - argument->next = temp; \ - /* Flatten the left side. */ \ - *here = eliminated_argument->next; \ - /* Free the memory of the alternation/subsequence. */ \ - eliminated_argument->ordered.inner = NULL; \ - eliminated_argument->next = NULL; \ - mds_kbdc_tree_free(eliminated_argument); \ - } \ - while (0) +#define FLATTEN(argument)\ + do {\ + /* Remember the alternation/subsequence and the argument that follows it. */\ + mds_kbdc_tree_t *eliminated_argument = argument;\ + temp = argument->next;\ + /* Find the last alternative/element. */\ + for (argument->next = argument->ordered.inner; argument->next;)\ + argument = argument->next;\ + /* Attach the argument that was after the alternation/subsequence to the */\ + /* end of the alternation/subsequence, that is, flatten the right side. */\ + argument->next = temp;\ + /* Flatten the left side. */\ + *here = eliminated_argument->next;\ + /* Free the memory of the alternation/subsequence. */\ + eliminated_argument->ordered.inner = NULL;\ + eliminated_argument->next = NULL;\ + mds_kbdc_tree_free(eliminated_argument);\ + } while (0) /** * Variable whether the latest created error is stored */ -static mds_kbdc_parse_error_t* error; +static mds_kbdc_parse_error_t *error; /** * The parameter of `simplify_tree` */ -static mds_kbdc_parsed_t* restrict result; +static mds_kbdc_parsed_t *restrict result; @@ -130,7 +128,7 @@ static mds_kbdc_parsed_t* restrict result; * @param tree The tree * @return Zero on success, -1 on error */ -static int simplify(mds_kbdc_tree_t* restrict tree); +static int simplify(mds_kbdc_tree_t *restrict tree); /** * Simplify an unordered subsequence-subtree @@ -138,7 +136,7 @@ static int simplify(mds_kbdc_tree_t* restrict tree); * @param tree The unordered subsequence-subtree * @return Zero on success, -1 on error */ -static int simplify_unordered(mds_kbdc_tree_unordered_t* restrict tree); +static int simplify_unordered(mds_kbdc_tree_unordered_t *restrict tree); @@ -150,60 +148,61 @@ static int simplify_unordered(mds_kbdc_tree_unordered_t* restrict tree); * @param argument_index The index of the argument to eliminate * @return Zero on sucess, -1 on error */ -static int eliminate_alternation(mds_kbdc_tree_t* tree, mds_kbdc_tree_t* argument, size_t argument_index) +static int +eliminate_alternation(mds_kbdc_tree_t *tree, mds_kbdc_tree_t *argument, size_t argument_index) { - mds_kbdc_tree_t** here; - mds_kbdc_tree_t* first; - mds_kbdc_tree_t* last; - mds_kbdc_tree_t* new_tree; - mds_kbdc_tree_t* alternative; - mds_kbdc_tree_t* next_statement; - mds_kbdc_tree_t* next_alternative; - mds_kbdc_tree_t* new_argument; - size_t i; - int saved_errno; - - /* Detach next statement, we do not want to duplicate all following statements. */ - next_statement = tree->next, tree->next = NULL; - /* Detach alternation, we replace it in all duplcates, - no need to duplicate all alternatives. */ - alternative = argument->alternation.inner, argument->alternation.inner = NULL; - /* Eliminate. */ - for (first = last = NULL; alternative; alternative = next_alternative) - { - /* Duplicate statement. */ - fail_if (new_tree = mds_kbdc_tree_dup(tree), new_tree == NULL); - /* Join trees. */ - if (last) - last->next = new_tree; - last = new_tree; - first = first ? first : new_tree; - /* Jump to the alternation. */ - here = &(new_tree->macro_call.arguments); /* `new_tree->macro_call.arguments` and - * `new_tree->map.sequence` as the same address. */ - for (new_argument = *here, i = 0; i < argument_index; i++, here = &((*here)->next)) - new_argument = new_argument->next; - /* Detach alternative. */ - next_alternative = alternative->next; - /* Right-join alternative. */ - alternative->next = new_argument->next, new_argument->next = NULL; - mds_kbdc_tree_free(new_argument); - /* Left-join alternative. */ - *here = alternative; - } - /* Replace the statement with the first generated statement without the alternation. */ - mds_kbdc_tree_destroy((mds_kbdc_tree_t*)tree); - memcpy(tree, first, sizeof(mds_kbdc_tree_t)); - if (first == last) last = (mds_kbdc_tree_t*)tree; - free(first); - /* Reattach the statement that followed to the last generated statement. */ - last->next = next_statement; - return 0; - fail: - saved_errno = errno; - argument->alternation.inner = alternative; - tree->next = next_statement; - return errno = saved_errno, -1; + mds_kbdc_tree_t **here; + mds_kbdc_tree_t *first; + mds_kbdc_tree_t *last; + mds_kbdc_tree_t *new_tree; + mds_kbdc_tree_t *alternative; + mds_kbdc_tree_t *next_statement; + mds_kbdc_tree_t *next_alternative; + mds_kbdc_tree_t *new_argument; + size_t i; + int saved_errno; + + /* Detach next statement, we do not want to duplicate all following statements. */ + next_statement = tree->next, tree->next = NULL; + /* Detach alternation, we replace it in all duplcates, + no need to duplicate all alternatives. */ + alternative = argument->alternation.inner, argument->alternation.inner = NULL; + /* Eliminate. */ + for (first = last = NULL; alternative; alternative = next_alternative) { + /* Duplicate statement. */ + fail_if (!(new_tree = mds_kbdc_tree_dup(tree))); + /* Join trees. */ + if (last) + last->next = new_tree; + last = new_tree; + first = first ? first : new_tree; + /* Jump to the alternation. */ + here = &(new_tree->macro_call.arguments); /* `new_tree->macro_call.arguments` and + * `new_tree->map.sequence` as the same address. */ + for (new_argument = *here, i = 0; i < argument_index; i++, here = &((*here)->next)) + new_argument = new_argument->next; + /* Detach alternative. */ + next_alternative = alternative->next; + /* Right-join alternative. */ + alternative->next = new_argument->next, new_argument->next = NULL; + mds_kbdc_tree_free(new_argument); + /* Left-join alternative. */ + *here = alternative; + } + /* Replace the statement with the first generated statement without the alternation. */ + mds_kbdc_tree_destroy((mds_kbdc_tree_t*)tree); + memcpy(tree, first, sizeof(mds_kbdc_tree_t)); + if (first == last) + last = (mds_kbdc_tree_t*)tree; + free(first); + /* Reattach the statement that followed to the last generated statement. */ + last->next = next_statement; + return 0; +fail: + saved_errno = errno; + argument->alternation.inner = alternative; + tree->next = next_statement; + return errno = saved_errno, -1; } @@ -213,118 +212,119 @@ static int eliminate_alternation(mds_kbdc_tree_t* tree, mds_kbdc_tree_t* argumen * @param tree The macro call-subtree * @return Zero on success, -1 on error */ -static int simplify_macro_call(mds_kbdc_tree_macro_call_t* restrict tree) +static int +simplify_macro_call(mds_kbdc_tree_macro_call_t *restrict tree) { - mds_kbdc_tree_t* argument; - mds_kbdc_tree_t* dup_arguments = NULL; - mds_kbdc_tree_t** here; - char* full_macro_name; - size_t argument_index = 0; - int saved_errno; - - /* Simplify arguments. */ - for (argument = tree->arguments; argument; argument = argument->next) - fail_if (simplify(argument)); - - /* Remove ‘.’:s. */ - REMOVE_NOTHING(arguments); - - /* Copy arguments. */ - if (tree->arguments == NULL) - goto no_args; - fail_if (dup_arguments = mds_kbdc_tree_dup(tree->arguments), dup_arguments == NULL); - - /* Eliminate alterations. */ - for (argument = dup_arguments; argument; argument = argument->next, argument_index++) - if (argument->type == C(ALTERNATION)) - fail_if (eliminate_alternation((mds_kbdc_tree_t*)tree, argument, argument_index)); - mds_kbdc_tree_free(dup_arguments), dup_arguments = NULL; - - /* Add argument count suffix. */ - no_args: - for (argument_index = 0, argument = tree->arguments; argument; argument = argument->next) - argument_index++; - fail_if (xasprintf(full_macro_name, "%s/%zu", tree->name, argument_index)); - free(tree->name), tree->name = full_macro_name; - - /* Example of what will happend: - * - * my_macro([1 2] [1 2] [1 2]) ## call 1 - * - * simplify_macro_call on call 1 - * after processing argument 1 - * my_macro(1 [1 2] [1 2]) ## call 1 - * my_macro(2 [1 2] [1 2]) ## call 5 - * after processing argument 2 - * my_macro(1 1 [1 2]) ## call 1 - * my_macro(1 2 [1 2]) ## call 3 - * my_macro(2 [1 2] [1 2]) ## call 5 - * after processing argument 3 - * my_macro(1 1 1) ## call 1 - * my_macro(1 1 2) ## call 2 - * my_macro(1 2 [1 2]) ## call 3 - * my_macro(2 [1 2] [1 2]) ## call 5 - * - * no difference after simplify_macro_call on call 2 - * - * simplify_macro_call on call 3 - * no difference after processing argument 1 - * no difference after processing argument 2 - * after processing argument 3 - * my_macro(1 1 1) ## (call 1) - * my_macro(1 1 2) ## (call 2) - * my_macro(1 2 1) ## call 3 - * my_macro(1 2 1) ## call 4 - * my_macro(2 [1 2] [1 2]) ## call 5 - * - * no difference after simplify_macro_call on call 4 - * - * simplify_macro_call on call 5 - * no difference after processing argument 1 - * after processing argument 2 - * my_macro(1 1 1) ## (call 1) - * my_macro(1 1 2) ## (call 2) - * my_macro(1 2 1) ## (call 3) - * my_macro(1 2 2) ## (call 4) - * my_macro(2 1 [1 2]) ## call 5 - * my_macro(2 2 [1 2]) ## call 7 - * after processing argument 3 - * my_macro(1 1 1) ## (call 1) - * my_macro(1 1 2) ## (call 2) - * my_macro(1 2 1) ## (call 3) - * my_macro(1 2 2) ## (call 4) - * my_macro(2 1 1) ## call 5 - * my_macro(2 1 2) ## call 6 - * my_macro(2 2 [1 2]) ## call 7 - * - * no difference after simplify_macro_call on call 6 - * - * simplify_macro_call on call 7 - * no difference after processing argument 1 - * no difference after processing argument 2 - * after processing argument 3 - * my_macro(1 1 1) ## (call 1) - * my_macro(1 1 2) ## (call 2) - * my_macro(1 2 1) ## (call 3) - * my_macro(1 2 2) ## (call 4) - * my_macro(2 1 1) ## (call 5) - * my_macro(2 1 2) ## (call 6) - * my_macro(2 2 1) ## call 7 - * my_macro(2 2 2) ## call 8 - * - * no difference after simplify_macro_call on call 8 - * - * Nothings (‘.’) are removed before processing the alternations. - * - * It should also be noticed that all macro names are update to - * with the argument count suffix. - */ - - return 0; - fail: - saved_errno = errno; - mds_kbdc_tree_free(dup_arguments); - return errno = saved_errno, -1; + mds_kbdc_tree_t *argument; + mds_kbdc_tree_t *dup_arguments = NULL; + mds_kbdc_tree_t **here; + char *full_macro_name; + size_t argument_index = 0; + int saved_errno; + + /* Simplify arguments. */ + for (argument = tree->arguments; argument; argument = argument->next) + fail_if (simplify(argument)); + + /* Remove ‘.’:s. */ + REMOVE_NOTHING(arguments); + + /* Copy arguments. */ + if (!tree->arguments) + goto no_args; + fail_if (!(dup_arguments = mds_kbdc_tree_dup(tree->arguments))); + + /* Eliminate alterations. */ + for (argument = dup_arguments; argument; argument = argument->next, argument_index++) + if (argument->type == C(ALTERNATION)) + fail_if (eliminate_alternation((mds_kbdc_tree_t*)tree, argument, argument_index)); + mds_kbdc_tree_free(dup_arguments), dup_arguments = NULL; + + /* Add argument count suffix. */ +no_args: + for (argument_index = 0, argument = tree->arguments; argument; argument = argument->next) + argument_index++; + fail_if (xasprintf(full_macro_name, "%s/%zu", tree->name, argument_index)); + free(tree->name), tree->name = full_macro_name; + + /* Example of what will happend: + * + * my_macro([1 2] [1 2] [1 2]) ## call 1 + * + * simplify_macro_call on call 1 + * after processing argument 1 + * my_macro(1 [1 2] [1 2]) ## call 1 + * my_macro(2 [1 2] [1 2]) ## call 5 + * after processing argument 2 + * my_macro(1 1 [1 2]) ## call 1 + * my_macro(1 2 [1 2]) ## call 3 + * my_macro(2 [1 2] [1 2]) ## call 5 + * after processing argument 3 + * my_macro(1 1 1) ## call 1 + * my_macro(1 1 2) ## call 2 + * my_macro(1 2 [1 2]) ## call 3 + * my_macro(2 [1 2] [1 2]) ## call 5 + * + * no difference after simplify_macro_call on call 2 + * + * simplify_macro_call on call 3 + * no difference after processing argument 1 + * no difference after processing argument 2 + * after processing argument 3 + * my_macro(1 1 1) ## (call 1) + * my_macro(1 1 2) ## (call 2) + * my_macro(1 2 1) ## call 3 + * my_macro(1 2 1) ## call 4 + * my_macro(2 [1 2] [1 2]) ## call 5 + * + * no difference after simplify_macro_call on call 4 + * + * simplify_macro_call on call 5 + * no difference after processing argument 1 + * after processing argument 2 + * my_macro(1 1 1) ## (call 1) + * my_macro(1 1 2) ## (call 2) + * my_macro(1 2 1) ## (call 3) + * my_macro(1 2 2) ## (call 4) + * my_macro(2 1 [1 2]) ## call 5 + * my_macro(2 2 [1 2]) ## call 7 + * after processing argument 3 + * my_macro(1 1 1) ## (call 1) + * my_macro(1 1 2) ## (call 2) + * my_macro(1 2 1) ## (call 3) + * my_macro(1 2 2) ## (call 4) + * my_macro(2 1 1) ## call 5 + * my_macro(2 1 2) ## call 6 + * my_macro(2 2 [1 2]) ## call 7 + * + * no difference after simplify_macro_call on call 6 + * + * simplify_macro_call on call 7 + * no difference after processing argument 1 + * no difference after processing argument 2 + * after processing argument 3 + * my_macro(1 1 1) ## (call 1) + * my_macro(1 1 2) ## (call 2) + * my_macro(1 2 1) ## (call 3) + * my_macro(1 2 2) ## (call 4) + * my_macro(2 1 1) ## (call 5) + * my_macro(2 1 2) ## (call 6) + * my_macro(2 2 1) ## call 7 + * my_macro(2 2 2) ## call 8 + * + * no difference after simplify_macro_call on call 8 + * + * Nothings (‘.’) are removed before processing the alternations. + * + * It should also be noticed that all macro names are update to + * with the argument count suffix. + */ + + return 0; +fail: + saved_errno = errno; + mds_kbdc_tree_free(dup_arguments); + return errno = saved_errno, -1; } @@ -334,26 +334,27 @@ static int simplify_macro_call(mds_kbdc_tree_macro_call_t* restrict tree) * @param tree The value statement-tree * @return Zero on success, -1 on error */ -static int check_value_statement_before_simplification(mds_kbdc_tree_map_t* restrict tree) +static int +check_value_statement_before_simplification(mds_kbdc_tree_map_t *restrict tree) { - again: - /* Check for alternation. */ - if ((tree->sequence->type == C(ALTERNATION)) && (tree->processed != PROCESS_LEVEL)) - NEW_ERROR(tree->sequence, WARNING, - "alternated value statement is undefined unless the alternatives are identical"); - - /* Check for unordered. */ - if (tree->sequence->type != C(UNORDERED)) - return 0; - if (tree->processed != PROCESS_LEVEL) - NEW_ERROR(tree->sequence, WARNING, "use of sequence in value statement is discouraged"); - - /* Simplify argument and start over. */ - fail_if (simplify(tree->sequence)); - goto again; - - fail: - return -1; +again: + /* Check for alternation. */ + if (tree->sequence->type == C(ALTERNATION) && tree->processed != PROCESS_LEVEL) + NEW_ERROR(tree->sequence, WARNING, + "alternated value statement is undefined unless the alternatives are identical"); + + /* Check for unordered. */ + if (tree->sequence->type != C(UNORDERED)) + return 0; + if (tree->processed != PROCESS_LEVEL) + NEW_ERROR(tree->sequence, WARNING, "use of sequence in value statement is discouraged"); + + /* Simplify argument and start over. */ + fail_if (simplify(tree->sequence)); + goto again; + +fail: + return -1; } @@ -363,19 +364,20 @@ static int check_value_statement_before_simplification(mds_kbdc_tree_map_t* rest * @param tree The value statement-tree * @return Zero on success, -1 on error */ -static int check_value_statement_after_simplification(mds_kbdc_tree_map_t* restrict tree) +static int +check_value_statement_after_simplification(mds_kbdc_tree_map_t *restrict tree) { - /* Check that there is only one value. */ - if (tree->sequence->next) - NEW_ERROR(tree->sequence->next, ERROR, "more the one value in value statement"); - - /* Check the type of the value */ - if (tree->sequence->type != C(STRING)) - NEW_ERROR(tree->sequence, ERROR, "bad value type"); - - return 0; - fail: - return -1; + /* Check that there is only one value. */ + if (tree->sequence->next) + NEW_ERROR(tree->sequence->next, ERROR, "more the one value in value statement"); + + /* Check the type of the value */ + if (tree->sequence->type != C(STRING)) + NEW_ERROR(tree->sequence, ERROR, "bad value type"); + + return 0; +fail: + return -1; } @@ -385,155 +387,154 @@ static int check_value_statement_after_simplification(mds_kbdc_tree_map_t* restr * @param tree The mapping-subtree * @return Zero on success, -1 on error */ -static int simplify_map(mds_kbdc_tree_map_t* restrict tree) +static int +simplify_map(mds_kbdc_tree_map_t *restrict tree) { - mds_kbdc_tree_t* argument; - mds_kbdc_tree_t** here; - mds_kbdc_tree_t* dup_sequence = NULL; - mds_kbdc_tree_t* temp; - size_t argument_index; - int redo = 0, need_reelimination, saved_errno; - - /* Check for bad things in the result. */ - for (argument = tree->result; argument; argument = argument->next) - if ((argument->type != C(KEYS)) && (argument->type != C(STRING))) - NEW_ERROR(argument, ERROR, "not allowed in mapping output"); - - /* Valid value properties. */ - if (tree->result == NULL) - fail_if (check_value_statement_before_simplification(tree)); - - /* Simplify sequence. */ - for (argument = tree->sequence; argument; argument = argument->next) - fail_if (simplify(argument)); - - /* Test predicted emptyness. */ - for (argument = tree->sequence; argument; argument = argument->next) - if (argument->type != C(NOTHING)) - goto will_not_be_empty; - if (tree->sequence->processed != PROCESS_LEVEL) - { - if (tree->result) - NEW_ERROR(tree->sequence, ERROR, "mapping of null sequence"); - else - NEW_ERROR(tree->sequence, ERROR, "nothing in value statement"); - } - /* The tree parsing process will not allow a mapping statement - * to start with a ‘.’. Thus if we select to highlight it we - * know that it is either an empty alternation, an empty - * unordered subsequence or a nothing inside an alternation. - * If it is already been processed by the simplifier, it is an - * error because it is an empty alternation or empty unordered - * subsequence, and there is not reason to print an additional - * error. If however it is a nothing inside an alternation we - * know that it is the cause of the error, however possibily - * in conjunction with additional such constructs, but those - * are harder to locate. */ - return 0; - will_not_be_empty: - - /* Remove ‘.’:s. */ - REMOVE_NOTHING(sequence); - - /* Because unordered are simplified to alternations of ordered subsequences, which - in turn can contain alternations, possibiled from simplification of nested - unordered sequenceses, we need to reeliminated until there are not alternations. */ - for (need_reelimination = 1; need_reelimination ? (need_reelimination = 0, 1) : 0; redo = 0) - { - /* Copy sequence. */ - fail_if (dup_sequence = mds_kbdc_tree_dup(tree->sequence), dup_sequence == NULL); - - /* Eliminate alterations, remember, unordered subsequences have - been simplified to alternations of ordered subsequences. */ - for (argument_index = 0, argument = dup_sequence; argument; argument = argument->next, argument_index++) - if (argument->type == C(ALTERNATION)) - fail_if (eliminate_alternation((mds_kbdc_tree_t*)tree, argument, argument_index)); - - mds_kbdc_tree_free(dup_sequence), dup_sequence = NULL; - - /* Eliminated ordered subsequences. */ - for (here = &(tree->sequence); (argument = *here); redo ? (redo = 0) : (here = &(argument->next), 0)) - if (argument->type == C(ORDERED)) - { - FLATTEN(argument); - redo = 1; - } - else if (argument->type == C(ALTERNATION)) - need_reelimination = 1; - } - - /* Valid value properties. */ - if (tree->result == NULL) - fail_if (check_value_statement_after_simplification(tree)); - - /* Mapping statements are simplified in a manner similar - * to how macro calls are simplified. However mapping - * statements can also contain unordered subsequences, - * there are translated into alternations of ordered - * subsequences. Thus after the elimination of alternations, - * ordered subsequences are eliminated too. - * - * Example of what will happen, ‘{ }’ represents an - * ordered subsequence: - * - * (1 2) (3 4) : 0 ## mapping 1 - * - * simplify_map on mapping 1 - * after simplification - * [{1 2} {2 1}] [{3 4} {4 3}] ## mapping 1 - * after alternation elimination on argument 1 - * {1 2} [{3 4} {4 3}] ## mapping 1 - * {2 1} [{3 4} {4 3}] ## mapping 3 - * after alternation elimination on argument 2 - * {1 2} {3 4} ## mapping 1 - * {1 2} {4 3} ## mapping 2 - * {2 1} [{3 4} {4 3}] ## mapping 3 - * after ordered subsequence elimination - * 1 2 3 4 ## mapping 1 - * {1 2} {4 3} ## mapping 2 - * {2 1} [{3 4} {4 3}] ## mapping 3 - * - * simplify_map on mapping 2 - * no difference after simplification - * no difference after alternation elimination on argument 1 - * no difference after alternation elimination on argument 2 - * after ordered subsequence elimination - * 1 2 3 4 ## (mapping 1) - * 1 2 4 3 ## mapping 2 - * {2 1} [{3 4} {4 3}] ## mapping 3 - * - * simplify_map on mapping 3 - * no difference after simplification - * no difference after alternation elimination on argument 1 - * after alternation elimination on argument 2 - * 1 2 3 4 ## (mapping 1) - * 1 2 4 3 ## (mapping 2) - * {2 1} {3 4} ## mapping 3 - * {2 1} {4 3} ## mapping 4 - * after ordered subsequence elimination - * 1 2 3 4 ## (mapping 1) - * 1 2 4 3 ## (mapping 2) - * 2 1 3 4 ## mapping 3 - * {2 1} {4 3} ## mapping 4 - * - * simplify_map on mapping 4 - * no difference after simplification - * no difference after alternation elimination on argument 1 - * no difference after alternation elimination on argument 2 - * after ordered subsequence elimination - * 1 2 3 4 ## (mapping 1) - * 1 2 4 3 ## (mapping 2) - * 2 1 3 4 ## (mapping 3) - * 2 1 4 3 ## mapping 4 - * - * Nothings (‘.’) are removed before processing the alternations. - */ - - return 0; - fail: - saved_errno = errno; - mds_kbdc_tree_free(dup_sequence); - return errno = saved_errno, -1; + mds_kbdc_tree_t *argument; + mds_kbdc_tree_t **here; + mds_kbdc_tree_t *dup_sequence = NULL; + mds_kbdc_tree_t *temp; + size_t argument_index; + int redo = 0, need_reelimination, saved_errno; + + /* Check for bad things in the result. */ + for (argument = tree->result; argument; argument = argument->next) + if (argument->type != C(KEYS) && argument->type != C(STRING)) + NEW_ERROR(argument, ERROR, "not allowed in mapping output"); + + /* Valid value properties. */ + if (!tree->result) + fail_if (check_value_statement_before_simplification(tree)); + + /* Simplify sequence. */ + for (argument = tree->sequence; argument; argument = argument->next) + fail_if (simplify(argument)); + + /* Test predicted emptyness. */ + for (argument = tree->sequence; argument; argument = argument->next) + if (argument->type != C(NOTHING)) + goto will_not_be_empty; + if (tree->sequence->processed != PROCESS_LEVEL) { + if (tree->result) + NEW_ERROR(tree->sequence, ERROR, "mapping of null sequence"); + else + NEW_ERROR(tree->sequence, ERROR, "nothing in value statement"); + } + /* The tree parsing process will not allow a mapping statement + * to start with a ‘.’. Thus if we select to highlight it we + * know that it is either an empty alternation, an empty + * unordered subsequence or a nothing inside an alternation. + * If it is already been processed by the simplifier, it is an + * error because it is an empty alternation or empty unordered + * subsequence, and there is not reason to print an additional + * error. If however it is a nothing inside an alternation we + * know that it is the cause of the error, however possibily + * in conjunction with additional such constructs, but those + * are harder to locate. */ + return 0; +will_not_be_empty: + + /* Remove ‘.’:s. */ + REMOVE_NOTHING(sequence); + + /* Because unordered are simplified to alternations of ordered subsequences, which + in turn can contain alternations, possibiled from simplification of nested + unordered sequenceses, we need to reeliminated until there are not alternations. */ + for (need_reelimination = 1; need_reelimination ? (need_reelimination = 0, 1) : 0; redo = 0) { + /* Copy sequence. */ + fail_if (!(dup_sequence = mds_kbdc_tree_dup(tree->sequence))); + + /* Eliminate alterations, remember, unordered subsequences have + been simplified to alternations of ordered subsequences. */ + for (argument_index = 0, argument = dup_sequence; argument; argument = argument->next, argument_index++) + if (argument->type == C(ALTERNATION)) + fail_if (eliminate_alternation((mds_kbdc_tree_t*)tree, argument, argument_index)); + + mds_kbdc_tree_free(dup_sequence), dup_sequence = NULL; + + /* Eliminated ordered subsequences. */ + for (here = &(tree->sequence); (argument = *here); redo ? (redo = 0) : (here = &(argument->next), 0)) { + if (argument->type == C(ORDERED)) { + FLATTEN(argument); + redo = 1; + } else if (argument->type == C(ALTERNATION)) { + need_reelimination = 1; + } + } + } + + /* Valid value properties. */ + if (!tree->result) + fail_if (check_value_statement_after_simplification(tree)); + + /* Mapping statements are simplified in a manner similar + * to how macro calls are simplified. However mapping + * statements can also contain unordered subsequences, + * there are translated into alternations of ordered + * subsequences. Thus after the elimination of alternations, + * ordered subsequences are eliminated too. + * + * Example of what will happen, ‘{ }’ represents an + * ordered subsequence: + * + * (1 2) (3 4) : 0 ## mapping 1 + * + * simplify_map on mapping 1 + * after simplification + * [{1 2} {2 1}] [{3 4} {4 3}] ## mapping 1 + * after alternation elimination on argument 1 + * {1 2} [{3 4} {4 3}] ## mapping 1 + * {2 1} [{3 4} {4 3}] ## mapping 3 + * after alternation elimination on argument 2 + * {1 2} {3 4} ## mapping 1 + * {1 2} {4 3} ## mapping 2 + * {2 1} [{3 4} {4 3}] ## mapping 3 + * after ordered subsequence elimination + * 1 2 3 4 ## mapping 1 + * {1 2} {4 3} ## mapping 2 + * {2 1} [{3 4} {4 3}] ## mapping 3 + * + * simplify_map on mapping 2 + * no difference after simplification + * no difference after alternation elimination on argument 1 + * no difference after alternation elimination on argument 2 + * after ordered subsequence elimination + * 1 2 3 4 ## (mapping 1) + * 1 2 4 3 ## mapping 2 + * {2 1} [{3 4} {4 3}] ## mapping 3 + * + * simplify_map on mapping 3 + * no difference after simplification + * no difference after alternation elimination on argument 1 + * after alternation elimination on argument 2 + * 1 2 3 4 ## (mapping 1) + * 1 2 4 3 ## (mapping 2) + * {2 1} {3 4} ## mapping 3 + * {2 1} {4 3} ## mapping 4 + * after ordered subsequence elimination + * 1 2 3 4 ## (mapping 1) + * 1 2 4 3 ## (mapping 2) + * 2 1 3 4 ## mapping 3 + * {2 1} {4 3} ## mapping 4 + * + * simplify_map on mapping 4 + * no difference after simplification + * no difference after alternation elimination on argument 1 + * no difference after alternation elimination on argument 2 + * after ordered subsequence elimination + * 1 2 3 4 ## (mapping 1) + * 1 2 4 3 ## (mapping 2) + * 2 1 3 4 ## (mapping 3) + * 2 1 4 3 ## mapping 4 + * + * Nothings (‘.’) are removed before processing the alternations. + */ + + return 0; +fail: + saved_errno = errno; + mds_kbdc_tree_free(dup_sequence); + return errno = saved_errno, -1; } @@ -543,69 +544,63 @@ static int simplify_map(mds_kbdc_tree_map_t* restrict tree) * @param tree The alternation-subtree * @return Zero on success, -1 on error */ -static int simplify_alternation(mds_kbdc_tree_alternation_t* restrict tree) +static int +simplify_alternation(mds_kbdc_tree_alternation_t *restrict tree) { - mds_kbdc_tree_t* argument; - mds_kbdc_tree_t* first_nothing = NULL; - mds_kbdc_tree_t* temp; - mds_kbdc_tree_t** here; - int redo = 0; - - /* Test emptyness. */ - if (tree->inner == NULL) - { - NEW_ERROR(tree, ERROR, "empty alternation"); - tree->type = C(NOTHING); - tree->processed = PROCESS_LEVEL; - return 0; - } - - /* Test singletonness. */ - if (tree->inner->next == NULL) - { - temp = tree->inner; - NEW_ERROR(tree, WARNING, "singleton alternation"); - memcpy(tree, temp, sizeof(mds_kbdc_tree_t)); - free(temp); - fail_if (simplify((mds_kbdc_tree_t*)tree)); - return 0; - } - - /* Simplify. */ - for (here = &(tree->inner); (argument = *here); redo ? (redo = 0) : (here = &(argument->next), 0)) - if ((argument->type == C(NOTHING)) && (argument->processed != PROCESS_LEVEL)) - { - /* Test multiple nothings. */ - if (first_nothing == NULL) - first_nothing = argument; - else - { - NEW_ERROR(argument, WARNING, "multiple ‘.’ inside an alternation"); - NEW_ERROR(first_nothing, NOTE, "first ‘.’ was here"); - } - } - else if (argument->type == C(ALTERNATION)) - { - /* Alternation nesting. */ - if (argument->processed != PROCESS_LEVEL) - NEW_ERROR(argument, WARNING, "alternation inside alternation is unnessary"); - fail_if (simplify_alternation(&(argument->alternation))); - if (argument->type == C(ALTERNATION)) - FLATTEN(argument); - redo = 1; - } - else if (argument->type == C(UNORDERED)) - { - /* Nesting unordered subsequence, - simplifies to alternation of ordered subsequence, or simpler. */ - NEW_ERROR(argument, WARNING, "unordered subsequence inside alternation is discouraged"); - fail_if (simplify_unordered(&(argument->unordered))); - redo = 1; - } - - return 0; - fail: - return -1; + mds_kbdc_tree_t *argument; + mds_kbdc_tree_t *first_nothing = NULL; + mds_kbdc_tree_t *temp; + mds_kbdc_tree_t **here; + int redo = 0; + + /* Test emptyness. */ + if (!tree->inner) { + NEW_ERROR(tree, ERROR, "empty alternation"); + tree->type = C(NOTHING); + tree->processed = PROCESS_LEVEL; + return 0; + } + + /* Test singletonness. */ + if (!tree->inner->next) { + temp = tree->inner; + NEW_ERROR(tree, WARNING, "singleton alternation"); + memcpy(tree, temp, sizeof(mds_kbdc_tree_t)); + free(temp); + fail_if (simplify((mds_kbdc_tree_t*)tree)); + return 0; + } + + /* Simplify. */ + for (here = &(tree->inner); (argument = *here); redo ? (redo = 0) : (here = &(argument->next), 0)) { + if (argument->type == C(NOTHING) && argument->processed != PROCESS_LEVEL) { + /* Test multiple nothings. */ + if (!first_nothing) { + first_nothing = argument; + } else{ + NEW_ERROR(argument, WARNING, "multiple ‘.’ inside an alternation"); + NEW_ERROR(first_nothing, NOTE, "first ‘.’ was here"); + } + } else if (argument->type == C(ALTERNATION)) { + /* Alternation nesting. */ + if (argument->processed != PROCESS_LEVEL) + NEW_ERROR(argument, WARNING, "alternation inside alternation is unnessary"); + fail_if (simplify_alternation(&(argument->alternation))); + if (argument->type == C(ALTERNATION)) + FLATTEN(argument); + redo = 1; + } else if (argument->type == C(UNORDERED)) { + /* Nesting unordered subsequence, + simplifies to alternation of ordered subsequence, or simpler. */ + NEW_ERROR(argument, WARNING, "unordered subsequence inside alternation is discouraged"); + fail_if (simplify_unordered(&(argument->unordered))); + redo = 1; + } + } + + return 0; +fail: + return -1; } @@ -616,77 +611,75 @@ static int simplify_alternation(mds_kbdc_tree_alternation_t* restrict tree) * @param elements The subtrees, chained * @return Chain of ordered subsequence, `NULL` on error */ -static mds_kbdc_tree_t* create_permutations(mds_kbdc_tree_t* elements) +static mds_kbdc_tree_t * +create_permutations(mds_kbdc_tree_t *elements) { - mds_kbdc_tree_t* first = NULL; - mds_kbdc_tree_t** here = &first; - mds_kbdc_tree_t** previous_next = &elements; - mds_kbdc_tree_t* argument; - mds_kbdc_tree_t* temp; - mds_kbdc_tree_t* subperms = NULL; - mds_kbdc_tree_t* perm; - mds_kbdc_tree_t ordered; - int saved_errno, no_perms, stage = 0; - - /* Error case. */ - fail_if (elements == NULL); - - /* Base case. */ - if (elements->next == NULL) - { - fail_if ((first = mds_kbdc_tree_create(C(ORDERED))) == NULL); - fail_if ((first->ordered.inner = mds_kbdc_tree_dup(elements)) == NULL); - return first; - } - - stage++; - for (previous_next = &elements; (argument = *previous_next); previous_next = &((*previous_next)->next)) - { - /* Created ordered alternative for a permutation prototype. */ - mds_kbdc_tree_initialise(&ordered, C(ORDERED)); - /* Select the first element. */ - temp = argument->next, argument->next = NULL; - ordered.ordered.inner = mds_kbdc_tree_dup(argument); - argument->next = temp; - fail_if (ordered.ordered.inner == NULL); - /* Create subpermutations. */ - *previous_next = argument->next; - argument->next = NULL; - no_perms = (elements == NULL); - subperms = create_permutations(elements); - argument->next = *previous_next; - *previous_next = argument; - fail_if (no_perms ? 0 : (subperms == NULL)); - /* Join first element with subpermutations. */ - while (subperms) - { - /* Join. */ - fail_if (perm = mds_kbdc_tree_dup(&ordered), perm == NULL); - perm->ordered.inner->next = subperms->ordered.inner; - subperms->ordered.inner = NULL; - /* Add the permutation to the chain. */ - *here = perm; - here = &(perm->next); - /* Select next permutation. */ - temp = subperms; - subperms = subperms->next; - temp->next = NULL; - mds_kbdc_tree_free(temp); + mds_kbdc_tree_t *first = NULL; + mds_kbdc_tree_t **here = &first; + mds_kbdc_tree_t **previous_next = &elements; + mds_kbdc_tree_t *argument; + mds_kbdc_tree_t *temp; + mds_kbdc_tree_t *subperms = NULL; + mds_kbdc_tree_t *perm; + mds_kbdc_tree_t ordered; + int saved_errno, no_perms, stage = 0; + + /* Error case. */ + fail_if (!elements); + + /* Base case. */ + if (!elements->next) { + fail_if (!(first = mds_kbdc_tree_create(C(ORDERED)))); + fail_if (!(first->ordered.inner = mds_kbdc_tree_dup(elements))); + return first; } - /* Destroy prototype. */ - mds_kbdc_tree_destroy(&ordered); - } - - return first; - - fail: - saved_errno = errno; - mds_kbdc_tree_free(first); - mds_kbdc_tree_free(subperms); - if (stage > 0) - mds_kbdc_tree_destroy(&ordered); - errno = saved_errno; - return NULL; + + stage++; + for (previous_next = &elements; (argument = *previous_next); previous_next = &(*previous_next)->next) { + /* Created ordered alternative for a permutation prototype. */ + mds_kbdc_tree_initialise(&ordered, C(ORDERED)); + /* Select the first element. */ + temp = argument->next, argument->next = NULL; + ordered.ordered.inner = mds_kbdc_tree_dup(argument); + argument->next = temp; + fail_if (!ordered.ordered.inner); + /* Create subpermutations. */ + *previous_next = argument->next; + argument->next = NULL; + no_perms = !elements; + subperms = create_permutations(elements); + argument->next = *previous_next; + *previous_next = argument; + fail_if (no_perms && !subperms); + /* Join first element with subpermutations. */ + while (subperms) { + /* Join. */ + fail_if (!(perm = mds_kbdc_tree_dup(&ordered))); + perm->ordered.inner->next = subperms->ordered.inner; + subperms->ordered.inner = NULL; + /* Add the permutation to the chain. */ + *here = perm; + here = &perm->next; + /* Select next permutation. */ + temp = subperms; + subperms = subperms->next; + temp->next = NULL; + mds_kbdc_tree_free(temp); + } + /* Destroy prototype. */ + mds_kbdc_tree_destroy(&ordered); + } + + return first; + +fail: + saved_errno = errno; + mds_kbdc_tree_free(first); + mds_kbdc_tree_free(subperms); + if (stage > 0) + mds_kbdc_tree_destroy(&ordered); + errno = saved_errno; + return NULL; } @@ -696,105 +689,97 @@ static mds_kbdc_tree_t* create_permutations(mds_kbdc_tree_t* elements) * @param tree The unordered subsequence-subtree * @return Zero on success, -1 on error */ -static int simplify_unordered(mds_kbdc_tree_unordered_t* restrict tree) +static int +simplify_unordered(mds_kbdc_tree_unordered_t *restrict tree) { - mds_kbdc_tree_t* arguments; - mds_kbdc_tree_t* argument; - mds_kbdc_tree_t* temp; - mds_kbdc_tree_t** here; - int allow_long = 0; - size_t argument_count; - - /* Test for ‘(( ))’. */ - if (tree->inner && (tree->inner->next == NULL) && (tree->inner->type == C(UNORDERED))) - { - tree->loc_end = tree->inner->loc_end; - temp = tree->inner; - tree->inner = tree->inner->unordered.inner; - temp->unordered.inner = NULL; - mds_kbdc_tree_free(temp); - allow_long = 1; - } - - /* Test emptyness. */ - if (tree->inner == NULL) - { - NEW_ERROR(tree, ERROR, "empty unordered subsequence"); - tree->type = C(NOTHING); - tree->processed = PROCESS_LEVEL; - return 0; - } - - /* Test singletonness. */ - if (tree->inner->next == NULL) - { - temp = tree->inner; - NEW_ERROR(tree, WARNING, "singleton unordered subsequence"); - memcpy(tree, temp, sizeof(mds_kbdc_tree_t)); - free(temp); - fail_if (simplify((mds_kbdc_tree_t*)tree)); - return -1; - } - - /* Remove ‘.’:s. */ - REMOVE_NOTHING(inner); - - /* Check that the sequnced contained anything else. */ - if (tree->inner == NULL) - { - NEW_ERROR(tree, ERROR, "unordered subsequence contained nothing else than ‘.’"); - tree->type = C(NOTHING); - tree->processed = PROCESS_LEVEL; - return 0; - } - - /* Simplify. */ - for (argument = tree->inner, argument_count = 0; argument; argument = argument->next, argument_count++) - if (argument->type == C(ALTERNATION)) - { - fail_if (simplify_alternation(&(argument->alternation))); - argument->processed = PROCESS_LEVEL; - } - else if (argument->type == C(UNORDERED)) - { - NEW_ERROR(argument, WARNING, "unordered subsequence inside unordered subsequence is discouraged"); - fail_if (simplify_unordered(&(argument->unordered))); - argument->processed = PROCESS_LEVEL; - } - - /* Check the size of the subsequence. */ - if ((argument_count > 5) && (allow_long * argv_force == 0)) - { - if (allow_long == 0) - NEW_ERROR(tree->inner, ERROR, - "unordered subsequence longer than 5 elements need double brackets"); - else if (argv_force == 0) - NEW_ERROR(tree->inner, ERROR, - "unordered subsequence of size %zu found, requires ‘--force’ to compile", argument_count); - return 0; - } - - /* Generate permutations. */ - tree->type = C(ALTERNATION); - tree->processed = PROCESS_LEVEL; - arguments = tree->inner; - if (tree->inner = create_permutations(arguments), tree->inner == NULL) - { - if (errno == 0) - { - /* `create_permutations` can return `NULL` without setting `errno` - * if it does not list any permutations. */ - NEW_ERROR_(result, INTERNAL_ERROR, 0, 0, 0, 0, 1, - "Fail to create permutations of an unordered sequence"); - return 0; + mds_kbdc_tree_t *arguments; + mds_kbdc_tree_t *argument; + mds_kbdc_tree_t *temp; + mds_kbdc_tree_t **here; + int allow_long = 0; + size_t argument_count; + + /* Test for ‘(( ))’. */ + if (tree->inner && !tree->inner->next && tree->inner->type == C(UNORDERED)) { + tree->loc_end = tree->inner->loc_end; + temp = tree->inner; + tree->inner = tree->inner->unordered.inner; + temp->unordered.inner = NULL; + mds_kbdc_tree_free(temp); + allow_long = 1; } - fail_if (tree->inner = arguments, 1); - } - mds_kbdc_tree_free(arguments); - - return 0; - fail: - return -1; + + /* Test emptyness. */ + if (!tree->inner) { + NEW_ERROR(tree, ERROR, "empty unordered subsequence"); + tree->type = C(NOTHING); + tree->processed = PROCESS_LEVEL; + return 0; + } + + /* Test singletonness. */ + if (!tree->inner->next) { + temp = tree->inner; + NEW_ERROR(tree, WARNING, "singleton unordered subsequence"); + memcpy(tree, temp, sizeof(mds_kbdc_tree_t)); + free(temp); + fail_if (simplify((mds_kbdc_tree_t*)tree)); + return -1; + } + + /* Remove ‘.’:s. */ + REMOVE_NOTHING(inner); + + /* Check that the sequnced contained anything else. */ + if (!tree->inner) { + NEW_ERROR(tree, ERROR, "unordered subsequence contained nothing else than ‘.’"); + tree->type = C(NOTHING); + tree->processed = PROCESS_LEVEL; + return 0; + } + + /* Simplify. */ + for (argument = tree->inner, argument_count = 0; argument; argument = argument->next, argument_count++) { + if (argument->type == C(ALTERNATION)) { + fail_if (simplify_alternation(&(argument->alternation))); + argument->processed = PROCESS_LEVEL; + } else if (argument->type == C(UNORDERED)) { + NEW_ERROR(argument, WARNING, "unordered subsequence inside unordered subsequence is discouraged"); + fail_if (simplify_unordered(&(argument->unordered))); + argument->processed = PROCESS_LEVEL; + } + } + + /* Check the size of the subsequence. */ + if (argument_count > 5 && (!allow_long || !argv_force)) { + if (!allow_long) + NEW_ERROR(tree->inner, ERROR, + "unordered subsequence longer than 5 elements need double brackets"); + else if (!argv_force) + NEW_ERROR(tree->inner, ERROR, + "unordered subsequence of size %zu found, requires ‘--force’ to compile", argument_count); + return 0; + } + + /* Generate permutations. */ + tree->type = C(ALTERNATION); + tree->processed = PROCESS_LEVEL; + arguments = tree->inner; + if (!(tree->inner = create_permutations(arguments))) { + if (!errno) { + /* `create_permutations` can return `NULL` without setting `errno` + * if it does not list any permutations. */ + NEW_ERROR_(result, INTERNAL_ERROR, 0, 0, 0, 0, 1, + "Fail to create permutations of an unordered sequence"); + return 0; + } + fail_if (tree->inner = arguments, 1); + } + mds_kbdc_tree_free(arguments); + + return 0; +fail: + return -1; } @@ -804,34 +789,34 @@ static int simplify_unordered(mds_kbdc_tree_unordered_t* restrict tree) * @param tree The tree * @return Zero on success, -1 on error */ -static int simplify(mds_kbdc_tree_t* restrict tree) +static int +simplify(mds_kbdc_tree_t *restrict tree) { -#define s(expr) fail_if (simplify(tree->expr)) -#define S(type) fail_if (simplify_##type(&(tree->type))) - again: - if (tree == NULL) - return 0; - - switch (tree->type) - { - case C(INFORMATION): s (information.inner); break; - case C(FUNCTION): s (function.inner); break; - case C(MACRO): s (macro.inner); break; - case C(ASSUMPTION): s (assumption.inner); break; - case C(FOR): s (for_.inner); break; - case C(IF): s (if_.inner); s (if_.otherwise); break; - case C(MAP): S (map); break; - case C(ALTERNATION): S (alternation); break; - case C(UNORDERED): S (unordered); break; - case C(MACRO_CALL): S (macro_call); break; - default: - break; - } - - tree = tree->next; - goto again; +#define s(expr) fail_if (simplify(tree->expr)) +#define S(type) fail_if (simplify_##type(&(tree->type))) +again: + if (!tree) + return 0; + + switch (tree->type) { + case C(INFORMATION): s (information.inner); break; + case C(FUNCTION): s (function.inner); break; + case C(MACRO): s (macro.inner); break; + case C(ASSUMPTION): s (assumption.inner); break; + case C(FOR): s (for_.inner); break; + case C(IF): s (if_.inner); s (if_.otherwise); break; + case C(MAP): S (map); break; + case C(ALTERNATION): S (alternation); break; + case C(UNORDERED): S (unordered); break; + case C(MACRO_CALL): S (macro_call); break; + default: + break; + } + + tree = tree->next; + goto again; fail: - return -1; + return -1; #undef s #undef S } @@ -843,10 +828,11 @@ static int simplify(mds_kbdc_tree_t* restrict tree) * @param result_ `result` from `parse_to_tree`, same sematics, will be updated * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise */ -int simplify_tree(mds_kbdc_parsed_t* restrict result_) +int +simplify_tree(mds_kbdc_parsed_t *restrict result_) { - result = result_; - return simplify(result_->tree); + result = result_; + return simplify(result_->tree); } @@ -856,4 +842,3 @@ int simplify_tree(mds_kbdc_parsed_t* restrict result_) #undef NEW_ERROR #undef C #undef PROCESS_LEVEL - diff --git a/src/mds-kbdc/simplify-tree.h b/src/mds-kbdc/simplify-tree.h index b5e5ce2..e648a46 100644 --- a/src/mds-kbdc/simplify-tree.h +++ b/src/mds-kbdc/simplify-tree.h @@ -28,8 +28,7 @@ * @param result `result` from `parse_to_tree`, same sematics, will be updated * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise */ -int simplify_tree(mds_kbdc_parsed_t* restrict result); +int simplify_tree(mds_kbdc_parsed_t *restrict result); #endif - diff --git a/src/mds-kbdc/string.c b/src/mds-kbdc/string.c index a334611..c0e9852 100644 --- a/src/mds-kbdc/string.c +++ b/src/mds-kbdc/string.c @@ -30,12 +30,13 @@ * @param string The string * @return The length of the string */ -size_t string_length(const char32_t* restrict string) +size_t +string_length(const char32_t *restrict string) { - size_t i = 0; - while (string[i] != -1) - i++; - return i; + size_t i = 0; + while (string[i] != -1) + i++; + return i; } @@ -45,43 +46,41 @@ size_t string_length(const char32_t* restrict string) * @param string The UTF-8 string * @return The string in UTF-32, `NULL` on error */ -char32_t* string_decode(const char* restrict string) +char32_t * +string_decode(const char *restrict string) { - size_t i, j, n, length = 0; - char32_t* rc; - - /* Get the length of the UTF-32 string, excluding termination. */ - for (i = 0; string[i]; i++) - if ((string[i] & 0xC0) != 0x80) - length++; - - /* Allocated UTF-32 string. */ - fail_if (xmalloc(rc, length + 1, char32_t)); - - /* Convert to UTF-32. */ - for (i = j = n = 0; string[i]; i++) - { - char c = string[i]; - if (n) - { - rc[j] <<= 6, rc[j] |= c & 0x3F; - if (--n == 0) - j++; - } - else if ((c & 0xC0) == 0xC0) - { - while (c & 0x80) - n++, c = (char)(c << 1); - rc[j] = c >> n--; + size_t i, j, n, length = 0; + char32_t *rc; + char c; + + /* Get the length of the UTF-32 string, excluding termination. */ + for (i = 0; string[i]; i++) + if ((string[i] & 0xC0) != 0x80) + length++; + + /* Allocated UTF-32 string. */ + fail_if (xmalloc(rc, length + 1, char32_t)); + + /* Convert to UTF-32. */ + for (i = j = n = 0; string[i]; i++) { + c = string[i]; + if (n) { + rc[j] <<= 6, rc[j] |= c & 0x3F; + if (!--n) + j++; + } else if ((c & 0xC0) == 0xC0) { + while (c & 0x80) + n++, c = (char)(c << 1); + rc[j] = c >> n--; + } else { + rc[j++] = c & 255; + } } - else - rc[j++] = c & 255; - } - /* -1-terminate and return. */ - return rc[length] = -1, rc; - fail: - return NULL; + /* -1-terminate and return. */ + return rc[length] = -1, rc; +fail: + return NULL; } @@ -93,42 +92,43 @@ char32_t* string_decode(const char* restrict string) * @param string The UTF-32 string * @return The string in UTF-8, `NULL` on error */ -char* string_encode(const char32_t* restrict string) +char * +string_encode(const char32_t *restrict string) { - size_t i, j, n = string_length(string); - char* restrict rc; - - /* Allocated Modified UTF-8 string. */ - fail_if (xmalloc(rc, 7 * n + 1, char)); - - /* Convert to Modified UTF-8. */ - for (i = j = 0; i < n; i++) - { -#define _c(s) rc[j++] = (char)(((c >> (s)) & 0x3F) | 0x80) -#define _t(s) (0 < c) && ((uint32_t)c < (uint32_t)(1ULL << s)) - char32_t c = string[i]; - if (c == 0) rc[j++] = (char)0xC0, rc[j++] = (char)0x80; - else if (_t( 7)) rc[j++] = (char)c; - else if (_t(11)) rc[j++] = (char)((c >> 6) | 0xC0), _c( 0); - else if (_t(16)) rc[j++] = (char)((c >> 12) | 0xE0), _c( 6), _c( 0); - else if (_t(21)) rc[j++] = (char)((c >> 18) | 0xF0), _c(12), _c( 6), _c( 0); - /* UTF-8 actually ends here, fits 32 planes. */ - else if (_t(26)) rc[j++] = (char)((c >> 24) | 0xF8), _c(18), _c(12), _c( 6), _c(0); - else if (_t(31)) rc[j++] = (char)((c >> 30) | 0xFC), _c(24), _c(18), _c(12), _c(6), _c(0); - /* The orginal UTF-8 specification ended here, fits 31 bits. - * However, we added another byte so we can fit 32 bits - * (actually we ca now fit 36 bits.) - * However, we only needed this in `string_decode` which would - * not require any changed, but we added it here for symmetry. */ - else rc[j++] = (char)0xFE, _c(30), _c(24), _c(18), _c(12), _c(6), _c(0); + size_t i, j, n = string_length(string); + char *restrict rc; + char32_t c; + + /* Allocated Modified UTF-8 string. */ + fail_if (xmalloc(rc, 7 * n + 1, char)); + + /* Convert to Modified UTF-8. */ + for (i = j = 0; i < n; i++) { +#define _c(s) rc[j++] = (char)(((c >> (s)) & 0x3F) | 0x80) +#define _t(s) (0 < c) && ((uint32_t)c < (uint32_t)(1ULL << (s))) + c = string[i]; + if (!c) rc[j++] = (char)0xC0, rc[j++] = (char)0x80; + else if (_t( 7)) rc[j++] = (char)c; + else if (_t(11)) rc[j++] = (char)((c >> 6) | 0xC0), _c( 0); + else if (_t(16)) rc[j++] = (char)((c >> 12) | 0xE0), _c( 6), _c( 0); + else if (_t(21)) rc[j++] = (char)((c >> 18) | 0xF0), _c(12), _c( 6), _c( 0); + /* UTF-8 actually ends here, fits 32 planes. */ + else if (_t(26)) rc[j++] = (char)((c >> 24) | 0xF8), _c(18), _c(12), _c( 6), _c(0); + else if (_t(31)) rc[j++] = (char)((c >> 30) | 0xFC), _c(24), _c(18), _c(12), _c(6), _c(0); + /* The orginal UTF-8 specification ended here, fits 31 bits. + * However, we added another byte so we can fit 32 bits + * (actually we ca now fit 36 bits.) + * However, we only needed this in `string_decode` which would + * not require any changed, but we added it here for symmetry. */ + else rc[j++] = (char)0xFE, _c(30), _c(24), _c(18), _c(12), _c(6), _c(0); #undef _t #undef _c - } - - /* NUL-terminate and return. */ - return rc[j] = '\0', rc; - fail: - return NULL; + } + + /* NUL-terminate and return. */ + return rc[j] = '\0', rc; +fail: + return NULL; } @@ -138,16 +138,16 @@ char* string_encode(const char32_t* restrict string) * @param string The string * @return A duplicate of the string, `NULL` on error or if `string` is `NULL` */ -char32_t* string_dup(const char32_t* restrict string) +char32_t * +string_dup(const char32_t *restrict string) { - size_t n; - char32_t* rc; - if (string == NULL) - return NULL; - n = string_length(string) + 1; - fail_if (xmemdup(rc, string, n, char32_t)); - return rc; - fail: - return NULL; + size_t n; + char32_t *rc; + if (!string) + return NULL; + n = string_length(string) + 1; + fail_if (xmemdup(rc, string, n, char32_t)); + return rc; +fail: + return NULL; } - diff --git a/src/mds-kbdc/string.h b/src/mds-kbdc/string.h index a58eb91..81155ed 100644 --- a/src/mds-kbdc/string.h +++ b/src/mds-kbdc/string.h @@ -35,7 +35,8 @@ typedef int32_t char32_t; * @param string The string * @return The length of the string */ -size_t string_length(const char32_t* restrict string) __attribute__((pure, nonnull)); +__attribute__((pure, nonnull)) +size_t string_length(const char32_t *restrict string); /** * Convert a NUL-terminated UTF-8 string to a -1-terminated UTF-32 string @@ -43,7 +44,8 @@ size_t string_length(const char32_t* restrict string) __attribute__((pure, nonnu * @param string The UTF-8 string * @return The string in UTF-32, `NULL` on error */ -char32_t* string_decode(const char* restrict string) __attribute__((nonnull)); +__attribute__((nonnull)) +char32_t *string_decode(const char *restrict string); /** * Convert a -1-terminated UTF-32 string to a NUL-terminated Modified UTF-8 string @@ -51,7 +53,8 @@ char32_t* string_decode(const char* restrict string) __attribute__((nonnull)); * @param string The UTF-32 string * @return The string in UTF-8, `NULL` on error */ -char* string_encode(const char32_t* restrict string) __attribute__((nonnull)); +__attribute__((nonnull)) +char *string_encode(const char32_t *restrict string); /** * Create duplicate of a string @@ -59,9 +62,8 @@ char* string_encode(const char32_t* restrict string) __attribute__((nonnull)); * @param string The string * @return A duplicate of the string, `NULL` on error or if `string` is `NULL` */ -char32_t* string_dup(const char32_t* restrict string); +char32_t *string_dup(const char32_t *restrict string); #endif - diff --git a/src/mds-kbdc/tree.c b/src/mds-kbdc/tree.c index 289ccac..33db89e 100644 --- a/src/mds-kbdc/tree.c +++ b/src/mds-kbdc/tree.c @@ -36,7 +36,7 @@ typedef struct mds_kbdc_tree_information_data mds_kbdc_tree_information_data_t; /** * Tree type constant shortener */ -#define C(t) MDS_KBDC_TREE_TYPE_##t +#define C(t) MDS_KBDC_TREE_TYPE_##t /** @@ -45,10 +45,11 @@ typedef struct mds_kbdc_tree_information_data mds_kbdc_tree_information_data_t; * @param this The memory slot for the tree node * @param type The type of the node */ -void mds_kbdc_tree_initialise(mds_kbdc_tree_t* restrict this, int type) +void +mds_kbdc_tree_initialise(mds_kbdc_tree_t *restrict this, int type) { - memset(this, 0, sizeof(mds_kbdc_tree_t)); - this->type = type; + memset(this, 0, sizeof(mds_kbdc_tree_t)); + this->type = type; } @@ -58,14 +59,15 @@ void mds_kbdc_tree_initialise(mds_kbdc_tree_t* restrict this, int type) * @param type The type of the node * @return The tree node, `NULL` on error */ -mds_kbdc_tree_t* mds_kbdc_tree_create(int type) +mds_kbdc_tree_t * +mds_kbdc_tree_create(int type) { - mds_kbdc_tree_t* this; - fail_if (xmalloc(this, 1, mds_kbdc_tree_t)); - mds_kbdc_tree_initialise(this, type); - return this; - fail: - return NULL; + mds_kbdc_tree_t *this; + fail_if (xmalloc(this, 1, mds_kbdc_tree_t)); + mds_kbdc_tree_initialise(this, type); + return this; +fail: + return NULL; } @@ -75,110 +77,109 @@ mds_kbdc_tree_t* mds_kbdc_tree_create(int type) * @param this The tree node * @param recursive Whether subtree should be destroyed and freed */ -static void mds_kbdc_tree_destroy_(mds_kbdc_tree_t* restrict this, int recursive) +static void mds_kbdc_tree_destroy_(mds_kbdc_tree_t *restrict this, int recursive) { -#define V(type, var) (((type)this)->var) -#define xfree(t, v) (free(V(t, v)), V(t, v) = NULL) -#define xdestroy(t, v) (recursive ? (mds_kbdc_tree_destroy_(V(t, v), 1), xfree(t, v)) : (V(t, v) = NULL)) - - mds_kbdc_tree_t* prev = NULL; - mds_kbdc_tree_t* first = this; - - again: - if (this == NULL) - return; - - switch (this->type) - { - case C(INFORMATION): - case C(ASSUMPTION): - case C(ALTERNATION): - case C(UNORDERED): - case C(ORDERED): - xdestroy(mds_kbdc_tree_nesting_t*, inner); - break; - - case C(INFORMATION_LANGUAGE): - case C(INFORMATION_COUNTRY): - case C(INFORMATION_VARIANT): - xfree(mds_kbdc_tree_information_data_t*, data); - break; - - case C(FUNCTION): - case C(MACRO): - xfree(mds_kbdc_tree_callable_t*, name); - xdestroy(mds_kbdc_tree_callable_t*, inner); - break; - - case C(INCLUDE): - xfree(mds_kbdc_tree_include_t*, filename); - xdestroy(mds_kbdc_tree_include_t*, inner); - mds_kbdc_source_code_free(this->include.source_code); - break; - - case C(ASSUMPTION_HAVE): - xdestroy(mds_kbdc_tree_assumption_have_t*, data); - break; - - case C(ASSUMPTION_HAVE_CHARS): - xfree(mds_kbdc_tree_assumption_have_chars_t*, chars); - break; - - case C(ASSUMPTION_HAVE_RANGE): - xfree(mds_kbdc_tree_assumption_have_range_t*, first); - xfree(mds_kbdc_tree_assumption_have_range_t*, last); - break; - - case C(FOR): - xfree(mds_kbdc_tree_for_t*, first); - xfree(mds_kbdc_tree_for_t*, last); - xfree(mds_kbdc_tree_for_t*, variable); - xdestroy(mds_kbdc_tree_for_t*, inner); - break; - - case C(IF): - xfree(mds_kbdc_tree_if_t*, condition); - xdestroy(mds_kbdc_tree_if_t*, inner); - xdestroy(mds_kbdc_tree_if_t*, otherwise); - break; - - case C(LET): - xfree(mds_kbdc_tree_let_t*, variable); - xdestroy(mds_kbdc_tree_let_t*, value); - break; - - case C(MAP): - xdestroy(mds_kbdc_tree_map_t*, sequence); - xdestroy(mds_kbdc_tree_map_t*, result); - break; - - case C(ARRAY): - xdestroy(mds_kbdc_tree_array_t*, elements); - break; - - case C(KEYS): - case C(STRING): - case C(COMPILED_KEYS): - case C(COMPILED_STRING): - xfree(mds_kbdc_tree_keys_t*, keys); - /* We are abusing the similaries of the structures. */ - break; - - case C(MACRO_CALL): - xfree(mds_kbdc_tree_macro_call_t*, name); - xdestroy(mds_kbdc_tree_macro_call_t*, arguments); - break; - - default: - break; - } - - prev = this; - this = this->next; - if (prev != first) - free(prev); - goto again; - +#define V(type, var) (((type)this)->var) +#define xfree(t, v) (free(V(t, v)), V(t, v) = NULL) +#define xdestroy(t, v) (recursive ? (mds_kbdc_tree_destroy_(V(t, v), 1), xfree(t, v)) : (V(t, v) = NULL)) + + mds_kbdc_tree_t *prev = NULL; + mds_kbdc_tree_t *first = this; + +again: + if (!this) + return; + + switch (this->type) { + case C(INFORMATION): + case C(ASSUMPTION): + case C(ALTERNATION): + case C(UNORDERED): + case C(ORDERED): + xdestroy(mds_kbdc_tree_nesting_t *, inner); + break; + + case C(INFORMATION_LANGUAGE): + case C(INFORMATION_COUNTRY): + case C(INFORMATION_VARIANT): + xfree(mds_kbdc_tree_information_data_t *, data); + break; + + case C(FUNCTION): + case C(MACRO): + xfree(mds_kbdc_tree_callable_t *, name); + xdestroy(mds_kbdc_tree_callable_t *, inner); + break; + + case C(INCLUDE): + xfree(mds_kbdc_tree_include_t *, filename); + xdestroy(mds_kbdc_tree_include_t *, inner); + mds_kbdc_source_code_free(this->include.source_code); + break; + + case C(ASSUMPTION_HAVE): + xdestroy(mds_kbdc_tree_assumption_have_t *, data); + break; + + case C(ASSUMPTION_HAVE_CHARS): + xfree(mds_kbdc_tree_assumption_have_chars_t *, chars); + break; + + case C(ASSUMPTION_HAVE_RANGE): + xfree(mds_kbdc_tree_assumption_have_range_t *, first); + xfree(mds_kbdc_tree_assumption_have_range_t *, last); + break; + + case C(FOR): + xfree(mds_kbdc_tree_for_t *, first); + xfree(mds_kbdc_tree_for_t *, last); + xfree(mds_kbdc_tree_for_t *, variable); + xdestroy(mds_kbdc_tree_for_t *, inner); + break; + + case C(IF): + xfree(mds_kbdc_tree_if_t *, condition); + xdestroy(mds_kbdc_tree_if_t *, inner); + xdestroy(mds_kbdc_tree_if_t *, otherwise); + break; + + case C(LET): + xfree(mds_kbdc_tree_let_t *, variable); + xdestroy(mds_kbdc_tree_let_t *, value); + break; + + case C(MAP): + xdestroy(mds_kbdc_tree_map_t *, sequence); + xdestroy(mds_kbdc_tree_map_t *, result); + break; + + case C(ARRAY): + xdestroy(mds_kbdc_tree_array_t *, elements); + break; + + case C(KEYS): + case C(STRING): + case C(COMPILED_KEYS): + case C(COMPILED_STRING): + xfree(mds_kbdc_tree_keys_t *, keys); + /* We are abusing the similaries of the structures. */ + break; + + case C(MACRO_CALL): + xfree(mds_kbdc_tree_macro_call_t *, name); + xdestroy(mds_kbdc_tree_macro_call_t *, arguments); + break; + + default: + break; + } + + prev = this; + this = this->next; + if (prev != first) + free(prev); + goto again; + #undef xdestroy #undef xfree #undef V @@ -192,9 +193,10 @@ static void mds_kbdc_tree_destroy_(mds_kbdc_tree_t* restrict this, int recursive * * @param this The tree node */ -void mds_kbdc_tree_destroy_nonrecursive(mds_kbdc_tree_t* restrict this) +void +mds_kbdc_tree_destroy_nonrecursive(mds_kbdc_tree_t *restrict this) { - mds_kbdc_tree_destroy_(this, 0); + mds_kbdc_tree_destroy_(this, 0); } @@ -206,10 +208,11 @@ void mds_kbdc_tree_destroy_nonrecursive(mds_kbdc_tree_t* restrict this) * * @param this The tree node */ -void mds_kbdc_tree_free_nonrecursive(mds_kbdc_tree_t* restrict this) +void +mds_kbdc_tree_free_nonrecursive(mds_kbdc_tree_t *restrict this) { - mds_kbdc_tree_destroy_nonrecursive(this); - free(this); + mds_kbdc_tree_destroy_nonrecursive(this); + free(this); } @@ -220,9 +223,10 @@ void mds_kbdc_tree_free_nonrecursive(mds_kbdc_tree_t* restrict this) * * @param this The tree node */ -void mds_kbdc_tree_destroy(mds_kbdc_tree_t* restrict this) +void +mds_kbdc_tree_destroy(mds_kbdc_tree_t *restrict this) { - mds_kbdc_tree_destroy_(this, 1); + mds_kbdc_tree_destroy_(this, 1); } @@ -233,10 +237,11 @@ void mds_kbdc_tree_destroy(mds_kbdc_tree_t* restrict this) * * @param this The tree node */ -void mds_kbdc_tree_free(mds_kbdc_tree_t* restrict this) +void +mds_kbdc_tree_free(mds_kbdc_tree_t *restrict this) { - mds_kbdc_tree_destroy(this); - free(this); + mds_kbdc_tree_destroy(this); + free(this); } @@ -246,7 +251,7 @@ void mds_kbdc_tree_free(mds_kbdc_tree_t* restrict this) * * @param member:identifer The member in the tree to duplicate */ -#define T(member) fail_if (t->member && (n->member = mds_kbdc_tree_dup(t->member), n->member == NULL)) +#define T(member) fail_if (t->member && !(n->member = mds_kbdc_tree_dup(t->member))) /** @@ -254,7 +259,7 @@ void mds_kbdc_tree_free(mds_kbdc_tree_t* restrict this) * * @param member:identifer The member in the tree to duplicate */ -#define S(member) fail_if (t->member && xstrdup(n->member, t->member)) +#define S(member) fail_if (t->member && xstrdup(n->member, t->member)) /** @@ -262,7 +267,7 @@ void mds_kbdc_tree_free(mds_kbdc_tree_t* restrict this) * * @param member:identifer The member in the tree to duplicate */ -#define Z(member) fail_if (t->member && (n->member = string_dup(t->member), n->member == NULL)) +#define Z(member) fail_if (t->member && !(n->member = string_dup(t->member))) /** @@ -270,7 +275,7 @@ void mds_kbdc_tree_free(mds_kbdc_tree_t* restrict this) * * @param member:identifer The member in the tree to copied */ -#define R(member) fail_if (t->member && (n->member = mds_kbdc_source_code_dup(t->member), n->member == NULL)) +#define R(member) fail_if (t->member && !(n->member = mds_kbdc_source_code_dup(t->member))) @@ -280,62 +285,109 @@ void mds_kbdc_tree_free(mds_kbdc_tree_t* restrict this) * @param this The tree node * @return A duplicate of `this`, `NULL` on error */ -mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this) +mds_kbdc_tree_t * +mds_kbdc_tree_dup(const mds_kbdc_tree_t *restrict this) { -#define t this -#define n (*node) - mds_kbdc_tree_t* rc = NULL; - mds_kbdc_tree_t** node = &rc; - int saved_errno; - - again: - if (t == NULL) return rc; - fail_if (xcalloc(n, 1, mds_kbdc_tree_t)); +#define t this +#define n (*node) + mds_kbdc_tree_t *rc = NULL; + mds_kbdc_tree_t **node = &rc; + int saved_errno; + +again: + if (!t) + return rc; + fail_if (xcalloc(n, 1, mds_kbdc_tree_t)); + + n->type = t->type; + n->loc_line = t->loc_line; + n->loc_start = t->loc_start; + n->loc_end = t->loc_end; + n->processed = t->processed; + + switch (this->type) { + case C(INFORMATION): + case C(ASSUMPTION): + case C(ALTERNATION): + case C(UNORDERED): + case C(ORDERED): + T(ordered.inner); + break; + case C(FUNCTION): + case C(MACRO): + S(macro.name); + T(macro.inner); + break; + case C(ASSUMPTION_HAVE): + T(have.data); + break; + case C(ARRAY): + T(array.elements); + break; + case C(LET): + S(let.variable); + T(let.value); + break; + case C(MACRO_CALL): + S(macro_call.name); + T(macro_call.arguments); + break; + case C(INFORMATION_LANGUAGE): + case C(INFORMATION_COUNTRY): + case C(INFORMATION_VARIANT): + S(variant.data); + break; + case C(INCLUDE): + S(include.filename); + T(include.inner); + R(include.source_code); + break; + case C(ASSUMPTION_HAVE_CHARS): + S(have_chars.chars); + break; + case C(KEYS): + S(keys.keys); + break; + case C(STRING): + S(string.string); + break; + case C(COMPILED_KEYS): + Z(compiled_keys.keys); + break; + case C(COMPILED_STRING): + Z(compiled_string.string); + break; + case C(ASSUMPTION_HAVE_RANGE): + S(have_range.first); + S(have_range.last); + break; + case C(FOR): + S(for_.first); + S(for_.last); + S(for_.variable); + T(for_.inner); + break; + case C(IF): + S(if_.condition); + T(if_.inner); + T(if_.otherwise); + break; + case C(MAP): + T(map.sequence); + T(map.result); + break; + default: + break; + } + + t = t->next; + node = &(n->next); + goto again; - n->type = t->type; - n->loc_line = t->loc_line; - n->loc_start = t->loc_start; - n->loc_end = t->loc_end; - n->processed = t->processed; - - switch (this->type) - { - case C(INFORMATION): - case C(ASSUMPTION): - case C(ALTERNATION): - case C(UNORDERED): - case C(ORDERED): T(ordered.inner); break; - case C(FUNCTION): - case C(MACRO): S(macro.name); T(macro.inner); break; - case C(ASSUMPTION_HAVE): T(have.data); break; - case C(ARRAY): T(array.elements); break; - case C(LET): S(let.variable); T(let.value); break; - case C(MACRO_CALL): S(macro_call.name); T(macro_call.arguments); break; - case C(INFORMATION_LANGUAGE): - case C(INFORMATION_COUNTRY): - case C(INFORMATION_VARIANT): S(variant.data); break; - case C(INCLUDE): S(include.filename); T(include.inner); R(include.source_code); break; - case C(ASSUMPTION_HAVE_CHARS): S(have_chars.chars); break; - case C(KEYS): S(keys.keys); break; - case C(STRING): S(string.string); break; - case C(COMPILED_KEYS): Z(compiled_keys.keys); break; - case C(COMPILED_STRING): Z(compiled_string.string); break; - case C(ASSUMPTION_HAVE_RANGE): S(have_range.first); S(have_range.last); break; - case C(FOR): S(for_.first); S(for_.last); S(for_.variable); T(for_.inner); break; - case C(IF): S(if_.condition); T(if_.inner); T(if_.otherwise); break; - case C(MAP): T(map.sequence); T(map.result); break; - default: - break; - } - - t = t->next; - node = &(n->next); - goto again; - - fail: - saved_errno = errno; - mds_kbdc_tree_free(rc); - return errno = saved_errno, NULL; +fail: + saved_errno = errno; + mds_kbdc_tree_free(rc); + return errno = saved_errno, NULL; #undef n #undef t } @@ -355,12 +407,12 @@ mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this) * @param LOWERCASE:identifer The name of subtype * @param NOTATION:const char* The notation for the subtype */ -#define NODE(LOWERCASE, NOTATION) \ - const mds_kbdc_tree_##LOWERCASE##_t* node; \ - node = (const mds_kbdc_tree_##LOWERCASE##_t*)this; \ - fprintf(output, "%*.s(\033[01m%s\033[00m", indent, "", NOTATION); \ - fprintf(output, " \033[36m(@ %zu %zu-%zu)\033[00m", \ - node->loc_line + 1, node->loc_start, node->loc_end) +#define NODE(LOWERCASE, NOTATION)\ + const mds_kbdc_tree_##LOWERCASE##_t *node;\ + node = (const mds_kbdc_tree_##LOWERCASE##_t *)this;\ + fprintf(output, "%*.s(\033[01m%s\033[00m", indent, "", NOTATION);\ + fprintf(output, " \033[36m(@ %zu %zu-%zu)\033[00m",\ + node->loc_line + 1, node->loc_start, node->loc_end) /** @@ -368,22 +420,23 @@ mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this) * * @param MEMBER:identifier The tree structure's member */ -#define BRANCH(MEMBER) \ - if (node->MEMBER) \ - { \ - fprintf(output, "\n%*.s(.%s\n", indent + 2, "", #MEMBER); \ - mds_kbdc_tree_print_indented(node->MEMBER, output, indent + 4); \ - fprintf(output, "%*.s)", indent + 2, ""); \ - } \ - else \ - fprintf(output, "\n%*.s(.%s \033[35mnil\033[00m)", indent + 2, "", #MEMBER) +#define BRANCH(MEMBER)\ + do {\ + if (node->MEMBER) {\ + fprintf(output, "\n%*.s(.%s\n", indent + 2, "", #MEMBER);\ + mds_kbdc_tree_print_indented(node->MEMBER, output, indent + 4);\ + fprintf(output, "%*.s)", indent + 2, "");\ + } else {\ + fprintf(output, "\n%*.s(.%s \033[35mnil\033[00m)", indent + 2, "", #MEMBER);\ + }\ + } while (0) /** * End a tree which has at least one member that is a subtree */ -#define COMPLEX \ - fprintf(output, "\n%*.s)\n", indent, "") +#define COMPLEX\ + fprintf(output, "\n%*.s)\n", indent, "") /** @@ -391,11 +444,13 @@ mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this) * * @param MEMBER:identifier The tree structure's member */ -#define STRING(MEMBER) \ - if (node->MEMBER) \ - fprintf(output, " ‘\033[32m%s\033[00m’", node->MEMBER); \ - else \ - fprintf(output, " \033[35mnil\033[00m") +#define STRING(MEMBER)\ + do {\ + if (node->MEMBER)\ + fprintf(output, " ‘\033[32m%s\033[00m’", node->MEMBER);\ + else\ + fprintf(output, " \033[35mnil\033[00m");\ + } while (0) /** @@ -404,9 +459,11 @@ mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this) * * @param MEMBER:identifier The tree structure's member */ -#define SIMPLE(MEMBER) \ - STRING(MEMBER); \ - fprintf(output, ")\n") +#define SIMPLE(MEMBER)\ + do {\ + STRING(MEMBER);\ + fprintf(output, ")\n");\ + } while (0) /** @@ -417,12 +474,12 @@ mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this) * @param NOTATION:const char* See `NODE` * @param MEMBER:identifier See `STRING` */ -#define SIMPLEX(LOWERCASE, NOTATION, MEMBER) \ - { \ - NODE(LOWERCASE, NOTATION); \ - SIMPLE(MEMBER); \ - } \ - break +#define SIMPLEX(LOWERCASE, NOTATION, MEMBER)\ + {\ + NODE(LOWERCASE, NOTATION);\ + SIMPLE(MEMBER);\ + }\ + break /** @@ -434,13 +491,13 @@ mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this) * @param FIRST:identifier See `STRING`, the first member * @param LAST:identifier See `STRING`, the second member */ -#define DUPLEX(LOWERCASE, NOTATION, FIRST, LAST) \ - { \ - NODE(LOWERCASE, NOTATION); \ - STRING(FIRST); \ - SIMPLE(LAST); \ - } \ - break +#define DUPLEX(LOWERCASE, NOTATION, FIRST, LAST)\ + {\ + NODE(LOWERCASE, NOTATION);\ + STRING(FIRST);\ + SIMPLE(LAST);\ + }\ + break /** @@ -451,13 +508,13 @@ mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this) * @param NOTATION:const char* See `NODE` * @param MEMBER:identifier See `BRANCH` */ -#define NESTING(LOWERCASE, NOTATION, MEMBER) \ - { \ - NODE(LOWERCASE, NOTATION); \ - BRANCH(MEMBER); \ - COMPLEX; \ - } \ - break +#define NESTING(LOWERCASE, NOTATION, MEMBER)\ + {\ + NODE(LOWERCASE, NOTATION);\ + BRANCH(MEMBER);\ + COMPLEX;\ + }\ + break /** @@ -470,14 +527,14 @@ mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this) * @param NAMER:identifier See `STRING` * @param MEMBER:identifier See `BRANCH` */ -#define NAMED_NESTING(LOWERCASE, NOTATION, NAMER, MEMBER) \ - { \ - NODE(LOWERCASE, NOTATION); \ - STRING(NAMER); \ - BRANCH(MEMBER); \ - COMPLEX; \ - } \ - break +#define NAMED_NESTING(LOWERCASE, NOTATION, NAMER, MEMBER)\ + {\ + NODE(LOWERCASE, NOTATION);\ + STRING(NAMER);\ + BRANCH(MEMBER);\ + COMPLEX;\ + }\ + break /** @@ -485,12 +542,12 @@ mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this) * * @param NOTATION:const char* See `NODE` */ -#define NOTHING(NOTATION) \ - fprintf(output, "%*.s(\033[01m%s\033[00m", indent, "", NOTATION); \ - fprintf(output, " \033[36m(@ %zu %zu-%zu)\033[00m", \ - this->loc_line + 1, this->loc_start, this->loc_end); \ - fprintf(output, ")\n"); \ - break +#define NOTHING(NOTATION)\ + fprintf(output, "%*.s(\033[01m%s\033[00m", indent, "", NOTATION);\ + fprintf(output, " \033[36m(@ %zu %zu-%zu)\033[00m",\ + this->loc_line + 1, this->loc_start, this->loc_end);\ + fprintf(output, ")\n");\ + break @@ -501,100 +558,100 @@ mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this) * @param output The output file * @param indent The indent */ -static void mds_kbdc_tree_print_indented(const mds_kbdc_tree_t* restrict this, FILE* output, int indent) +static void +mds_kbdc_tree_print_indented(const mds_kbdc_tree_t *restrict this, FILE *output, int indent) { - again: - if (this == NULL) - return; - - switch (this->type) - { - /* These have their break built into their macro. */ - case C(INFORMATION): NESTING(information, "information", inner); - case C(INFORMATION_LANGUAGE): SIMPLEX(information_language, "language", data); - case C(INFORMATION_COUNTRY): SIMPLEX(information_country, "country", data); - case C(INFORMATION_VARIANT): SIMPLEX(information_variant, "variant", data); - case C(INCLUDE): NAMED_NESTING(include, "include", filename, inner); - case C(FUNCTION): NAMED_NESTING(function, "function", name, inner); - case C(MACRO): NAMED_NESTING(macro, "macro", name, inner); - case C(ASSUMPTION): NESTING(assumption, "assumption", inner); - case C(ASSUMPTION_HAVE): NESTING(assumption_have, "have", data); - case C(ASSUMPTION_HAVE_CHARS): SIMPLEX(assumption_have_chars, "have_chars", chars); - case C(ASSUMPTION_HAVE_RANGE): DUPLEX(assumption_have_range, "have_range", first, last); - case C(LET): NAMED_NESTING(let, "let", variable, value); - case C(ARRAY): NESTING(array, "array", elements); - case C(KEYS): SIMPLEX(keys, "keys", keys); - case C(STRING): SIMPLEX(string, "string", string); - case C(NOTHING): NOTHING("nothing"); - case C(ALTERNATION): NESTING(alternation, "alternation", inner); - case C(UNORDERED): NESTING(unordered, "unordered", inner); - case C(ORDERED): NESTING(ordered, "ordered", inner); - case C(MACRO_CALL): NAMED_NESTING(macro_call, "macro_call", name, arguments); - case C(RETURN): NOTHING("return"); - case C(BREAK): NOTHING("break"); - case C(CONTINUE): NOTHING("continue"); - - case C(COMPILED_KEYS): - { - NODE(compiled_keys, "compiled_keys"); - if (node->keys) - fprintf(output, " ‘\033[32m%s\033[00m’", string_encode(node->keys)); - else - fprintf(output, " \033[35mnil\033[00m"); - fprintf(output, ")\n"); - } - break; - - case C(COMPILED_STRING): - { - NODE(compiled_string, "compiled_string"); - if (node->string) - fprintf(output, " ‘\033[32m%s\033[00m’", string_encode(node->string)); - else - fprintf(output, " \033[35mnil\033[00m"); - fprintf(output, ")\n"); - } - break; - - case C(FOR): - { - NODE(for, "for"); - STRING(first); - STRING(last); - fprintf(output, " (.variable"); - STRING(variable); - fprintf(output, ")"); - BRANCH(inner); - COMPLEX; - } - break; - - case C(IF): - { - NODE(if, "if"); - STRING(condition); - BRANCH(inner); - BRANCH(otherwise); - COMPLEX; - } - break; - - case C(MAP): - { - NODE(map, "map"); - BRANCH(sequence); - BRANCH(result); - COMPLEX; - } - break; - - default: - abort(); - break; - } - - this = this->next; - goto again; +again: + if (!this) + return; + + switch (this->type) { + /* These have their break built into their macro. */ + case C(INFORMATION): NESTING(information, "information", inner); + case C(INFORMATION_LANGUAGE): SIMPLEX(information_language, "language", data); + case C(INFORMATION_COUNTRY): SIMPLEX(information_country, "country", data); + case C(INFORMATION_VARIANT): SIMPLEX(information_variant, "variant", data); + case C(INCLUDE): NAMED_NESTING(include, "include", filename, inner); + case C(FUNCTION): NAMED_NESTING(function, "function", name, inner); + case C(MACRO): NAMED_NESTING(macro, "macro", name, inner); + case C(ASSUMPTION): NESTING(assumption, "assumption", inner); + case C(ASSUMPTION_HAVE): NESTING(assumption_have, "have", data); + case C(ASSUMPTION_HAVE_CHARS): SIMPLEX(assumption_have_chars, "have_chars", chars); + case C(ASSUMPTION_HAVE_RANGE): DUPLEX(assumption_have_range, "have_range", first, last); + case C(LET): NAMED_NESTING(let, "let", variable, value); + case C(ARRAY): NESTING(array, "array", elements); + case C(KEYS): SIMPLEX(keys, "keys", keys); + case C(STRING): SIMPLEX(string, "string", string); + case C(NOTHING): NOTHING("nothing"); + case C(ALTERNATION): NESTING(alternation, "alternation", inner); + case C(UNORDERED): NESTING(unordered, "unordered", inner); + case C(ORDERED): NESTING(ordered, "ordered", inner); + case C(MACRO_CALL): NAMED_NESTING(macro_call, "macro_call", name, arguments); + case C(RETURN): NOTHING("return"); + case C(BREAK): NOTHING("break"); + case C(CONTINUE): NOTHING("continue"); + + case C(COMPILED_KEYS): + { + NODE(compiled_keys, "compiled_keys"); + if (node->keys) + fprintf(output, " ‘\033[32m%s\033[00m’", string_encode(node->keys)); + else + fprintf(output, " \033[35mnil\033[00m"); + fprintf(output, ")\n"); + } + break; + + case C(COMPILED_STRING): + { + NODE(compiled_string, "compiled_string"); + if (node->string) + fprintf(output, " ‘\033[32m%s\033[00m’", string_encode(node->string)); + else + fprintf(output, " \033[35mnil\033[00m"); + fprintf(output, ")\n"); + } + break; + + case C(FOR): + { + NODE(for, "for"); + STRING(first); + STRING(last); + fprintf(output, " (.variable"); + STRING(variable); + fprintf(output, ")"); + BRANCH(inner); + COMPLEX; + } + break; + + case C(IF): + { + NODE(if, "if"); + STRING(condition); + BRANCH(inner); + BRANCH(otherwise); + COMPLEX; + } + break; + + case C(MAP): + { + NODE(map, "map"); + BRANCH(sequence); + BRANCH(result); + COMPLEX; + } + break; + + default: + abort(); + break; + } + + this = this->next; + goto again; } @@ -604,9 +661,10 @@ static void mds_kbdc_tree_print_indented(const mds_kbdc_tree_t* restrict this, F * @param this The tree node * @param output The output file */ -void mds_kbdc_tree_print(const mds_kbdc_tree_t* restrict this, FILE* output) +void +mds_kbdc_tree_print(const mds_kbdc_tree_t *restrict this, FILE *output) { - mds_kbdc_tree_print_indented(this, output, 0); + mds_kbdc_tree_print_indented(this, output, 0); } @@ -622,4 +680,3 @@ void mds_kbdc_tree_print(const mds_kbdc_tree_t* restrict this, FILE* output) #undef NODE #undef C - diff --git a/src/mds-kbdc/tree.h b/src/mds-kbdc/tree.h index e9d28f4..392c85b 100644 --- a/src/mds-kbdc/tree.h +++ b/src/mds-kbdc/tree.h @@ -32,142 +32,142 @@ /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_information_t` */ -#define MDS_KBDC_TREE_TYPE_INFORMATION 0 +#define MDS_KBDC_TREE_TYPE_INFORMATION 0 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_information_language_t` */ -#define MDS_KBDC_TREE_TYPE_INFORMATION_LANGUAGE 1 +#define MDS_KBDC_TREE_TYPE_INFORMATION_LANGUAGE 1 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_information_country_t` */ -#define MDS_KBDC_TREE_TYPE_INFORMATION_COUNTRY 2 +#define MDS_KBDC_TREE_TYPE_INFORMATION_COUNTRY 2 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_information_variant_t` */ -#define MDS_KBDC_TREE_TYPE_INFORMATION_VARIANT 3 +#define MDS_KBDC_TREE_TYPE_INFORMATION_VARIANT 3 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_include_t` */ -#define MDS_KBDC_TREE_TYPE_INCLUDE 4 +#define MDS_KBDC_TREE_TYPE_INCLUDE 4 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_function_t` */ -#define MDS_KBDC_TREE_TYPE_FUNCTION 5 +#define MDS_KBDC_TREE_TYPE_FUNCTION 5 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_macro_t` */ -#define MDS_KBDC_TREE_TYPE_MACRO 6 +#define MDS_KBDC_TREE_TYPE_MACRO 6 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_assumption` */ -#define MDS_KBDC_TREE_TYPE_ASSUMPTION 7 +#define MDS_KBDC_TREE_TYPE_ASSUMPTION 7 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_assumption_have_t` */ -#define MDS_KBDC_TREE_TYPE_ASSUMPTION_HAVE 8 +#define MDS_KBDC_TREE_TYPE_ASSUMPTION_HAVE 8 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_assumption_have_chars_t` */ -#define MDS_KBDC_TREE_TYPE_ASSUMPTION_HAVE_CHARS 9 +#define MDS_KBDC_TREE_TYPE_ASSUMPTION_HAVE_CHARS 9 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_assumption_have_range_t` */ -#define MDS_KBDC_TREE_TYPE_ASSUMPTION_HAVE_RANGE 10 +#define MDS_KBDC_TREE_TYPE_ASSUMPTION_HAVE_RANGE 10 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_for_t` */ -#define MDS_KBDC_TREE_TYPE_FOR 11 +#define MDS_KBDC_TREE_TYPE_FOR 11 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_if_t` */ -#define MDS_KBDC_TREE_TYPE_IF 12 +#define MDS_KBDC_TREE_TYPE_IF 12 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_let_t` */ -#define MDS_KBDC_TREE_TYPE_LET 13 +#define MDS_KBDC_TREE_TYPE_LET 13 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_map_t` */ -#define MDS_KBDC_TREE_TYPE_MAP 14 +#define MDS_KBDC_TREE_TYPE_MAP 14 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_array_t` */ -#define MDS_KBDC_TREE_TYPE_ARRAY 15 +#define MDS_KBDC_TREE_TYPE_ARRAY 15 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_keys_t` */ -#define MDS_KBDC_TREE_TYPE_KEYS 16 +#define MDS_KBDC_TREE_TYPE_KEYS 16 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_string_t` */ -#define MDS_KBDC_TREE_TYPE_STRING 17 +#define MDS_KBDC_TREE_TYPE_STRING 17 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_compiled_keys_t` */ -#define MDS_KBDC_TREE_TYPE_COMPILED_KEYS 18 +#define MDS_KBDC_TREE_TYPE_COMPILED_KEYS 18 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_compiled_string_t` */ -#define MDS_KBDC_TREE_TYPE_COMPILED_STRING 19 +#define MDS_KBDC_TREE_TYPE_COMPILED_STRING 19 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_nothing_t` */ -#define MDS_KBDC_TREE_TYPE_NOTHING 20 +#define MDS_KBDC_TREE_TYPE_NOTHING 20 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_alternation_t` */ -#define MDS_KBDC_TREE_TYPE_ALTERNATION 21 +#define MDS_KBDC_TREE_TYPE_ALTERNATION 21 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_unordered_t` */ -#define MDS_KBDC_TREE_TYPE_UNORDERED 22 +#define MDS_KBDC_TREE_TYPE_UNORDERED 22 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_ordered_t` */ -#define MDS_KBDC_TREE_TYPE_ORDERED 23 +#define MDS_KBDC_TREE_TYPE_ORDERED 23 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_macro_call_t` */ -#define MDS_KBDC_TREE_TYPE_MACRO_CALL 24 +#define MDS_KBDC_TREE_TYPE_MACRO_CALL 24 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_return_t` */ -#define MDS_KBDC_TREE_TYPE_RETURN 25 +#define MDS_KBDC_TREE_TYPE_RETURN 25 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_break_t` */ -#define MDS_KBDC_TREE_TYPE_BREAK 26 +#define MDS_KBDC_TREE_TYPE_BREAK 26 /** * Value of `mds_kbdc_tree_t.type` for `mds_kbdc_tree_continue_t` */ -#define MDS_KBDC_TREE_TYPE_CONTINUE 27 +#define MDS_KBDC_TREE_TYPE_CONTINUE 27 @@ -196,13 +196,13 @@ typedef union mds_kbdc_tree mds_kbdc_tree_t; * - size_t loc_end; -- The last byte in the source code where this is found, exclusive * - long processed; -- The lasted step where the statement has already been processed once */ -#define MDS_KBDC_TREE_COMMON \ - int type; \ - mds_kbdc_tree_t* next; \ - size_t loc_line; \ - size_t loc_start; \ - size_t loc_end; \ - long processed +#define MDS_KBDC_TREE_COMMON\ + int type;\ + mds_kbdc_tree_t *next;\ + size_t loc_line;\ + size_t loc_start;\ + size_t loc_end;\ + long processed /** * This macro is used in this header file, and is then @@ -211,7 +211,7 @@ typedef union mds_kbdc_tree mds_kbdc_tree_t; * @param S:size_t The size of the data structure excluding this padding and * the members defined by the macro `MDS_KBDC_TREE_COMMON` */ -#define MDS_KBDC_TREE_PADDING_(S) char _padding[(5 * sizeof(void*) - (S)) / sizeof(char)] +#define MDS_KBDC_TREE_PADDING_(S) char _padding[(5 * sizeof(void*) - (S)) / sizeof(char)] /** * This macro is used in this header file, and is then @@ -221,7 +221,7 @@ typedef union mds_kbdc_tree mds_kbdc_tree_t; * structure excluding this padding and the members defined * by the macro `MDS_KBDC_TREE_COMMON` */ -#define MDS_KBDC_TREE_PADDING(N) MDS_KBDC_TREE_PADDING_((N) * sizeof(void*)) +#define MDS_KBDC_TREE_PADDING(N) MDS_KBDC_TREE_PADDING_((N) * sizeof(void*)) @@ -232,17 +232,16 @@ typedef union mds_kbdc_tree mds_kbdc_tree_t; * the common members, a pointer to the first * node on next level in the tree */ -struct mds_kbdc_tree_nesting -{ - MDS_KBDC_TREE_COMMON; - - /** - * The first child node, `.inner.next` - * is used to access the second child node. - */ - mds_kbdc_tree_t* inner; - - MDS_KBDC_TREE_PADDING(1); +struct mds_kbdc_tree_nesting { + MDS_KBDC_TREE_COMMON; + + /** + * The first child node, `.inner.next` + * is used to access the second child node. + */ + mds_kbdc_tree_t *inner; + + MDS_KBDC_TREE_PADDING(1); }; @@ -258,16 +257,15 @@ typedef struct mds_kbdc_tree_nesting mds_kbdc_tree_information_t; * for the tree structurs for the information * entries: the children of `mds_kbdc_tree_information_t` */ -struct mds_kbdc_tree_information_data -{ - MDS_KBDC_TREE_COMMON; - - /** - * The value of the information entry - */ - char* data; - - MDS_KBDC_TREE_PADDING(1); +struct mds_kbdc_tree_information_data { + MDS_KBDC_TREE_COMMON; + + /** + * The value of the information entry + */ + char *data; + + MDS_KBDC_TREE_PADDING(1); }; @@ -290,27 +288,25 @@ typedef struct mds_kbdc_tree_information_data mds_kbdc_tree_information_variant_ /** * Leaf structure for inclusion of a file */ -typedef struct mds_kbdc_tree_include -{ - MDS_KBDC_TREE_COMMON; - - /** - * The included layout code tree - */ - mds_kbdc_tree_t* inner; - - /** - * The filename of the file to include - */ - char* filename; - - /** - * The source code of the file included by this statement - */ - mds_kbdc_source_code_t* source_code; - - MDS_KBDC_TREE_PADDING(3); - +typedef struct mds_kbdc_tree_include { + MDS_KBDC_TREE_COMMON; + + /** + * The included layout code tree + */ + mds_kbdc_tree_t *inner; + + /** + * The filename of the file to include + */ + char *filename; + + /** + * The source code of the file included by this statement + */ + mds_kbdc_source_code_t* source_code; + + MDS_KBDC_TREE_PADDING(3); } mds_kbdc_tree_include_t; @@ -320,28 +316,27 @@ typedef struct mds_kbdc_tree_include * for tree structurs that define a callable * element */ -struct mds_kbdc_tree_callable -{ - MDS_KBDC_TREE_COMMON; - - /** - * The first child node, `.inner.next` - * is used to access the second child node - */ - mds_kbdc_tree_t* inner; - - /* It is important that `.inner` is first because - * it is first in `struct mds_kbdc_tree_nesting` - * too which means that `.inner` has to same - * offset everyever (except in `mds_kbdc_tree_if_t`). - */ - - /** - * The name of the callable - */ - char* name; - - MDS_KBDC_TREE_PADDING(2); +struct mds_kbdc_tree_callable { + MDS_KBDC_TREE_COMMON; + + /** + * The first child node, `.inner.next` + * is used to access the second child node + */ + mds_kbdc_tree_t *inner; + + /* It is important that `.inner` is first because + * it is first in `struct mds_kbdc_tree_nesting` + * too which means that `.inner` has to same + * offset everyever (except in `mds_kbdc_tree_if_t`). + */ + + /** + * The name of the callable + */ + char *name; + + MDS_KBDC_TREE_PADDING(2); }; @@ -366,17 +361,15 @@ typedef struct mds_kbdc_tree_nesting mds_kbdc_tree_assumption_t; * Tree structure for making the assumption * that there is a mapping to a key or string */ -typedef struct mds_kbdc_tree_assumption_have -{ - MDS_KBDC_TREE_COMMON; - - /** - * The key or string - */ - mds_kbdc_tree_t* data; - - MDS_KBDC_TREE_PADDING(1); - +typedef struct mds_kbdc_tree_assumption_have { + MDS_KBDC_TREE_COMMON; + + /** + * The key or string + */ + mds_kbdc_tree_t *data; + + MDS_KBDC_TREE_PADDING(1); } mds_kbdc_tree_assumption_have_t; @@ -384,17 +377,15 @@ typedef struct mds_kbdc_tree_assumption_have * Leaf structure for making the assumption * that there are mappings to a set of characters */ -typedef struct mds_kbdc_tree_assumption_have_chars -{ - MDS_KBDC_TREE_COMMON; - - /** - * The characters - */ - char* chars; - - MDS_KBDC_TREE_PADDING(1); - +typedef struct mds_kbdc_tree_assumption_have_chars { + MDS_KBDC_TREE_COMMON; + + /** + * The characters + */ + char *chars; + + MDS_KBDC_TREE_PADDING(1); } mds_kbdc_tree_assumption_have_chars_t; @@ -402,91 +393,85 @@ typedef struct mds_kbdc_tree_assumption_have_chars * Leaf structure for making the assumption * that there are mappings to a range of characters */ -typedef struct mds_kbdc_tree_assumption_have_range -{ - MDS_KBDC_TREE_COMMON; - - /** - * The first character, inclusive - */ - char* first; - - /** - * The last character, inclusive - */ - char* last; - - MDS_KBDC_TREE_PADDING(2); - +typedef struct mds_kbdc_tree_assumption_have_range { + MDS_KBDC_TREE_COMMON; + + /** + * The first character, inclusive + */ + char *first; + + /** + * The last character, inclusive + */ + char *last; + + MDS_KBDC_TREE_PADDING(2); } mds_kbdc_tree_assumption_have_range_t; /** * Tree structure for a "for"-loop */ -typedef struct mds_kbdc_tree_for -{ - MDS_KBDC_TREE_COMMON; - - /** - * The first child node, `.inner.next` is - * used to access the second child node. - * This is what should be done inside the loop. - */ - mds_kbdc_tree_t* inner; - - /* It is important that `.inner` is first because - * it is first in `struct mds_kbdc_tree_nesting` - * too which means that `.inner` has to same - * offset everyever (except in `mds_kbdc_tree_if_t`). - */ - - /** - * The first value to variable should take, inclusive - */ - char* first; - - /** - * The last value the variable should take, inclusive - */ - char* last; - - /** - * The variable - */ - char* variable; - - MDS_KBDC_TREE_PADDING(4); - +typedef struct mds_kbdc_tree_for { + MDS_KBDC_TREE_COMMON; + + /** + * The first child node, `.inner.next` is + * used to access the second child node. + * This is what should be done inside the loop. + */ + mds_kbdc_tree_t *inner; + + /* It is important that `.inner` is first because + * it is first in `struct mds_kbdc_tree_nesting` + * too which means that `.inner` has to same + * offset everyever (except in `mds_kbdc_tree_if_t`). + */ + + /** + * The first value to variable should take, inclusive + */ + char *first; + + /** + * The last value the variable should take, inclusive + */ + char *last; + + /** + * The variable + */ + char *variable; + + MDS_KBDC_TREE_PADDING(4); } mds_kbdc_tree_for_t; /** * Tree structure for a "if"-statement */ -typedef struct mds_kbdc_tree_if -{ - MDS_KBDC_TREE_COMMON; - - /** - * The condition - */ - char* condition; - - /** - * This is what should be done inside - * if the condition is satisfied - */ - mds_kbdc_tree_t* inner; - - /** - * This is what should be done inside - * if the condition is not satisfied - */ - mds_kbdc_tree_t* otherwise; - - MDS_KBDC_TREE_PADDING(3); - +typedef struct mds_kbdc_tree_if { + MDS_KBDC_TREE_COMMON; + + /** + * The condition + */ + char *condition; + + /** + * This is what should be done inside + * if the condition is satisfied + */ + mds_kbdc_tree_t *inner; + + /** + * This is what should be done inside + * if the condition is not satisfied + */ + mds_kbdc_tree_t *otherwise; + + MDS_KBDC_TREE_PADDING(3); } mds_kbdc_tree_if_t; @@ -494,22 +479,20 @@ typedef struct mds_kbdc_tree_if * Tree structure for assigning a value to a variable, * possibly declaring the variable in the process */ -typedef struct mds_kbdc_tree_let -{ - MDS_KBDC_TREE_COMMON; - - /** - * The variable - */ - char* variable; - - /** - * The value to assign to the variable - */ - mds_kbdc_tree_t* value; - - MDS_KBDC_TREE_PADDING(2); - +typedef struct mds_kbdc_tree_let { + MDS_KBDC_TREE_COMMON; + + /** + * The variable + */ + char *variable; + + /** + * The value to assign to the variable + */ + mds_kbdc_tree_t *value; + + MDS_KBDC_TREE_PADDING(2); } mds_kbdc_tree_let_t; @@ -522,127 +505,115 @@ typedef struct mds_kbdc_tree_let * in such case `sequence` should not be `NULL` but * `sequence.next` and `result` should be `NULL` */ -typedef struct mds_kbdc_tree_map -{ - MDS_KBDC_TREE_COMMON; - - /** - * The input sequence - */ - mds_kbdc_tree_t* sequence; - - /** - * The output sequence - */ - mds_kbdc_tree_t* result; - - /* - * These are ordered so that `mds_kbdc_tree_t.macro_call.arguments` - * and `mds_kbdc_tree_t.map.sequence` have the same address. - */ - - MDS_KBDC_TREE_PADDING(2); - +typedef struct mds_kbdc_tree_map { + MDS_KBDC_TREE_COMMON; + + /** + * The input sequence + */ + mds_kbdc_tree_t *sequence; + + /** + * The output sequence + */ + mds_kbdc_tree_t *result; + + /* + * These are ordered so that `mds_kbdc_tree_t.macro_call.arguments` + * and `mds_kbdc_tree_t.map.sequence` have the same address. + */ + + MDS_KBDC_TREE_PADDING(2); } mds_kbdc_tree_map_t; /** * Tree structure for an array of values */ -typedef struct mds_kbdc_tree_array -{ - MDS_KBDC_TREE_COMMON; - - /** - * The first value, `.elements.next` - * is used to access the second value. - */ - mds_kbdc_tree_t* elements; - - MDS_KBDC_TREE_PADDING(1); - +typedef struct mds_kbdc_tree_array { + MDS_KBDC_TREE_COMMON; + + /** + * The first value, `.elements.next` + * is used to access the second value. + */ + mds_kbdc_tree_t *elements; + + MDS_KBDC_TREE_PADDING(1); } mds_kbdc_tree_array_t; /** * Leaf structure for a key-combination */ -typedef struct mds_kbdc_tree_keys -{ - MDS_KBDC_TREE_COMMON; - - /** - * The key-combination - */ - char* keys; - - MDS_KBDC_TREE_PADDING(1); - +typedef struct mds_kbdc_tree_keys { + MDS_KBDC_TREE_COMMON; + + /** + * The key-combination + */ + char *keys; + + MDS_KBDC_TREE_PADDING(1); } mds_kbdc_tree_keys_t; /** * Leaf structure for a string */ -typedef struct mds_kbdc_tree_string -{ - MDS_KBDC_TREE_COMMON; - - /** - * The string - */ - char* string; - - /* - * `evaluate_element` in "compile-layout.c" utilises - * that `mds_kbdc_tree_string.string` has the same - * offset as `mds_kbdc_tree_keys.keys`. - */ - - MDS_KBDC_TREE_PADDING(1); - +typedef struct mds_kbdc_tree_string { + MDS_KBDC_TREE_COMMON; + + /** + * The string + */ + char *string; + + /* + * `evaluate_element` in "compile-layout.c" utilises + * that `mds_kbdc_tree_string.string` has the same + * offset as `mds_kbdc_tree_keys.keys`. + */ + + MDS_KBDC_TREE_PADDING(1); } mds_kbdc_tree_string_t; /** * Leaf structure for a compiled key-combination */ -typedef struct mds_kbdc_tree_compiled_keys -{ - MDS_KBDC_TREE_COMMON; - - /** - * The key-combination - * - * Strictly terminated by -1 - */ - char32_t* keys; - - MDS_KBDC_TREE_PADDING(1); - +typedef struct mds_kbdc_tree_compiled_keys { + MDS_KBDC_TREE_COMMON; + + /** + * The key-combination + * + * Strictly terminated by -1 + */ + char32_t *keys; + + MDS_KBDC_TREE_PADDING(1); } mds_kbdc_tree_compiled_keys_t; /** * Leaf structure for a compiled string */ -typedef struct mds_kbdc_tree_compiled_string -{ - MDS_KBDC_TREE_COMMON; - - /** - * The string - */ - char32_t* string; - - /* - * `evaluate_element` in "compile-layout.c" utilises - * that `mds_kbdc_tree_string.compiled_string` has the - * same offset as `mds_kbdc_tree_keys.compiled_keys`. - */ - - MDS_KBDC_TREE_PADDING(1); - +typedef struct mds_kbdc_tree_compiled_string { + MDS_KBDC_TREE_COMMON; + + /** + * The string + */ + char32_t *string; + + /* + * `evaluate_element` in "compile-layout.c" utilises + * that `mds_kbdc_tree_string.compiled_string` has the + * same offset as `mds_kbdc_tree_keys.compiled_keys`. + */ + + MDS_KBDC_TREE_PADDING(1); } mds_kbdc_tree_compiled_string_t; @@ -652,11 +623,9 @@ typedef struct mds_kbdc_tree_compiled_string * Other leaf structures without any content may `typedef` * this structure */ -typedef struct mds_kbdc_tree_nothing -{ - MDS_KBDC_TREE_COMMON; - MDS_KBDC_TREE_PADDING(0); - +typedef struct mds_kbdc_tree_nothing { + MDS_KBDC_TREE_COMMON; + MDS_KBDC_TREE_PADDING(0); } mds_kbdc_tree_nothing_t; @@ -682,29 +651,27 @@ typedef struct mds_kbdc_tree_nesting mds_kbdc_tree_ordered_t; /** * Tree structure for a macro call */ -typedef struct mds_kbdc_tree_macro_call -{ - MDS_KBDC_TREE_COMMON; - - /** - * The first input argument for the - * macro call, the second is accessed - * using `.arguments.next` - */ - mds_kbdc_tree_t* arguments; - - /** - * The name of the macro - */ - char* name; - - /* - * These are ordered so that `mds_kbdc_tree_t.macro_call.arguments` - * and `mds_kbdc_tree_t.map.sequence` have the same address. - */ - - MDS_KBDC_TREE_PADDING(2); - +typedef struct mds_kbdc_tree_macro_call { + MDS_KBDC_TREE_COMMON; + + /** + * The first input argument for the + * macro call, the second is accessed + * using `.arguments.next` + */ + mds_kbdc_tree_t *arguments; + + /** + * The name of the macro + */ + char *name; + + /* + * These are ordered so that `mds_kbdc_tree_t.macro_call.arguments` + * and `mds_kbdc_tree_t.map.sequence` have the same address. + */ + + MDS_KBDC_TREE_PADDING(2); } mds_kbdc_tree_macro_call_t; @@ -728,45 +695,47 @@ typedef struct mds_kbdc_tree_nothing mds_kbdc_tree_continue_t; /** * Keyboard layout syntax tree */ -union mds_kbdc_tree -{ +union mds_kbdc_tree { +#if defined(__GNUC__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wpedantic" /* unnamed struct */ - struct - { - MDS_KBDC_TREE_COMMON; - MDS_KBDC_TREE_PADDING(0); - }; +#endif + struct { + MDS_KBDC_TREE_COMMON; + MDS_KBDC_TREE_PADDING(0); + }; +#if defined(__GNUC__) # pragma GCC diagnostic pop - - mds_kbdc_tree_information_t information; - mds_kbdc_tree_information_language_t language; - mds_kbdc_tree_information_country_t country; - mds_kbdc_tree_information_variant_t variant; - mds_kbdc_tree_include_t include; - mds_kbdc_tree_function_t function; - mds_kbdc_tree_macro_t macro; - mds_kbdc_tree_assumption_t assumption; - mds_kbdc_tree_assumption_have_t have; - mds_kbdc_tree_assumption_have_chars_t have_chars; - mds_kbdc_tree_assumption_have_range_t have_range; - mds_kbdc_tree_for_t for_; - mds_kbdc_tree_if_t if_; - mds_kbdc_tree_let_t let; - mds_kbdc_tree_map_t map; - mds_kbdc_tree_array_t array; - mds_kbdc_tree_keys_t keys; - mds_kbdc_tree_string_t string; - mds_kbdc_tree_compiled_keys_t compiled_keys; - mds_kbdc_tree_compiled_string_t compiled_string; - mds_kbdc_tree_nothing_t nothing; - mds_kbdc_tree_alternation_t alternation; - mds_kbdc_tree_unordered_t unordered; - mds_kbdc_tree_ordered_t ordered; - mds_kbdc_tree_macro_call_t macro_call; - mds_kbdc_tree_return_t return_; - mds_kbdc_tree_break_t break_; - mds_kbdc_tree_continue_t continue_; +#endif + + mds_kbdc_tree_information_t information; + mds_kbdc_tree_information_language_t language; + mds_kbdc_tree_information_country_t country; + mds_kbdc_tree_information_variant_t variant; + mds_kbdc_tree_include_t include; + mds_kbdc_tree_function_t function; + mds_kbdc_tree_macro_t macro; + mds_kbdc_tree_assumption_t assumption; + mds_kbdc_tree_assumption_have_t have; + mds_kbdc_tree_assumption_have_chars_t have_chars; + mds_kbdc_tree_assumption_have_range_t have_range; + mds_kbdc_tree_for_t for_; + mds_kbdc_tree_if_t if_; + mds_kbdc_tree_let_t let; + mds_kbdc_tree_map_t map; + mds_kbdc_tree_array_t array; + mds_kbdc_tree_keys_t keys; + mds_kbdc_tree_string_t string; + mds_kbdc_tree_compiled_keys_t compiled_keys; + mds_kbdc_tree_compiled_string_t compiled_string; + mds_kbdc_tree_nothing_t nothing; + mds_kbdc_tree_alternation_t alternation; + mds_kbdc_tree_unordered_t unordered; + mds_kbdc_tree_ordered_t ordered; + mds_kbdc_tree_macro_call_t macro_call; + mds_kbdc_tree_return_t return_; + mds_kbdc_tree_break_t break_; + mds_kbdc_tree_continue_t continue_; }; @@ -777,7 +746,7 @@ union mds_kbdc_tree * @param this The memory slot for the tree node * @param type The type of the node */ -void mds_kbdc_tree_initialise(mds_kbdc_tree_t* restrict this, int type); +void mds_kbdc_tree_initialise(mds_kbdc_tree_t *restrict this, int type); /** * Create a tree node @@ -785,7 +754,7 @@ void mds_kbdc_tree_initialise(mds_kbdc_tree_t* restrict this, int type); * @param type The type of the node * @return The tree node, `NULL` on error */ -mds_kbdc_tree_t* mds_kbdc_tree_create(int type); +mds_kbdc_tree_t *mds_kbdc_tree_create(int type); /** * Release all resources stored in a tree node, @@ -794,7 +763,7 @@ mds_kbdc_tree_t* mds_kbdc_tree_create(int type); * * @param this The tree node */ -void mds_kbdc_tree_destroy_nonrecursive(mds_kbdc_tree_t* restrict this); +void mds_kbdc_tree_destroy_nonrecursive(mds_kbdc_tree_t *restrict this); /** * Release all resources stored in a tree node, @@ -804,7 +773,7 @@ void mds_kbdc_tree_destroy_nonrecursive(mds_kbdc_tree_t* restrict this); * * @param this The tree node */ -void mds_kbdc_tree_free_nonrecursive(mds_kbdc_tree_t* restrict this); +void mds_kbdc_tree_free_nonrecursive(mds_kbdc_tree_t *restrict this); /** * Release all resources stored in a tree node @@ -813,7 +782,7 @@ void mds_kbdc_tree_free_nonrecursive(mds_kbdc_tree_t* restrict this); * * @param this The tree node */ -void mds_kbdc_tree_destroy(mds_kbdc_tree_t* restrict this); +void mds_kbdc_tree_destroy(mds_kbdc_tree_t *restrict this); /** * Release all resources stored in a tree node @@ -822,7 +791,7 @@ void mds_kbdc_tree_destroy(mds_kbdc_tree_t* restrict this); * * @param this The tree node */ -void mds_kbdc_tree_free(mds_kbdc_tree_t* restrict this); +void mds_kbdc_tree_free(mds_kbdc_tree_t *restrict this); /** @@ -832,7 +801,7 @@ void mds_kbdc_tree_free(mds_kbdc_tree_t* restrict this); * @param this The tree node * @return A duplicate of `this`, `NULL` on error */ -mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this); +mds_kbdc_tree_t *mds_kbdc_tree_dup(const mds_kbdc_tree_t *restrict this); /** @@ -841,7 +810,7 @@ mds_kbdc_tree_t* mds_kbdc_tree_dup(const mds_kbdc_tree_t* restrict this); * @param this The tree node * @param output The output file */ -void mds_kbdc_tree_print(const mds_kbdc_tree_t* restrict this, FILE* output); +void mds_kbdc_tree_print(const mds_kbdc_tree_t *restrict this, FILE *output); @@ -850,4 +819,3 @@ void mds_kbdc_tree_print(const mds_kbdc_tree_t* restrict this, FILE* output); #undef MDS_KBDC_TREE_COMMON #endif - diff --git a/src/mds-kbdc/validate-tree.c b/src/mds-kbdc/validate-tree.c index 632b9a8..80ef7d5 100644 --- a/src/mds-kbdc/validate-tree.c +++ b/src/mds-kbdc/validate-tree.c @@ -28,12 +28,12 @@ /** * Tree type constant shortener */ -#define C(TYPE) MDS_KBDC_TREE_TYPE_##TYPE +#define C(TYPE) MDS_KBDC_TREE_TYPE_##TYPE /** * Check the value of `innermost_visit` */ -#define VISITING(TYPE) (innermost_visit == MDS_KBDC_TREE_TYPE_##TYPE) +#define VISITING(TYPE) (innermost_visit == MDS_KBDC_TREE_TYPE_##TYPE) /** * Add an error with “included from here”-notes to the error list @@ -44,20 +44,20 @@ * @param ...:const char*, ... Error description format string and arguments * @scope error:mds_kbdc_parse_error_t* Variable where the new error will be stored */ -#define NEW_ERROR(NODE, PTR, SEVERITY, ...) \ - NEW_ERROR_WITH_INCLUDES(NODE, PTR, SEVERITY, __VA_ARGS__) +#define NEW_ERROR(NODE, PTR, SEVERITY, ...)\ + NEW_ERROR_WITH_INCLUDES(NODE, PTR, SEVERITY, __VA_ARGS__) /** * Variable whether the latest created error is stored */ -static mds_kbdc_parse_error_t* error; +static mds_kbdc_parse_error_t *error; /** * The parameter of `validate_tree` */ -static mds_kbdc_parsed_t* restrict result; +static mds_kbdc_parsed_t *restrict result; /** * The number visited for-statements @@ -67,22 +67,22 @@ static size_t fors = 0; /** * The function definition that is currently being visited */ -static mds_kbdc_tree_function_t* function = NULL; +static mds_kbdc_tree_function_t *function = NULL; /** * The macro definition that is currently being visited */ -static mds_kbdc_tree_macro_t* macro = NULL; +static mds_kbdc_tree_macro_t *macro = NULL; /** * The information clause that is currently being visited */ -static mds_kbdc_tree_information_t* information = NULL; +static mds_kbdc_tree_information_t *information = NULL; /** * The assumption clause that is currently being visited */ -static mds_kbdc_tree_assumption_t* assumption = NULL; +static mds_kbdc_tree_assumption_t *assumption = NULL; /** * The value `includes_ptr` had when `function`, @@ -105,7 +105,7 @@ static int innermost_visit = -1; * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_subtree(mds_kbdc_tree_t* restrict tree); +static int validate_subtree(mds_kbdc_tree_t *restrict tree); @@ -115,17 +115,18 @@ static int validate_subtree(mds_kbdc_tree_t* restrict tree); * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_include(mds_kbdc_tree_include_t* restrict tree) +static int +validate_include(mds_kbdc_tree_include_t *restrict tree) { - void* data; - int r; - fail_if (mds_kbdc_include_stack_push(tree, &data)); - r = validate_subtree(tree->inner); - mds_kbdc_include_stack_pop(data); - fail_if (r); - return 0; - fail: - return -1; + void *data; + int r; + fail_if (mds_kbdc_include_stack_push(tree, &data)); + r = validate_subtree(tree->inner); + mds_kbdc_include_stack_pop(data); + fail_if (r); + return 0; +fail: + return -1; } @@ -135,34 +136,30 @@ static int validate_include(mds_kbdc_tree_include_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_function(mds_kbdc_tree_function_t* restrict tree) +static int +validate_function(mds_kbdc_tree_function_t *restrict tree) { - int r; - if (VISITING(FUNCTION)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "nested function definition"); - NEW_ERROR(function, def_includes_ptr, NOTE, "outer function defined here"); - return 0; - } - else if (VISITING(MACRO)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "function definition inside macro definition"); - NEW_ERROR(macro, def_includes_ptr, NOTE, "outer macro defined here"); - return 0; - } - else if (VISITING(INFORMATION)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "function definition inside information clause"); - NEW_ERROR(information, def_includes_ptr, NOTE, "outer information clause defined here"); - return 0; - } - innermost_visit = tree->type; - function = tree; - def_includes_ptr = includes_ptr; - r = validate_subtree(tree->inner); - return function = NULL, r; - fail: - return -1; + int r; + if (VISITING(FUNCTION)) { + NEW_ERROR(tree, includes_ptr, ERROR, "nested function definition"); + NEW_ERROR(function, def_includes_ptr, NOTE, "outer function defined here"); + return 0; + } else if (VISITING(MACRO)) { + NEW_ERROR(tree, includes_ptr, ERROR, "function definition inside macro definition"); + NEW_ERROR(macro, def_includes_ptr, NOTE, "outer macro defined here"); + return 0; + } else if (VISITING(INFORMATION)) { + NEW_ERROR(tree, includes_ptr, ERROR, "function definition inside information clause"); + NEW_ERROR(information, def_includes_ptr, NOTE, "outer information clause defined here"); + return 0; + } + innermost_visit = tree->type; + function = tree; + def_includes_ptr = includes_ptr; + r = validate_subtree(tree->inner); + return function = NULL, r; +fail: + return -1; } @@ -172,34 +169,30 @@ static int validate_function(mds_kbdc_tree_function_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_macro(mds_kbdc_tree_macro_t* restrict tree) +static int +validate_macro(mds_kbdc_tree_macro_t *restrict tree) { - int r; - if (VISITING(FUNCTION)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "macro definition inside function definition"); - NEW_ERROR(function, def_includes_ptr, NOTE, "outer function definition defined here"); - return 0; - } - else if (VISITING(MACRO)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "nested macro definition"); - NEW_ERROR(macro, def_includes_ptr, NOTE, "outer macro defined here"); - return 0; - } - else if (VISITING(INFORMATION)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "macro definition inside information clause"); - NEW_ERROR(information, def_includes_ptr, NOTE, "outer information clause defined here"); - return 0; - } - innermost_visit = tree->type; - macro = tree; - def_includes_ptr = includes_ptr; - r = validate_subtree(tree->inner); - return macro = NULL, r; - fail: - return -1; + int r; + if (VISITING(FUNCTION)) { + NEW_ERROR(tree, includes_ptr, ERROR, "macro definition inside function definition"); + NEW_ERROR(function, def_includes_ptr, NOTE, "outer function definition defined here"); + return 0; + } else if (VISITING(MACRO)) { + NEW_ERROR(tree, includes_ptr, ERROR, "nested macro definition"); + NEW_ERROR(macro, def_includes_ptr, NOTE, "outer macro defined here"); + return 0; + } else if (VISITING(INFORMATION)) { + NEW_ERROR(tree, includes_ptr, ERROR, "macro definition inside information clause"); + NEW_ERROR(information, def_includes_ptr, NOTE, "outer information clause defined here"); + return 0; + } + innermost_visit = tree->type; + macro = tree; + def_includes_ptr = includes_ptr; + r = validate_subtree(tree->inner); + return macro = NULL, r; +fail: + return -1; } @@ -209,40 +202,34 @@ static int validate_macro(mds_kbdc_tree_macro_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_information(mds_kbdc_tree_information_t* restrict tree) +static int +validate_information(mds_kbdc_tree_information_t *restrict tree) { - int r; - if (VISITING(FUNCTION)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "information clause inside function definition"); - NEW_ERROR(function, def_includes_ptr, NOTE, "outer function definition defined here"); - return 0; - } - else if (VISITING(MACRO)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "information clause inside macro definition"); - NEW_ERROR(macro, def_includes_ptr, NOTE, "outer macro defined here"); - return 0; - } - else if (VISITING(INFORMATION)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "nested information clause"); - NEW_ERROR(information, def_includes_ptr, NOTE, "outer information clause defined here"); - return 0; - } - else if (VISITING(ASSUMPTION)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "information clause inside assumption clause"); - NEW_ERROR(assumption, def_includes_ptr, NOTE, "outer assumption clause defined here"); - return 0; - } - innermost_visit = tree->type; - information = tree; - def_includes_ptr = includes_ptr; - r = validate_subtree(tree->inner); - return information = NULL, r; - fail: - return -1; + int r; + if (VISITING(FUNCTION)) { + NEW_ERROR(tree, includes_ptr, ERROR, "information clause inside function definition"); + NEW_ERROR(function, def_includes_ptr, NOTE, "outer function definition defined here"); + return 0; + } else if (VISITING(MACRO)) { + NEW_ERROR(tree, includes_ptr, ERROR, "information clause inside macro definition"); + NEW_ERROR(macro, def_includes_ptr, NOTE, "outer macro defined here"); + return 0; + } else if (VISITING(INFORMATION)) { + NEW_ERROR(tree, includes_ptr, ERROR, "nested information clause"); + NEW_ERROR(information, def_includes_ptr, NOTE, "outer information clause defined here"); + return 0; + } else if (VISITING(ASSUMPTION)) { + NEW_ERROR(tree, includes_ptr, ERROR, "information clause inside assumption clause"); + NEW_ERROR(assumption, def_includes_ptr, NOTE, "outer assumption clause defined here"); + return 0; + } + innermost_visit = tree->type; + information = tree; + def_includes_ptr = includes_ptr; + r = validate_subtree(tree->inner); + return information = NULL, r; +fail: + return -1; } @@ -252,40 +239,34 @@ static int validate_information(mds_kbdc_tree_information_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_assumption(mds_kbdc_tree_assumption_t* restrict tree) +static int +validate_assumption(mds_kbdc_tree_assumption_t *restrict tree) { - int r; - if (VISITING(FUNCTION)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "assumption clause inside function definition"); - NEW_ERROR(function, def_includes_ptr, NOTE, "outer function definition defined here"); - return 0; - } - else if (VISITING(MACRO)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "assumption clause inside macro definition"); - NEW_ERROR(macro, def_includes_ptr, NOTE, "outer macro defined here"); - return 0; - } - else if (VISITING(INFORMATION)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "assumption clause inside information clause"); - NEW_ERROR(information, def_includes_ptr, NOTE, "outer information clause defined here"); - return 0; - } - else if (VISITING(ASSUMPTION)) - { - NEW_ERROR(tree, includes_ptr, ERROR, "nested assumption clause"); - NEW_ERROR(assumption, def_includes_ptr, NOTE, "outer assumption clause defined here"); - return 0; - } - innermost_visit = tree->type; - assumption = tree; - def_includes_ptr = includes_ptr; - r = validate_subtree(tree->inner); - return assumption = NULL, r; - fail: - return -1; + int r; + if (VISITING(FUNCTION)) { + NEW_ERROR(tree, includes_ptr, ERROR, "assumption clause inside function definition"); + NEW_ERROR(function, def_includes_ptr, NOTE, "outer function definition defined here"); + return 0; + } else if (VISITING(MACRO)) { + NEW_ERROR(tree, includes_ptr, ERROR, "assumption clause inside macro definition"); + NEW_ERROR(macro, def_includes_ptr, NOTE, "outer macro defined here"); + return 0; + } else if (VISITING(INFORMATION)) { + NEW_ERROR(tree, includes_ptr, ERROR, "assumption clause inside information clause"); + NEW_ERROR(information, def_includes_ptr, NOTE, "outer information clause defined here"); + return 0; + } else if (VISITING(ASSUMPTION)) { + NEW_ERROR(tree, includes_ptr, ERROR, "nested assumption clause"); + NEW_ERROR(assumption, def_includes_ptr, NOTE, "outer assumption clause defined here"); + return 0; + } + innermost_visit = tree->type; + assumption = tree; + def_includes_ptr = includes_ptr; + r = validate_subtree(tree->inner); + return assumption = NULL, r; +fail: + return -1; } @@ -295,25 +276,26 @@ static int validate_assumption(mds_kbdc_tree_assumption_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_map(mds_kbdc_tree_map_t* restrict tree) +static int +validate_map(mds_kbdc_tree_map_t *restrict tree) { - int is_value = tree->result == NULL; - if (is_value); - /* We do not want value-statments outside function - * definitions, however, we do want \set/3 to be usable, - * from anywhere, even indirectly, therefore we cannot, - * at this process level, determine whether a - * value-statement is used correctly or not. - */ - else if (VISITING(INFORMATION)) - NEW_ERROR(tree, includes_ptr, ERROR, "mapping-statement inside information clause"); - else if (VISITING(ASSUMPTION)) - NEW_ERROR(tree, includes_ptr, ERROR, "mapping-statement inside assumption clause"); - else if (VISITING(FUNCTION)) - NEW_ERROR(tree, includes_ptr, ERROR, "mapping-statement inside function definition"); - return 0; + int is_value = tree->result == NULL; + if (is_value) + /* We do not want value-statments outside function + * definitions, however, we do want \set/3 to be usable, + * from anywhere, even indirectly, therefore we cannot, + * at this process level, determine whether a + * value-statement is used correctly or not. + */; + else if (VISITING(INFORMATION)) + NEW_ERROR(tree, includes_ptr, ERROR, "mapping-statement inside information clause"); + else if (VISITING(ASSUMPTION)) + NEW_ERROR(tree, includes_ptr, ERROR, "mapping-statement inside assumption clause"); + else if (VISITING(FUNCTION)) + NEW_ERROR(tree, includes_ptr, ERROR, "mapping-statement inside function definition"); + return 0; fail: - return -1; + return -1; } @@ -323,17 +305,18 @@ static int validate_map(mds_kbdc_tree_map_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_macro_call(mds_kbdc_tree_macro_call_t* restrict tree) +static int +validate_macro_call(mds_kbdc_tree_macro_call_t *restrict tree) { - if (VISITING(INFORMATION)) - NEW_ERROR(tree, includes_ptr, ERROR, "macro call inside information clause"); - else if (VISITING(ASSUMPTION)) - NEW_ERROR(tree, includes_ptr, ERROR, "macro call inside assumption clause"); - else if (VISITING(FUNCTION)) - NEW_ERROR(tree, includes_ptr, ERROR, "macro call inside function definition"); - return 0; - fail: - return -1; + if (VISITING(INFORMATION)) + NEW_ERROR(tree, includes_ptr, ERROR, "macro call inside information clause"); + else if (VISITING(ASSUMPTION)) + NEW_ERROR(tree, includes_ptr, ERROR, "macro call inside assumption clause"); + else if (VISITING(FUNCTION)) + NEW_ERROR(tree, includes_ptr, ERROR, "macro call inside function definition"); + return 0; +fail: + return -1; } @@ -343,14 +326,15 @@ static int validate_macro_call(mds_kbdc_tree_macro_call_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_for(mds_kbdc_tree_for_t* restrict tree) +static int +validate_for(mds_kbdc_tree_for_t *restrict tree) { - int r; - fors++, r = validate_subtree(tree->inner), fors--; - fail_if (r); - return 0; - fail: - return -1; + int r; + fors++, r = validate_subtree(tree->inner), fors--; + fail_if (r); + return 0; +fail: + return -1; } @@ -360,12 +344,13 @@ static int validate_for(mds_kbdc_tree_for_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_if(mds_kbdc_tree_if_t* restrict tree) +static int +validate_if(mds_kbdc_tree_if_t *restrict tree) { - fail_if ((validate_subtree(tree->inner) || validate_subtree(tree->otherwise))); - return 0; - fail: - return -1; + fail_if ((validate_subtree(tree->inner) || validate_subtree(tree->otherwise))); + return 0; +fail: + return -1; } @@ -375,13 +360,14 @@ static int validate_if(mds_kbdc_tree_if_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_return(mds_kbdc_tree_return_t* restrict tree) +static int +validate_return(mds_kbdc_tree_return_t *restrict tree) { - if ((function == NULL) && (macro == NULL)) - NEW_ERROR(tree, includes_ptr, ERROR, "‘return’ outside function and macro definition"); - return 0; - fail: - return -1; + if (!function && !macro) + NEW_ERROR(tree, includes_ptr, ERROR, "‘return’ outside function and macro definition"); + return 0; +fail: + return -1; } @@ -391,13 +377,14 @@ static int validate_return(mds_kbdc_tree_return_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_break(mds_kbdc_tree_break_t* restrict tree) +static int +validate_break(mds_kbdc_tree_break_t *restrict tree) { - if (fors == 0) - NEW_ERROR(tree, includes_ptr, ERROR, "‘break’ outside ‘for’"); - return 0; - fail: - return -1; + if (!fors) + NEW_ERROR(tree, includes_ptr, ERROR, "‘break’ outside ‘for’"); + return 0; +fail: + return -1; } @@ -407,13 +394,14 @@ static int validate_break(mds_kbdc_tree_break_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_continue(mds_kbdc_tree_continue_t* restrict tree) +static int +validate_continue(mds_kbdc_tree_continue_t *restrict tree) { - if (fors == 0) - NEW_ERROR(tree, includes_ptr, ERROR, "‘continue’ outside ‘for’"); - return 0; - fail: - return -1; + if (!fors) + NEW_ERROR(tree, includes_ptr, ERROR, "‘continue’ outside ‘for’"); + return 0; +fail: + return -1; } @@ -423,13 +411,14 @@ static int validate_continue(mds_kbdc_tree_continue_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_assumption_data(mds_kbdc_tree_t* restrict tree) +static int +validate_assumption_data(mds_kbdc_tree_t *restrict tree) { - if (assumption == NULL) - NEW_ERROR(tree, includes_ptr, ERROR, "assumption outside assumption clause"); - return 0; - fail: - return -1; + if (!assumption) + NEW_ERROR(tree, includes_ptr, ERROR, "assumption outside assumption clause"); + return 0; +fail: + return -1; } @@ -439,13 +428,14 @@ static int validate_assumption_data(mds_kbdc_tree_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_information_data(mds_kbdc_tree_t* restrict tree) +static int +validate_information_data(mds_kbdc_tree_t *restrict tree) { - if (information == NULL) - NEW_ERROR(tree, includes_ptr, ERROR, "information outside information clause"); - return 0; - fail: - return -1; + if (!information) + NEW_ERROR(tree, includes_ptr, ERROR, "information outside information clause"); + return 0; +fail: + return -1; } @@ -455,48 +445,48 @@ static int validate_information_data(mds_kbdc_tree_t* restrict tree) * @param tree The tree to validate * @return Zero on success, -1 on error */ -static int validate_subtree(mds_kbdc_tree_t* restrict tree) +static int +validate_subtree(mds_kbdc_tree_t *restrict tree) { -#define v(type) fail_if (validate_##type(&(tree->type))) -#define V(type) fail_if (validate_##type(&(tree->type##_))) - int old_innermost_visit = innermost_visit; - again: - if (tree == NULL) - return 0; - - switch (tree->type) - { - case C(INFORMATION): v(information); break; - case C(INCLUDE): v(include); break; - case C(FUNCTION): v(function); break; - case C(MACRO): v(macro); break; - case C(ASSUMPTION): v(assumption); break; - case C(FOR): V(for); break; - case C(IF): V(if); break; - case C(MAP): v(map); break; - case C(MACRO_CALL): v(macro_call); break; - case C(RETURN): V(return); break; - case C(BREAK): V(break); break; - case C(CONTINUE): V(continue); break; - case C(INFORMATION_LANGUAGE): - case C(INFORMATION_COUNTRY): - case C(INFORMATION_VARIANT): - fail_if (validate_information_data(tree)); - break; - case C(ASSUMPTION_HAVE): - case C(ASSUMPTION_HAVE_CHARS): - case C(ASSUMPTION_HAVE_RANGE): - fail_if (validate_assumption_data(tree)); - break; - default: - break; - } - - innermost_visit = old_innermost_visit; - tree = tree->next; - goto again; - fail: - return innermost_visit = old_innermost_visit, -1; +#define v(type) fail_if (validate_##type(&(tree->type))) +#define V(type) fail_if (validate_##type(&(tree->type##_))) + int old_innermost_visit = innermost_visit; +again: + if (!tree) + return 0; + + switch (tree->type) { + case C(INFORMATION): v(information); break; + case C(INCLUDE): v(include); break; + case C(FUNCTION): v(function); break; + case C(MACRO): v(macro); break; + case C(ASSUMPTION): v(assumption); break; + case C(FOR): V(for); break; + case C(IF): V(if); break; + case C(MAP): v(map); break; + case C(MACRO_CALL): v(macro_call); break; + case C(RETURN): V(return); break; + case C(BREAK): V(break); break; + case C(CONTINUE): V(continue); break; + case C(INFORMATION_LANGUAGE): + case C(INFORMATION_COUNTRY): + case C(INFORMATION_VARIANT): + fail_if (validate_information_data(tree)); + break; + case C(ASSUMPTION_HAVE): + case C(ASSUMPTION_HAVE_CHARS): + case C(ASSUMPTION_HAVE_RANGE): + fail_if (validate_assumption_data(tree)); + break; + default: + break; + } + + innermost_visit = old_innermost_visit; + tree = tree->next; + goto again; +fail: + return innermost_visit = old_innermost_visit, -1; #undef V #undef v } @@ -508,17 +498,18 @@ static int validate_subtree(mds_kbdc_tree_t* restrict tree) * @param result_ `result` from `process_includes`, will be updated * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise */ -int validate_tree(mds_kbdc_parsed_t* restrict result_) +int +validate_tree(mds_kbdc_parsed_t *restrict result_) { - int r; - mds_kbdc_include_stack_begin(result = result_); - r = validate_subtree(result_->tree); - fors = 0; - mds_kbdc_include_stack_end(); - fail_if (r); - return 0; - fail: - return -1; + int r; + mds_kbdc_include_stack_begin(result = result_); + r = validate_subtree(result_->tree); + fors = 0; + mds_kbdc_include_stack_end(); + fail_if (r); + return 0; +fail: + return -1; } @@ -526,4 +517,3 @@ int validate_tree(mds_kbdc_parsed_t* restrict result_) #undef NEW_ERROR #undef VISITING #undef C - diff --git a/src/mds-kbdc/validate-tree.h b/src/mds-kbdc/validate-tree.h index e32b2f2..5ca9277 100644 --- a/src/mds-kbdc/validate-tree.h +++ b/src/mds-kbdc/validate-tree.h @@ -28,8 +28,7 @@ * @param result `result` from `process_includes`, will be updated * @return -1 if an error occursed that cannot be stored in `result`, zero otherwise */ -int validate_tree(mds_kbdc_parsed_t* restrict result); +int validate_tree(mds_kbdc_parsed_t *restrict result); #endif - diff --git a/src/mds-kbdc/variables.c b/src/mds-kbdc/variables.c index 3b2e128..15a1cb6 100644 --- a/src/mds-kbdc/variables.c +++ b/src/mds-kbdc/variables.c @@ -27,32 +27,30 @@ /** * The state of a variable */ -typedef struct variable -{ - /** - * The current value of the variable - */ - mds_kbdc_tree_t* value; - - /** - * The previous version of variable, - * before it was shadowed - */ - struct variable* restrict previous; - - /** - * The original scope in which the current - * shadow of the variable was created - */ - size_t scope; - - /** - * The latest scope the in which the - * variable has been used in a for-loop, - * `~0' if never, or below `scope` - */ - size_t used_in_for; - +typedef struct variable { + /** + * The current value of the variable + */ + mds_kbdc_tree_t *value; + + /** + * The previous version of variable, + * before it was shadowed + */ + struct variable *restrict previous; + + /** + * The original scope in which the current + * shadow of the variable was created + */ + size_t scope; + + /** + * The latest scope the in which the + * variable has been used in a for-loop, + * `~0' if never, or below `scope` + */ + size_t used_in_for; } variable_t; @@ -60,7 +58,7 @@ typedef struct variable /** * Map (by index) of defined variables */ -static variable_t** restrict variables = NULL; +static variable_t **restrict variables = NULL; /** * The size of `variables` @@ -79,20 +77,21 @@ static size_t current_scope = 0; /** * Destroy the variable storage */ -void variables_terminate(void) +void +variables_terminate(void) { - size_t i; - variable_t* old; - for (i = 0; i < variable_count; i++) - while (variables[i]) - { - old = variables[i]; - variables[i] = variables[i]->previous; - mds_kbdc_tree_free(old->value); - free(old); - } - free(variables), variables = NULL; - variable_count = current_scope = 0; + size_t i; + variable_t *old; + for (i = 0; i < variable_count; i++) { + while (variables[i]) { + old = variables[i]; + variables[i] = variables[i]->previous; + mds_kbdc_tree_free(old->value); + free(old); + } + } + free(variables), variables = NULL; + variable_count = current_scope = 0; } @@ -100,9 +99,10 @@ void variables_terminate(void) * Push the variable-stack, making it * possible to shadow all variables */ -void variables_stack_push(void) +void +variables_stack_push(void) { - current_scope++; + current_scope++; } @@ -112,19 +112,20 @@ void variables_stack_push(void) * since it was last called (without a * corresponding call to this function) */ -void variables_stack_pop(void) +void +variables_stack_pop(void) { - size_t i; - variable_t* old; - for (i = 0; i < variable_count; i++) - if (variables[i] && (variables[i]->scope == current_scope)) - { - old = variables[i]; - variables[i] = variables[i]->previous; - mds_kbdc_tree_free(old->value); - free(old); - } - current_scope--; + size_t i; + variable_t *old; + for (i = 0; i < variable_count; i++) { + if (variables[i] && variables[i]->scope == current_scope) { + old = variables[i]; + variables[i] = variables[i]->previous; + mds_kbdc_tree_free(old->value); + free(old); + } + } + current_scope--; } @@ -135,11 +136,12 @@ void variables_stack_pop(void) * @param variable The variable index * @return Whether a let will override the variable */ -int variables_let_will_override(size_t variable) +int +variables_let_will_override(size_t variable) { - if (variable >= variable_count) return 0; - if (variables[variable] == NULL) return 0; - return variables[variable]->scope == current_scope; + if (variable >= variable_count) return 0; + if (!variables[variable]) return 0; + return variables[variable]->scope == current_scope; } @@ -150,42 +152,39 @@ int variables_let_will_override(size_t variable) * @param value The variable's new value * @return Zero on success, -1 on error */ -int variables_let(size_t variable, mds_kbdc_tree_t* restrict value) +int +variables_let(size_t variable, mds_kbdc_tree_t *restrict value) { - variable_t** new; - variable_t* previous; - - /* Grow the table if necessary to fit the variable. */ - if (variable >= variable_count) - { - new = variables; - fail_if (xrealloc(new, variable + 1, variable_t*)); - variables = new; - memset(variables + variable_count, 0, (variable + 1 - variable_count) * sizeof(variable_t*)); - variable_count = variable + 1; - } + variable_t **new; + variable_t *previous; + + /* Grow the table if necessary to fit the variable. */ + if (variable >= variable_count) { + new = variables; + fail_if (xrealloc(new, variable + 1, variable_t*)); + variables = new; + memset(variables + variable_count, 0, (variable + 1 - variable_count) * sizeof(variable_t*)); + variable_count = variable + 1; + } + + if (variables_let_will_override(variable)) { + /* Override. */ + mds_kbdc_tree_free(variables[variable]->value); + variables[variable]->value = value; + } else { + /* Shadow or define. */ + previous = variables[variable]; + if (xmalloc(variables[variable], 1, variable_t)) + fail_if (variables[variable] = previous, 1); + variables[variable]->value = value; + variables[variable]->previous = previous; + variables[variable]->scope = current_scope; + variables[variable]->used_in_for = (size_t)(~0LL); + } - if (variables_let_will_override(variable)) - { - /* Override. */ - mds_kbdc_tree_free(variables[variable]->value); - variables[variable]->value = value; - } - else - { - /* Shadow or define. */ - previous = variables[variable]; - if (xmalloc(variables[variable], 1, variable_t)) - fail_if (variables[variable] = previous, 1); - variables[variable]->value = value; - variables[variable]->previous = previous; - variables[variable]->scope = current_scope; - variables[variable]->used_in_for = (size_t)(~0LL); - } - - return 0; - fail: - return -1; + return 0; +fail: + return -1; } @@ -198,11 +197,12 @@ int variables_let(size_t variable, mds_kbdc_tree_t* restrict value) * @param variable The variable index * @return The variable's value, `NULL` if not defined */ -mds_kbdc_tree_t* variables_get(size_t variable) +mds_kbdc_tree_t * +variables_get(size_t variable) { - if (variable >= variable_count) return NULL; - if (variables[variable] == NULL) return NULL; - return variables[variable]->value; + if (variable >= variable_count) return NULL; + if (!variables[variable]) return NULL; + return variables[variable]->value; } @@ -212,31 +212,32 @@ mds_kbdc_tree_t* variables_get(size_t variable) * @param variable The variable index, must already be defined * @return Zero on success, -1 on error */ -int variables_was_used_in_for(size_t variable) +int +variables_was_used_in_for(size_t variable) { - variable_t* previous; - - /* Already marked. */ - if (variables[variable]->used_in_for == current_scope) - return 0; - - /* Not marked. */ - if (variables[variable]->used_in_for == (size_t)(~0LL)) - return variables[variable]->used_in_for = current_scope, 0; - - /* Marked for another scope. */ - previous = variables[variable]; - if (xmalloc(variables[variable], 1, variable_t)) - fail_if (variables[variable] = previous, 1); - variables[variable]->value = mds_kbdc_tree_dup(previous->value); - fail_if (variables[variable]->value == NULL); - variables[variable]->previous = previous; - variables[variable]->scope = current_scope; - variables[variable]->used_in_for = current_scope; - - return 0; - fail: - return -1; + variable_t *previous; + + /* Already marked. */ + if (variables[variable]->used_in_for == current_scope) + return 0; + + /* Not marked. */ + if (variables[variable]->used_in_for == (size_t)(~0LL)) + return variables[variable]->used_in_for = current_scope, 0; + + /* Marked for another scope. */ + previous = variables[variable]; + if (xmalloc(variables[variable], 1, variable_t)) + fail_if (variables[variable] = previous, 1); + variables[variable]->value = mds_kbdc_tree_dup(previous->value); + fail_if (variables[variable]->value == NULL); + variables[variable]->previous = previous; + variables[variable]->scope = current_scope; + variables[variable]->used_in_for = current_scope; + + return 0; +fail: + return -1; } @@ -246,8 +247,8 @@ int variables_was_used_in_for(size_t variable) * @param variable The variable index, must already be defined * @return Whether `variables_was_used_in_for` has been unused on the variable */ -int variables_has_been_used_in_for(size_t variable) +int +variables_has_been_used_in_for(size_t variable) { - return variables[variable]->used_in_for == current_scope; + return variables[variable]->used_in_for == current_scope; } - diff --git a/src/mds-kbdc/variables.h b/src/mds-kbdc/variables.h index 485961b..a175ab7 100644 --- a/src/mds-kbdc/variables.h +++ b/src/mds-kbdc/variables.h @@ -52,7 +52,8 @@ void variables_stack_pop(void); * @param variable The variable index * @return Whether a let will override the variable */ -int variables_let_will_override(size_t variable) __attribute__((pure)); +__attribute__((pure)) +int variables_let_will_override(size_t variable); /** * Assign a value to a variable, and define or shadow it in the process @@ -61,7 +62,7 @@ int variables_let_will_override(size_t variable) __attribute__((pure)); * @param value The variable's new value * @return Zero on success, -1 on error */ -int variables_let(size_t variable, mds_kbdc_tree_t* restrict value); +int variables_let(size_t variable, mds_kbdc_tree_t *restrict value); /** * Get the value currently assigned to a variable @@ -72,7 +73,8 @@ int variables_let(size_t variable, mds_kbdc_tree_t* restrict value); * @param variable The variable index * @return The variable's value, `NULL` if not defined */ -mds_kbdc_tree_t* variables_get(size_t variable) __attribute__((pure)); +__attribute__((pure)) +mds_kbdc_tree_t *variables_get(size_t variable); /** * Mark a variable as having been unsed in a for-loop in the current scope @@ -88,8 +90,8 @@ int variables_was_used_in_for(size_t variable); * @param variable The variable index, must already be defined * @return Whether `variables_was_used_in_for` has been unused on the variable */ -int variables_has_been_used_in_for(size_t variable) __attribute__((pure)); +__attribute__((pure)) +int variables_has_been_used_in_for(size_t variable); #endif - diff --git a/src/mds-kkbd.c b/src/mds-kkbd.c index e57e6b5..31915bd 100644 --- a/src/mds-kkbd.c +++ b/src/mds-kkbd.c @@ -1718,7 +1718,7 @@ void shrink_map(void) { size_t i, greatest_mapping = 0; - int* old; + int *old; for (i = mapping_size; i > 0; i--) { if (mapping[i] != (int)i) { diff --git a/src/mds-libinput.h b/src/mds-libinput.h index 85ad5d5..6474e6d 100644 --- a/src/mds-libinput.h +++ b/src/mds-libinput.h @@ -105,4 +105,3 @@ void dump_info(void); #endif - diff --git a/src/mds-registry/mds-registry.c b/src/mds-registry/mds-registry.c index 57a0b92..3d17247 100644 --- a/src/mds-registry/mds-registry.c +++ b/src/mds-registry/mds-registry.c @@ -66,7 +66,8 @@ server_characteristics_t server_characteristics = { * * @return Non-zero on error */ -int preinitialise_server(void) +int +preinitialise_server(void) { int stage = 0; diff --git a/src/mds-registry/registry.c b/src/mds-registry/registry.c index f5a9b8a..0c4d5a5 100644 --- a/src/mds-registry/registry.c +++ b/src/mds-registry/registry.c @@ -465,7 +465,8 @@ handle_register_message(void) * @return Zero on success, -1 on error or interruption, * `errno` will be set accordingly */ -int handle_message(void) +int +handle_message(void) { size_t i; for (i = 0; i < received.header_count; i++) { @@ -476,6 +477,6 @@ int handle_message(void) } fail_if (handle_close_message()); return 0; - fail: +fail: return -1; } diff --git a/src/mds-registry/signals.c b/src/mds-registry/signals.c index 9b0a7a0..8fb90dd 100644 --- a/src/mds-registry/signals.c +++ b/src/mds-registry/signals.c @@ -34,7 +34,8 @@ * * @param signo The signal */ -void signal_all(int signo) +void +signal_all(int signo) { pthread_t current_thread; ssize_t node; diff --git a/src/mds-registry/slave.h b/src/mds-registry/slave.h index f9f748b..0b4f7b2 100644 --- a/src/mds-registry/slave.h +++ b/src/mds-registry/slave.h @@ -35,8 +35,7 @@ /** * Slave information, a thread waiting for protocols to become available */ -typedef struct slave -{ +typedef struct slave { /** * Set of protocols for which to wait that they become available */ @@ -82,7 +81,6 @@ typedef struct slave * Whether `dethklok` should apply */ int timed; - } slave_t; diff --git a/src/mds-registry/util.c b/src/mds-registry/util.c index c8d2015..77dff5a 100644 --- a/src/mds-registry/util.c +++ b/src/mds-registry/util.c @@ -37,7 +37,8 @@ * * @param obj The key */ -void reg_table_free_key(size_t obj) +void +reg_table_free_key(size_t obj) { char *command = (void *)obj; free(command); @@ -49,7 +50,8 @@ void reg_table_free_key(size_t obj) * * @param obj The value */ -void reg_table_free_value(size_t obj) +void +reg_table_free_value(size_t obj) { client_list_t *list = (void *)obj; client_list_destroy(list); diff --git a/src/mds-respawn.h b/src/mds-respawn.h index c614cf4..b664c05 100644 --- a/src/mds-respawn.h +++ b/src/mds-respawn.h @@ -66,8 +66,7 @@ /** * The state and identifier of a server */ -typedef struct server_state -{ +typedef struct server_state { /** * The server's process ID */ @@ -82,10 +81,8 @@ typedef struct server_state * The time (monotonic) the server started */ struct timespec started; - } server_state_t; #endif - diff --git a/src/mds-server/client.h b/src/mds-server/client.h index 91ab0c2..b003d31 100644 --- a/src/mds-server/client.h +++ b/src/mds-server/client.h @@ -36,8 +36,7 @@ /** * Client information structure */ -typedef struct client -{ +typedef struct client { /** * The client's entry in the list of clients */ @@ -134,7 +133,6 @@ typedef struct client * Whether `modify_cond` has been initialised */ int modify_cond_created; - } client_t; diff --git a/src/mds-server/globals.h b/src/mds-server/globals.h index 94a3651..8083717 100644 --- a/src/mds-server/globals.h +++ b/src/mds-server/globals.h @@ -93,4 +93,3 @@ extern hash_table_t modify_map; #endif - diff --git a/src/mds-server/interception-condition.h b/src/mds-server/interception-condition.h index 1ca3823..78383f4 100644 --- a/src/mds-server/interception-condition.h +++ b/src/mds-server/interception-condition.h @@ -28,8 +28,7 @@ /** * A condition for a message being intercepted by a client */ -typedef struct interception_condition -{ +typedef struct interception_condition { /** * The header of messages to intercept, optionally with a value, * empty (most not be NULL) for all messages. @@ -52,7 +51,6 @@ typedef struct interception_condition * Whether the messages may get modified by the client */ int modifying; - } interception_condition_t; diff --git a/src/mds-server/interceptors.h b/src/mds-server/interceptors.h index 99cd0a3..21f74d4 100644 --- a/src/mds-server/interceptors.h +++ b/src/mds-server/interceptors.h @@ -52,7 +52,7 @@ void add_intercept_condition(client_t *client, char *condition, int64_t priority */ __attribute__((pure, nonnull(1))) int is_condition_matching(interception_condition_t *cond, size_t *hashes, - char **keys, char **headers, size_t count); + char **keys, char **headers, size_t count); /** diff --git a/src/mds-server/multicast.h b/src/mds-server/multicast.h index 611298f..126c4ba 100644 --- a/src/mds-server/multicast.h +++ b/src/mds-server/multicast.h @@ -27,8 +27,7 @@ /** * Message multicast state */ -typedef struct multicast -{ +typedef struct multicast { /** * Queue of clients that is listening this message */ @@ -63,7 +62,6 @@ typedef struct multicast * How much of the message to skip if the recipient is not a modifier */ size_t message_prefix; - } multicast_t; diff --git a/src/mds-server/queued-interception.h b/src/mds-server/queued-interception.h index 2a072bc..1555801 100644 --- a/src/mds-server/queued-interception.h +++ b/src/mds-server/queued-interception.h @@ -29,8 +29,7 @@ /** * A queued interception */ -typedef struct queued_interception -{ +typedef struct queued_interception { /** * The intercepting client */ @@ -50,7 +49,6 @@ typedef struct queued_interception * The file descriptor of the intercepting client's socket (used for unmarshalling) */ int socket_fd; - } queued_interception_t; diff --git a/src/mds-vt.c b/src/mds-vt.c index c009d65..7a34dd6 100644 --- a/src/mds-vt.c +++ b/src/mds-vt.c @@ -38,7 +38,7 @@ -#define MDS_VT_VARS_VERSION 0 +#define MDS_VT_VARS_VERSION 0 diff --git a/src/mds.h b/src/mds.h index 45ebbbf..49c911c 100644 --- a/src/mds.h +++ b/src/mds.h @@ -57,7 +57,7 @@ int spawn_and_respawn_server(int fd); * @return Non-zero on error */ __attribute__((nonnull)) -int create_directory_root(const char* pathname); +int create_directory_root(const char *pathname); /** * Create a directory owned by the real user and nobody group @@ -66,7 +66,7 @@ int create_directory_root(const char* pathname); * @return Non-zero on error */ __attribute__((nonnull)) -int create_directory_user(const char* pathname); +int create_directory_user(const char *pathname); /** * Recursively remove a directory @@ -75,8 +75,7 @@ int create_directory_user(const char* pathname); * @return Non-zero on error */ __attribute__((nonnull)) -int unlink_recursive(const char* pathname); +int unlink_recursive(const char *pathname); #endif - -- cgit v1.2.3-70-g09d2