aboutsummaryrefslogtreecommitdiffstats
path: root/interactive-test.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--interactive-test.c130
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;
}