diff options
Diffstat (limited to '')
-rw-r--r-- | interactive-test.c | 130 |
1 files changed, 126 insertions, 4 deletions
diff --git a/interactive-test.c b/interactive-test.c index 2180de8..3945eb2 100644 --- a/interactive-test.c +++ b/interactive-test.c @@ -1,4 +1,8 @@ /* See LICENSE file for copyright and license details. */ +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -8,15 +12,94 @@ #include "libterminput.h" +#define TEST(EXPR)\ + do {\ + if (EXPR)\ + break;\ + fprintf(stderr, "Failure at line %i, with errno = %i (%s): %s\n",\ + __LINE__, errno, strerror(errno), #EXPR);\ + exit(1);\ + } while (0) + + +static volatile sig_atomic_t interrupted = 0; + +static struct libterminput_state ctx; + +static char *marshalled = NULL; +static size_t nmarshalled = 0; +static size_t nunmarshalled = 0; +static size_t marshalled_size = 0; + + +static int +store(struct libterminput_marshaller *this, const void *data, size_t size) +{ + (void) this; + if (size > marshalled_size - nmarshalled) { + TEST(size < SIZE_MAX - nmarshalled); + marshalled_size = nmarshalled + size; + TEST((marshalled = realloc(marshalled, marshalled_size))); + } + memcpy(&marshalled[nmarshalled], data, size); + nmarshalled += size; + return 0; +} + + +static int +load(struct libterminput_unmarshaller *this, void *data, size_t size) +{ + (void) this; + TEST(nunmarshalled <= nmarshalled); + TEST(size <= nmarshalled - nunmarshalled); + memcpy(data, &marshalled[nunmarshalled], size); + nunmarshalled += size; + return 0; +} + + +static struct libterminput_marshaller marshaller = {.store = &store}; +static struct libterminput_unmarshaller unmarshaller = {.load = &load}; + + +static void +check_ctx_marshal(void) +{ + struct libterminput_state old_ctx; + memcpy(&old_ctx, &ctx, sizeof(ctx)); + TEST(!libterminput_marshal_state(&marshaller, &ctx)); + memset(&ctx, 255, sizeof(ctx)); + TEST(!libterminput_unmarshal_state(&unmarshaller, &ctx)); + TEST(!memcmp(&old_ctx, &ctx, sizeof(ctx))); +} + + +static void +sigint_handler(int signo) +{ + (void) signo; + interrupted = 1; +} + + int main(void) { - struct libterminput_state ctx; union libterminput_input input; struct termios stty, saved_stty; - int r; + int r, print_state, flags; + struct sigaction sa; memset(&ctx, 0, sizeof(ctx)); + if (libterminput_init(&ctx, STDIN_FILENO)) { + perror("libterminput_init STDIN_FILENO"); + return 1; + } + + memset(&sa, 0, sizeof(sa)); /* importantly, SA_RESTART is cleared from sa.sa_flags */ + sa.sa_handler = &sigint_handler; + sigaction(SIGINT, &sa, NULL); if (getenv("TEST_LIBTERMINPUT_DECSET_1005")) { fprintf(stderr, "LIBTERMINPUT_DECSET_1005 set\n"); @@ -47,6 +130,8 @@ main(void) libterminput_set_flags(&ctx, LIBTERMINPUT_AWAITING_CURSOR_POSITION); } + print_state = !!getenv("TEST_LIBTERMINPUT_PRINT_STATE"); + if (tcgetattr(STDERR_FILENO, &stty)) { perror("tcgetattr STDERR_FILENO"); return 1; @@ -58,7 +143,20 @@ main(void) return 1; } + flags = fcntl(STDIN_FILENO, F_GETFL); + if (flags < 0) { + perror("fcntl STDIN_FILENO F_GETFL"); + return 1; + } else if (!(flags & O_NONBLOCK)) { + if (fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK) < 0) { + perror("fcntl STDIN_FILENO F_SETFL <old>|O_NONBLOCK"); + return 1; + } + } + +again: while ((r = libterminput_read(STDIN_FILENO, &input, &ctx)) > 0) { + check_ctx_marshal(); if (input.type == LIBTERMINPUT_NONE) { printf("none\n"); } else if (input.type == LIBTERMINPUT_KEYPRESS) { @@ -184,11 +282,35 @@ main(void) } else { printf("other\n"); } + if (print_state) { + printf("(state):\n" + "\tinited=%i, mods=%#x, flags=%#x, bracketed_paste=%i, mouse_tracking=%i, meta=%i,\n" + "\tn=%i, stored_head=%zu, stored_tail=%zu, paused=%i, npartial=%i, partial=\"%.*s\",\n" + "\tkey=\"%s\", stored=\"%.*s\"\n", + (int)ctx.inited, (unsigned)ctx.mods, (unsigned)ctx.flags, (int)ctx.bracketed_paste, + (int)ctx.mouse_tracking, (int)ctx.meta, (int)ctx.n, ctx.stored_head, ctx.stored_tail, + (int)ctx.paused, (int)ctx.npartial, (int)ctx.npartial, ctx.partial, ctx.key, + (int)(ctx.stored_tail - ctx.stored_head), &ctx.stored[ctx.stored_head]); + } } + check_ctx_marshal(); - if (r < 0) + if (r < 0 && !interrupted) { + if (errno == EAGAIN) { + fd_set fdset; + FD_ZERO(&fdset); + FD_SET(STDIN_FILENO, &fdset); + select(1, &fdset, NULL, NULL, NULL); + goto again; + } perror("libterminput_read STDIN_FILENO"); + } + if (!(flags & O_NONBLOCK)) + fcntl(STDIN_FILENO, F_SETFL, flags); tcsetattr(STDERR_FILENO, TCSAFLUSH, &saved_stty); - return -r; + + libterminput_destroy(&ctx); + free(marshalled); + return -r && !interrupted; } |