summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--view.c66
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");
 }