diff options
| author | Berke Güzel <wenekar1@gmail.com> | 2026-10-12 00:09:38 +0300 |
|---|---|---|
| committer | Berke Güzel <wenekar1@gmail.com> | 2026-10-12 00:09:38 +0300 |
| commit | 624d1371304a5ae4b3429ad5e4267aac7cd03dfd (patch) | |
| tree | 32de069f6eec83686521fc4bf39cc9874b123e93 /src/common/input.c | |
| parent | e813252e685d761235ad45e170d97c9375f51958 (diff) | |
missing impls and hardening
Diffstat (limited to 'src/common/input.c')
| -rw-r--r-- | src/common/input.c | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/src/common/input.c b/src/common/input.c new file mode 100644 index 0000000..eac4d1a --- /dev/null +++ b/src/common/input.c @@ -0,0 +1,103 @@ +#include "input.h" + +#include <stdlib.h> +#include <string.h> + +static const char *event_text(const struct yasl_input_event *ev, size_t *len) +{ + switch (ev->kind) { + case YASL_INPUT_TEXT: *len = ev->text.len; return ev->text.text; + case YASL_INPUT_PASTE: *len = ev->paste.len; return ev->paste.text; + case YASL_INPUT_DROP_FILES: *len = ev->drop_files.len; return ev->drop_files.files; + default: *len = 0; return NULL; + } +} + +static void set_text(struct yasl_input_event *ev, const char *text) +{ + switch (ev->kind) { + case YASL_INPUT_TEXT: ev->text.text = text; break; + case YASL_INPUT_PASTE: ev->paste.text = text; break; + case YASL_INPUT_DROP_FILES: ev->drop_files.files = text; break; + default: break; + } +} + +static void discard_pending(struct input_queue *q) +{ + for (size_t i = 0; i < q->count; i++) { + size_t len; + free((void *)event_text(&q->events[(q->head + i) % q->capacity], &len)); + } + q->head = q->count = 0; +} + +bool input_queue_push(struct input_queue *q, const struct yasl_input_event *ev) +{ + struct yasl_input_event copy = *ev; + size_t len; + const char *text = event_text(ev, &len); + char *owned = NULL; + if (ev->kind == YASL_INPUT_TEXT || ev->kind == YASL_INPUT_PASTE || + ev->kind == YASL_INPUT_DROP_FILES) { + if ((!text && len) || len == SIZE_MAX) goto failed; + owned = malloc(len + 1); + if (!owned) goto failed; + if (len) memcpy(owned, text, len); + owned[len] = '\0'; + set_text(©, owned); + } + if (q->count == q->capacity) { + size_t capacity = q->capacity ? q->capacity * 2 : 32; + if (capacity < q->capacity || capacity > SIZE_MAX / sizeof(*q->events)) + goto failed; + struct yasl_input_event *events = malloc(capacity * sizeof(*events)); + if (!events) goto failed; + for (size_t i = 0; i < q->count; i++) + events[i] = q->events[(q->head + i) % q->capacity]; + free(q->events); + q->events = events; + q->capacity = capacity; + q->head = 0; + } + q->events[(q->head + q->count) % q->capacity] = copy; + q->count++; + return true; + +failed: + free(owned); + /* A missing release must never silently leave app input state stuck. + * Discard the old stream and deliver an allocation-free reset first. */ + discard_pending(q); + q->reset_surface = ev->surface; + q->reset_pending = true; + return false; +} + +bool input_queue_pop(struct input_queue *q, struct yasl_input_event *ev) +{ + if (!ev || (!q->count && !q->reset_pending)) return false; + free(q->last_text); + q->last_text = NULL; + if (q->reset_pending) { + *ev = (struct yasl_input_event){ + .surface = q->reset_surface, .kind = YASL_INPUT_RESET, + }; + q->reset_pending = false; + return true; + } + *ev = q->events[q->head]; + size_t len; + q->last_text = (char *)event_text(ev, &len); + q->head = (q->head + 1) % q->capacity; + q->count--; + return true; +} + +void input_queue_clear(struct input_queue *q) +{ + discard_pending(q); + free(q->last_text); + free(q->events); + *q = (struct input_queue){0}; +} |
