diff options
Diffstat (limited to '')
-rw-r--r-- | view.c | 66 |
1 files changed, 48 insertions, 18 deletions
diff --git a/view.c b/view.c index d7ca456..732aeca 100644 --- a/view.c +++ b/view.c @@ -18,8 +18,10 @@ #include <fcntl.h> #include <poll.h> #include <signal.h> +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> +#include <sys/event.h> #include <sys/ioctl.h> #include <sysexits.h> #include <termios.h> @@ -47,6 +49,13 @@ static void sigwinch() { } } +static struct winsize remoteWindow; +static void readRemoteWindow(int remote) { + ssize_t size = read(remote, &remoteWindow, sizeof(remoteWindow)); + if (size < 0) err(EX_IOERR, "read(%d)", remote); + if ((size_t)size < sizeof(remoteWindow)) errx(EX_IOERR, "short read(%d)", remote); +} + int main(int argc, char *argv[]) { int error; @@ -65,27 +74,35 @@ int main(int argc, char *argv[]) { error = tcsetattr(local, TCSADRAIN, &term); if (error) err(EX_IOERR, "tcsetattr"); - int remote = open(path, O_RDONLY); - if (remote < 0) err(EX_NOINPUT, "%s", path); - - struct winsize remoteWindow; - ssize_t size = read(remote, &remoteWindow, sizeof(remoteWindow)); - if (size < 0) err(EX_IOERR, "%s", path); - if ((size_t)size < sizeof(remoteWindow)) errx(EX_IOERR, "%s: short read", path); - error = pipe((int *)&winch); if (error) err(EX_OSERR, "pipe"); signal(SIGWINCH, sigwinch); sigwinch(); - char buf[4096]; - struct pollfd fds[3] = { - { .fd = winch.read, .events = POLLIN }, - { .fd = input, .events = POLLIN }, - { .fd = remote, .events = POLLIN }, + int remote = open(path, O_RDONLY); + if (remote < 0) err(EX_NOINPUT, "%s", path); + readRemoteWindow(remote); + + int kq = kqueue(); + if (kq < 0) err(EX_OSERR, "kqueue"); + + struct kevent events[3] = { + { .ident = winch.read, .filter = EVFILT_READ, .flags = EV_ADD }, + { .ident = input, .filter = EVFILT_READ, .flags = EV_ADD }, + { .ident = remote, .filter = EVFILT_READ, .flags = EV_ADD }, }; - while (0 < poll(fds, 3, -1)) { - if (fds[0].revents) { + int nevents = kevent(kq, events, 3, NULL, 0, NULL); + if (nevents < 0) err(EX_OSERR, "kevent"); + + char buf[4096]; + bool truncated = false; + for (;;) { + struct kevent event; + int nevents = kevent(kq, NULL, 0, &event, 1, NULL); + if (nevents < 0) err(EX_OSERR, "kevent"); + if (!nevents) continue; + + if (event.ident == (uintptr_t)winch.read) { for (;;) { struct winsize localWindow; ssize_t size = read(winch.read, &localWindow, sizeof(localWindow)); @@ -107,13 +124,27 @@ int main(int argc, char *argv[]) { } } - if (fds[1].revents) { + if (event.ident == (uintptr_t)input) { ssize_t size = read(input, buf, sizeof(buf)); if (size < 0) err(EX_IOERR, "read(%d)", input); if (size == 1 && buf[0] == 'q') return EX_OK; } - if (fds[2].revents) { + if (event.ident == (uintptr_t)remote) { + if (event.data < 0) { + off_t offset = lseek(remote, 0, SEEK_SET); + if (offset < 0) err(EX_IOERR, "lseek(%d)", remote); + truncated = true; + continue; + } + + if (truncated) { + readRemoteWindow(remote); + sigwinch(); + truncated = false; + continue; + } + ssize_t readSize = read(remote, buf, sizeof(buf)); if (readSize < 0) err(EX_IOERR, "read(%d)", remote); @@ -122,5 +153,4 @@ int main(int argc, char *argv[]) { if (writeSize < readSize) errx(EX_IOERR, "short write(%d)", local); } } - err(EX_IOERR, "poll"); } |