summary refs log tree commit diff
path: root/home/.bin
diff options
context:
space:
mode:
Diffstat (limited to 'home/.bin')
-rwxr-xr-xhome/.bin/bri.c77
-rwxr-xr-xhome/.bin/dtch.c254
-rwxr-xr-xhome/.bin/hnel.c115
-rwxr-xr-xhome/.bin/jrp.c273
-rwxr-xr-xhome/.bin/pbd.c136
-rwxr-xr-xhome/.bin/sup7
-rwxr-xr-xhome/.bin/tup7
-rwxr-xr-xhome/.bin/up12
-rwxr-xr-xhome/.bin/wake.c41
-rwxr-xr-xhome/.bin/watch.c100
-rwxr-xr-xhome/.bin/xx.c117
11 files changed, 1139 insertions, 0 deletions
diff --git a/home/.bin/bri.c b/home/.bin/bri.c
new file mode 100755
index 00000000..d085814b
--- /dev/null
+++ b/home/.bin/bri.c
@@ -0,0 +1,77 @@
+#if 0
+set -e
+bin=$(dirname $0)
+cc -Wall -Wextra -pedantic $@ -o $bin/bri $0
+sudo chown root:root $bin/bri
+sudo chmod u+s $bin/bri
+exit
+#endif
+
+// Backlight brightness control.
+
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+static const char *CLASS = "/sys/class/backlight";
+
+int main(int argc, char *argv[]) {
+    int error;
+
+    if (argc < 2) errx(EX_USAGE, "usage: bri N | +... | -...");
+
+    error = chdir(CLASS);
+    if (error) err(EX_IOERR, "%s", CLASS);
+
+    DIR *dir = opendir(".");
+    if (!dir) err(EX_IOERR, "%s", CLASS);
+
+    struct dirent *entry;
+    while (NULL != (errno = 0, entry = readdir(dir))) {
+        if (entry->d_name[0] == '.') continue;
+
+        error = chdir(entry->d_name);
+        if (error) err(EX_IOERR, "%s", entry->d_name);
+        break;
+    }
+    if (!entry) {
+        if (errno) err(EX_IOERR, "%s", CLASS);
+        errx(EX_CONFIG, "empty %s", CLASS);
+    }
+
+    char *value = argv[1];
+
+    if (value[0] == '+' || value[0] == '-') {
+        FILE *actual = fopen("actual_brightness", "r");
+        if (!actual) err(EX_IOERR, "actual_brightness");
+
+        unsigned int brightness;
+        int match = fscanf(actual, "%u", &brightness);
+        if (match == EOF) err(EX_IOERR, "actual_brightness");
+        if (match < 1) err(EX_DATAERR, "actual_brightness");
+
+        size_t count = strnlen(value, 15);
+        if (value[0] == '+') {
+            brightness += 16 * count;
+        } else {
+            brightness -= 16 * count;
+        }
+
+        char buf[15];
+        snprintf(buf, sizeof(buf), "%u", brightness);
+
+        value = buf;
+    }
+
+    FILE *brightness = fopen("brightness", "w");
+    if (!brightness) err(EX_IOERR, "brightness");
+
+    int count = fprintf(brightness, "%s", value);
+    if (count < 0) err(EX_IOERR, "brightness");
+
+    return EX_OK;
+}
diff --git a/home/.bin/dtch.c b/home/.bin/dtch.c
new file mode 100755
index 00000000..a37eeeeb
--- /dev/null
+++ b/home/.bin/dtch.c
@@ -0,0 +1,254 @@
+#if 0
+set -e
+bin=$(dirname $0)
+cc -Wall -Wextra -pedantic $@ -lutil -o $bin/dtch $0
+ln -f $bin/dtch $bin/atch
+exit
+#endif
+
+// Session attach and detach.
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <sysexits.h>
+#include <termios.h>
+#include <unistd.h>
+
+#if defined __FreeBSD__
+#include <libutil.h>
+#elif defined __linux__
+#include <pty.h>
+#else
+#include <util.h>
+#endif
+
+static struct passwd *getUser(void) {
+    uid_t uid = getuid();
+    struct passwd *user = getpwuid(uid);
+    if (!user) err(EX_OSFILE, "/etc/passwd");
+    return user;
+}
+
+static struct sockaddr_un sockAddr(const char *home, const char *name) {
+    struct sockaddr_un addr = { .sun_family = AF_LOCAL };
+    snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/.dtch/%s", home, name);
+    return addr;
+}
+
+static ssize_t writeAll(int fd, const char *buf, size_t len) {
+    ssize_t writeLen;
+    while (0 < (writeLen = write(fd, buf, len))) {
+        buf += writeLen;
+        len -= writeLen;
+    }
+    return writeLen;
+}
+
+char z;
+struct iovec iov = { .iov_base = &z, .iov_len = 1 };
+
+static ssize_t sendFd(int sock, int fd) {
+    size_t len = CMSG_LEN(sizeof(int));
+    char buf[len];
+    struct msghdr msg = {
+        .msg_iov = &iov,
+        .msg_iovlen = 1,
+        .msg_control = buf,
+        .msg_controllen = len,
+    };
+
+    struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
+    cmsg->cmsg_len = len;
+    cmsg->cmsg_level = SOL_SOCKET;
+    cmsg->cmsg_type = SCM_RIGHTS;
+    *(int *)CMSG_DATA(cmsg) = fd;
+
+    return sendmsg(sock, &msg, 0);
+}
+
+static int recvFd(int sock) {
+    size_t len = CMSG_LEN(sizeof(int));
+    char buf[len];
+    struct msghdr msg = {
+        .msg_iov = &iov,
+        .msg_iovlen = 1,
+        .msg_control = buf,
+        .msg_controllen = len,
+    };
+
+    ssize_t n = recvmsg(sock, &msg, 0);
+    if (n < 0) return -1;
+
+    struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
+    if (!cmsg) { errno = ENOMSG; return -1; }
+    if (cmsg->cmsg_type != SCM_RIGHTS) { errno = EBADMSG; return -1; }
+
+    return *(int *)CMSG_DATA(cmsg);
+}
+
+static struct sockaddr_un addr;
+
+static void unlinkAddr(void) {
+    unlink(addr.sun_path);
+}
+
+static int dtch(int argc, char *argv[]) {
+    int error;
+
+    struct passwd *user = getUser();
+
+    char *name = user->pw_name;
+    char *cmd = user->pw_shell;
+    if (argc > 2) {
+        name = argv[1];
+        cmd = argv[2];
+        argv += 2;
+    } else if (argc > 1) {
+        name = argv[1];
+        argv++;
+    }
+
+    int home = open(user->pw_dir, 0);
+    if (home < 0) err(EX_IOERR, "%s", user->pw_dir);
+    error = mkdirat(home, ".dtch", S_IRWXU);
+    if (error && errno != EEXIST) err(EX_IOERR, "%s/.dtch", user->pw_dir);
+    error = close(home);
+    if (error) err(EX_IOERR, "%s", user->pw_dir);
+
+    int server = socket(PF_LOCAL, SOCK_STREAM, 0);
+    if (server < 0) err(EX_OSERR, "socket");
+
+    addr = sockAddr(user->pw_dir, name);
+    error = bind(server, (struct sockaddr *)&addr, sizeof(addr));
+    if (error) err(EX_IOERR, "%s", addr.sun_path);
+    atexit(unlinkAddr);
+
+    error = chmod(addr.sun_path, 0600);
+    if (error) err(EX_IOERR, "%s", addr.sun_path);
+
+    int master;
+    pid_t pid = forkpty(&master, NULL, NULL, NULL);
+    if (pid < 0) err(EX_OSERR, "forkpty");
+
+    if (!pid) {
+        error = close(server);
+        if (error) warn("close(%d)", server);
+        execvp(cmd, argv);
+        err(EX_OSERR, "%s", cmd);
+    }
+
+    error = listen(server, 0);
+    if (error) err(EX_OSERR, "listen");
+
+    for (;;) {
+        int client = accept(server, NULL, NULL);
+        if (client < 0) err(EX_IOERR, "accept(%d)", server);
+
+        ssize_t len = sendFd(client, master);
+        if (len < 0) warn("sendmsg(%d)", client);
+
+        len = recv(client, &z, sizeof(z), 0);
+        if (len < 0) warn("recv(%d)", client);
+
+        error = close(client);
+        if (error) warn("close(%d)", client);
+
+        pid_t dead = waitpid(pid, NULL, WNOHANG);
+        if (dead < 0) warn("waitpid(%d)", pid);
+        if (dead) exit(EX_OK);
+    }
+}
+
+static struct termios saveTerm;
+
+static void restoreTerm(void) {
+    tcsetattr(STDERR_FILENO, TCSADRAIN, &saveTerm);
+    printf(
+        "\x1b[?1049l" // rmcup
+        "\x1b\x63\x1b[!p\x1b[?3;4l\x1b[4l\x1b>" // reset
+    );
+}
+
+static int atch(int argc, char *argv[]) {
+    int error;
+
+    struct passwd *user = getUser();
+    char *name = (argc > 1) ? argv[1] : user->pw_name;
+
+    int client = socket(PF_LOCAL, SOCK_STREAM, 0);
+    if (client < 0) err(EX_OSERR, "socket");
+
+    struct sockaddr_un addr = sockAddr(user->pw_dir, name);
+    error = connect(client, (struct sockaddr *)&addr, sizeof(addr));
+    if (error) err(EX_IOERR, "%s", addr.sun_path);
+
+    int master = recvFd(client);
+    if (master < 0) err(EX_IOERR, "recvmsg(%d)", client);
+
+    struct winsize window;
+    error = ioctl(STDERR_FILENO, TIOCGWINSZ, &window);
+    if (error) err(EX_IOERR, "ioctl(%d, TIOCGWINSZ)", STDERR_FILENO);
+
+    error = ioctl(master, TIOCSWINSZ, &window);
+    if (error) err(EX_IOERR, "ioctl(%d, TIOCSWINSZ)", master);
+
+    error = tcgetattr(STDERR_FILENO, &saveTerm);
+    if (error) err(EX_IOERR, "tcgetattr(%d)", STDERR_FILENO);
+    atexit(restoreTerm);
+
+    struct termios raw;
+    cfmakeraw(&raw);
+    error = tcsetattr(STDERR_FILENO, TCSADRAIN, &raw);
+    if (error) err(EX_IOERR, "tcsetattr(%d)", STDERR_FILENO);
+
+    char ctrlL = CTRL('L');
+    ssize_t len = write(master, &ctrlL, 1);
+    if (len < 0) err(EX_IOERR, "write(%d)", master);
+
+    struct pollfd fds[2] = {
+        { .fd = STDIN_FILENO, .events = POLLIN },
+        { .fd = master, .events = POLLIN },
+    };
+
+    while (0 < poll(fds, 2, -1)) {
+        char buf[4096];
+        ssize_t len;
+
+        if (fds[0].revents) {
+            len = read(STDIN_FILENO, buf, sizeof(buf));
+            if (len < 0) err(EX_IOERR, "read(%d)", STDIN_FILENO);
+
+            if (len && buf[0] == CTRL('Q')) exit(EX_OK);
+
+            len = writeAll(master, buf, len);
+            if (len < 0) err(EX_IOERR, "write(%d)", master);
+        }
+
+        if (fds[1].revents) {
+            len = read(master, buf, sizeof(buf));
+            if (len < 0) err(EX_IOERR, "read(%d)", master);
+            len = writeAll(STDOUT_FILENO, buf, len);
+            if (len < 0) err(EX_IOERR, "write(%d)", STDOUT_FILENO);
+        }
+    }
+    err(EX_IOERR, "poll([%d,%d])", STDIN_FILENO, master);
+}
+
+int main(int argc, char *argv[]) {
+    switch (argv[0][0]) {
+        case 'd': return dtch(argc, argv);
+        case 'a': return atch(argc, argv);
+    }
+    return EX_USAGE;
+}
diff --git a/home/.bin/hnel.c b/home/.bin/hnel.c
new file mode 100755
index 00000000..3aec85b3
--- /dev/null
+++ b/home/.bin/hnel.c
@@ -0,0 +1,115 @@
+#if 0
+exec cc -Wall -Wextra -pedantic $@ -lutil -o $(dirname $0)/hnel $0
+#endif
+
+// PTY wrapper for preserving HJKL in Tarmak layouts.
+
+#include <err.h>
+#include <poll.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <sysexits.h>
+#include <termios.h>
+#include <unistd.h>
+
+#if defined __FreeBSD__
+#include <libutil.h>
+#elif defined __linux__
+#include <pty.h>
+#else
+#include <util.h>
+#endif
+
+static char table[256] = {
+    ['n'] = 'j', ['N'] = 'J', [CTRL('N')] = CTRL('J'),
+    ['e'] = 'k', ['E'] = 'K', [CTRL('E')] = CTRL('K'),
+    ['j'] = 'e', ['J'] = 'E', [CTRL('J')] = CTRL('E'),
+    ['k'] = 'n', ['K'] = 'N', [CTRL('K')] = CTRL('N'),
+};
+
+static ssize_t writeAll(int fd, const char *buf, size_t len) {
+    ssize_t writeLen;
+    while (0 < (writeLen = write(fd, buf, len))) {
+        buf += writeLen;
+        len -= writeLen;
+    }
+    return writeLen;
+}
+
+static struct termios saveTerm;
+
+static void restoreTerm(void) {
+    tcsetattr(STDERR_FILENO, TCSADRAIN, &saveTerm);
+}
+
+int main(int argc, char *argv[]) {
+    int error;
+
+    if (argc < 2) return EX_USAGE;
+
+    error = tcgetattr(STDERR_FILENO, &saveTerm);
+    if (error) err(EX_IOERR, "tcgetattr");
+    atexit(restoreTerm);
+
+    struct termios raw;
+    cfmakeraw(&raw);
+    error = tcsetattr(STDERR_FILENO, TCSADRAIN, &raw);
+    if (error) err(EX_IOERR, "tcsetattr");
+
+    struct winsize window;
+    error = ioctl(STDERR_FILENO, TIOCGWINSZ, &window);
+    if (error) err(EX_IOERR, "ioctl(%d, TIOCGWINSZ)", STDERR_FILENO);
+
+    int master;
+    pid_t pid = forkpty(&master, NULL, NULL, &window);
+    if (pid < 0) err(EX_OSERR, "forkpty");
+
+    if (!pid) {
+        execvp(argv[1], argv + 1);
+        err(EX_OSERR, "%s", argv[1]);
+    }
+
+    bool enable = true;
+
+    struct pollfd fds[2] = {
+        { .fd = STDIN_FILENO, .events = POLLIN },
+        { .fd = master, .events = POLLIN },
+    };
+    while (0 < poll(fds, 2, -1)) {
+        char buf[4096];
+        ssize_t len;
+
+        if (fds[0].revents) {
+            len = read(STDIN_FILENO, buf, sizeof(buf));
+            if (len < 0) err(EX_IOERR, "read(%d)", STDIN_FILENO);
+
+            if (len == 1) {
+                if (buf[0] == CTRL('S')) {
+                    enable = !enable;
+                    continue;
+                }
+
+                unsigned char c = buf[0];
+                if (enable && table[c]) buf[0] = table[c];
+            }
+
+            len = writeAll(master, buf, len);
+            if (len < 0) err(EX_IOERR, "write(%d)", master);
+        }
+
+        if (fds[1].revents) {
+            len = read(master, buf, sizeof(buf));
+            if (len < 0) err(EX_IOERR, "read(%d)", master);
+            len = writeAll(STDOUT_FILENO, buf, len);
+            if (len < 0) err(EX_IOERR, "write(%d)", STDOUT_FILENO);
+        }
+
+        int status;
+        pid_t dead = waitpid(pid, &status, WNOHANG);
+        if (dead < 0) err(EX_OSERR, "waitpid(%d)", pid);
+        if (dead) return WIFEXITED(status) ? WEXITSTATUS(status) : EX_SOFTWARE;
+    }
+    err(EX_IOERR, "poll");
+}
diff --git a/home/.bin/jrp.c b/home/.bin/jrp.c
new file mode 100755
index 00000000..9317ac8e
--- /dev/null
+++ b/home/.bin/jrp.c
@@ -0,0 +1,273 @@
+#if 0
+exec cc -Wall -Wextra -pedantic $@ $0 -ledit -o $(dirname $0)/jrp
+#endif
+
+// JIT RPN calculator.
+
+#include <err.h>
+#include <histedit.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+typedef unsigned long qop;
+typedef unsigned int dop;
+
+typedef long qvalue;
+typedef int dvalue;
+typedef unsigned long uvalue;
+
+typedef qvalue *(*jitFn)(qvalue *);
+typedef void (*rtFn)(qvalue);
+
+static char *formatBin(qvalue val) {
+    static char buf[sizeof(qvalue) * 8 + 1];
+    uvalue uval = val;
+    size_t i = sizeof(buf);
+    do {
+        buf[--i] = '0' + (uval & 1);
+    } while (uval >>= 1);
+    return &buf[i];
+}
+
+static void rtPrintAscii(qvalue val) {
+    printf("%c\n", (char)val);
+}
+static void rtPrintBin(qvalue val) {
+    printf("%s\n", formatBin(val));
+}
+static void rtPrintOct(qvalue val) {
+    printf("%lo\n", val);
+}
+static void rtPrintDec(qvalue val) {
+    printf("%ld\n", val);
+}
+static void rtPrintHex(qvalue val) {
+    printf("%lx\n", val);
+}
+
+static const dop DOP_NOP  = 0x90666666; // nop
+static const dop DOP_PUSH = 0xc7c74857; // push rdi; mov rdi, strict dword 0
+static const dop DOP_DROP = 0x9066665f; // pop rdi
+static const dop DOP_DUP  = 0x90666657; // push rdi
+static const dop DOP_SWAP = 0x243c8748; // xchg rdi, [rsp]
+static const dop DOP_NEG  = 0x90dff748; // neg rdi
+static const dop DOP_ADD  = 0xc7014858; // pop rax; add rdi, rax
+static const dop DOP_QUO  = 0x90c78948; // mov rdi, rax
+static const dop DOP_REM  = 0x90d78948; // mov rdi, rdx
+static const dop DOP_NOT  = 0x90d7f748; // not rdi
+static const dop DOP_AND  = 0xc7214858; // pop rax; and rdi, rax
+static const dop DOP_OR   = 0xc7094858; // pop rax; or rdi, rax
+static const dop DOP_XOR  = 0xc7314858; // pop rax; xor rdi, rax
+
+static const qop QOP_PROL = 0x5ffc8948e5894855; // push rbp; mov rbp, rsp; mov rsp, rdi; pop rdi
+static const qop QOP_EPIL = 0x5dec8948e0894857; // push rdi; mov rax, rsp; mov rsp, rbp; pop rbp
+static const qop QOP_RET  = 0x90666666906666c3; // ret
+static const qop QOP_CRT  = 0xb848906690e58748; // xchg rsp, rbp; mov rax, strict qword 0
+static const qop QOP_CALL = 0x90665fe58748d0ff; // call rax; xchg rsp, rbp; pop rdi
+static const qop QOP_PUSH = 0xbf48906690666657; // push rdi; mov rdi, strict qword 0
+static const qop QOP_SUB  = 0x9066665f243c2948; // sub [rsp], rdi; pop rdi
+static const qop QOP_MUL  = 0x906666f8af0f4858; // pop rax; imul rdi, rax
+static const qop QOP_DIV  = 0x9066fff748994858; // pop rax; cqo; idiv rdi
+static const qop QOP_SHL  = 0x5f2424d348f98948; // mov rcx, rdi; shl qword [rsp], cl; pop rdi
+static const qop QOP_SHR  = 0x5f242cd348f98948; // mov rcx, rdi; shr qword [rsp], cl; pop rdi
+
+static int radix = 10;
+
+static struct {
+    qop *base;
+    qop *ptr;
+    dop dop;
+} code;
+
+static struct {
+    qvalue *base;
+    qvalue *limit;
+    qvalue *ptr;
+} stack;
+
+static void jitDop(dop op) {
+    if (code.dop) {
+        *code.ptr++ = (qop)op << 32 | code.dop;
+        code.dop = 0;
+    } else {
+        code.dop = op;
+    }
+}
+
+static void jitQop(qop op) {
+    if (code.dop) jitDop(DOP_NOP);
+    *code.ptr++ = op;
+}
+
+static void jitPush(qvalue imm) {
+    if ((dvalue)imm == imm) {
+        jitQop(DOP_PUSH | (qop)imm << 32);
+    } else {
+        jitQop(QOP_PUSH);
+        jitQop((qop)imm);
+    }
+}
+
+static void jitCall(rtFn fn) {
+    jitQop(QOP_CRT);
+    jitQop((qop)fn);
+    jitQop(QOP_CALL);
+}
+
+static void jitBegin(void) {
+    code.ptr = code.base;
+    jitQop(QOP_PROL);
+}
+
+static void jitEnd(void) {
+    jitQop(QOP_EPIL);
+    jitQop(QOP_RET);
+}
+
+static void jitInit(void) {
+    code.base = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
+    if (code.base == MAP_FAILED) err(EX_OSERR, "mmap");
+}
+
+static void stackInit(void) {
+    stack.base = mmap(0, 2 * getpagesize(), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
+    if (stack.base == MAP_FAILED) err(EX_OSERR, "mmap");
+    stack.limit = stack.base + getpagesize() / sizeof(qvalue);
+    stack.ptr = stack.limit;
+}
+
+static void jitExec(void) {
+    int error;
+    error = mprotect(code.base, getpagesize(), PROT_READ | PROT_EXEC);
+    if (error) err(EX_OSERR, "mprotect");
+    stack.ptr = ((jitFn)code.base)(stack.ptr);
+    if (stack.ptr > stack.limit) stack.ptr = stack.limit;
+    error = mprotect(code.base, getpagesize(), PROT_READ | PROT_WRITE);
+    if (error) err(EX_OSERR, "mprotect");
+}
+
+static void jitSrc(const char *src) {
+    bool quote = false;
+    while (*src) {
+        if (quote) {
+            jitPush(*src++);
+            quote = false;
+            continue;
+        }
+
+        switch (*src) {
+            case ' ': break;
+            case 39: quote = true; break;
+            case 'B': radix = 2;   break;
+            case 'O': radix = 8;   break;
+            case 'D': radix = 10;  break;
+            case 'X': radix = 16;  break;
+            case ';': jitDop(DOP_DROP); break;
+            case ':': jitDop(DOP_DUP);  break;
+            case 92:  jitDop(DOP_SWAP); break;
+            case '_': jitDop(DOP_NEG);  break;
+            case '+': jitDop(DOP_ADD);  break;
+            case '-': jitQop(QOP_SUB);  break;
+            case '*': jitQop(QOP_MUL);  break;
+            case '/': jitQop(QOP_DIV); jitDop(DOP_QUO); break;
+            case '%': jitQop(QOP_DIV); jitDop(DOP_REM); break;
+            case '~': jitDop(DOP_NOT);  break;
+            case '&': jitDop(DOP_AND);  break;
+            case '|': jitDop(DOP_OR);   break;
+            case '^': jitDop(DOP_XOR);  break;
+            case '<': jitQop(QOP_SHL);  break;
+            case '>': jitQop(QOP_SHR);  break;
+            case ',': jitCall(rtPrintAscii); break;
+            case '.': switch (radix) {
+                case 2:  jitCall(rtPrintBin); break;
+                case 8:  jitCall(rtPrintOct); break;
+                case 10: jitCall(rtPrintDec); break;
+                case 16: jitCall(rtPrintHex); break;
+            } break;
+
+            default: {
+                char *rest;
+                qvalue val = strtol(src, &rest, radix);
+                if (rest != src) {
+                    src = rest;
+                    jitPush(val);
+                    continue;
+                }
+            }
+        }
+
+        src++;
+    }
+}
+
+static void jitDump(const char *path, FILE *file) {
+    size_t nitems = code.ptr - code.base;
+    size_t written = fwrite(code.base, sizeof(qop), nitems, file);
+    if (written < nitems) err(EX_IOERR, "%s", path);
+}
+
+static char *prompt(EditLine *el __attribute((unused))) {
+    static char buf[4096];
+    char *bufPtr = buf;
+    for (qvalue *stackPtr = stack.limit - 1; stackPtr >= stack.ptr; --stackPtr) {
+        size_t bufLen = sizeof(buf) - (bufPtr - buf) - 2;
+        switch (radix) {
+            case 2:  bufPtr += snprintf(bufPtr, bufLen, " %s", formatBin(*stackPtr)); break;
+            case 8:  bufPtr += snprintf(bufPtr, bufLen, " %lo", *stackPtr); break;
+            case 10: bufPtr += snprintf(bufPtr, bufLen, " %ld", *stackPtr); break;
+            case 16: bufPtr += snprintf(bufPtr, bufLen, " %lx", *stackPtr); break;
+        }
+    }
+    buf[0] = '[';
+    if (bufPtr == buf) bufPtr++;
+    *bufPtr++ = ']';
+    *bufPtr++ = ' ';
+    *bufPtr = 0;
+    return buf;
+}
+
+int main(int argc, char *argv[]) {
+    FILE *file = NULL;
+    char *path = getenv("JRP_DUMP");
+    if (path) {
+        file = fopen(path, "w");
+        if (!file) err(EX_CANTCREAT, "%s", path);
+    }
+
+    jitInit();
+    stackInit();
+
+    if (argc > 1) {
+        jitBegin();
+        for (int i = 1; i < argc; ++i)
+            jitSrc(argv[i]);
+        jitEnd();
+        if (file) jitDump(path, file);
+        jitExec();
+        return EX_OK;
+    }
+
+    EditLine *el = el_init(argv[0], stdin, stdout, stderr);
+    el_set(el, EL_PROMPT, prompt);
+    el_set(el, EL_SIGNAL, true);
+
+    for (;;) {
+        int count;
+        const char *line = el_gets(el, &count);
+        if (count < 0) err(EX_IOERR, "el_gets");
+        if (!line) break;
+
+        jitBegin();
+        jitSrc(line);
+        jitEnd();
+        if (file) jitDump(path, file);
+        jitExec();
+    }
+
+    el_end(el);
+    return EX_OK;
+}
diff --git a/home/.bin/pbd.c b/home/.bin/pbd.c
new file mode 100755
index 00000000..01e5c07d
--- /dev/null
+++ b/home/.bin/pbd.c
@@ -0,0 +1,136 @@
+#if 0
+set -e
+bin=$(dirname $0)
+cc -Wall -Wextra -pedantic $@ -o $bin/pbd $0
+ln -f $bin/pbd $bin/pbcopy
+ln -f $bin/pbd $bin/pbpaste
+exit
+#endif
+
+// TCP server which pipes between macOS pbcopy and pbpaste, and pbcopy and
+// pbpaste implementations which connect to it.
+
+#include <arpa/inet.h>
+#include <err.h>
+#include <netinet/in.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+static void spawn(const char *cmd, int childFd, int parentFd) {
+    pid_t pid = fork();
+    if (pid < 0) err(EX_OSERR, "fork");
+
+    if (pid) {
+        int status;
+        pid_t wait = waitpid(pid, &status, 0);
+        if (wait < 0) err(EX_OSERR, "waitpid");
+
+        if (status) {
+            warnx("child %s status %d", cmd, status);
+        }
+    } else {
+        int fd = dup2(parentFd, childFd);
+        if (fd < 0) err(EX_OSERR, "dup2");
+
+        int error = execlp(cmd, cmd, NULL);
+        if (error) err(EX_OSERR, "execlp");
+    }
+}
+
+static int pbd(void) {
+    int error;
+
+    int server = socket(PF_INET, SOCK_STREAM, 0);
+    if (server < 0) err(EX_OSERR, "socket");
+
+    struct sockaddr_in addr = {
+        .sin_family = AF_INET,
+        .sin_port = htons(7062),
+        .sin_addr = { .s_addr = htonl(0x7f000001) },
+    };
+
+    error = bind(server, (struct sockaddr *)&addr, sizeof(addr));
+    if (error) err(EX_OSERR, "bind");
+
+    error = listen(server, 1);
+    if (error) err(EX_OSERR, "listen");
+
+    for (;;) {
+        int client = accept(server, NULL, NULL);
+        if (client < 0) err(EX_OSERR, "accept");
+
+        spawn("pbpaste", STDOUT_FILENO, client);
+
+        uint8_t p;
+        ssize_t peek = recv(client, &p, 1, MSG_PEEK);
+        if (peek < 0) err(EX_IOERR, "recv");
+
+        if (peek) {
+            spawn("pbcopy", STDIN_FILENO, client);
+        }
+
+        error = close(client);
+        if (error) err(EX_IOERR, "close");
+    }
+}
+
+static int pbdClient(void) {
+    int client = socket(PF_INET, SOCK_STREAM, 0);
+    if (client < 0) err(EX_OSERR, "socket");
+
+    struct sockaddr_in addr = {
+        .sin_family = AF_INET,
+        .sin_port = htons(7062),
+        .sin_addr = { .s_addr = htonl(0x7f000001) },
+    };
+
+    int error = connect(client, (struct sockaddr *)&addr, sizeof(addr));
+    if (error) err(EX_OSERR, "connect");
+
+    return client;
+}
+
+static void copy(int fdIn, int fdOut) {
+    char readBuf[4096];
+    ssize_t readLen;
+    while (0 < (readLen = read(fdIn, readBuf, sizeof(readBuf)))) {
+        char *writeBuf = readBuf;
+        ssize_t writeLen;
+        while (0 < (writeLen = write(fdOut, writeBuf, readLen))) {
+            writeBuf += writeLen;
+            readLen -= writeLen;
+        }
+        if (writeLen < 0) err(EX_IOERR, "write");
+    }
+    if (readLen < 0) err(EX_IOERR, "read");
+}
+
+static int pbcopy(void) {
+    int client = pbdClient();
+    copy(STDIN_FILENO, client);
+    return EX_OK;
+}
+
+static int pbpaste(void) {
+    int client = pbdClient();
+    int error = shutdown(client, SHUT_WR);
+    if (error) err(EX_OSERR, "shutdown");
+    copy(client, STDOUT_FILENO);
+    return EX_OK;
+}
+
+int main(int argc __attribute((unused)), char *argv[]) {
+    if (!argv[0][0] || !argv[0][1]) return EX_USAGE;
+    switch (argv[0][2]) {
+        case 'd': return pbd();
+        case 'c': return pbcopy();
+        case 'p': return pbpaste();
+    }
+    return EX_USAGE;
+}
diff --git a/home/.bin/sup b/home/.bin/sup
new file mode 100755
index 00000000..7a69d9d0
--- /dev/null
+++ b/home/.bin/sup
@@ -0,0 +1,7 @@
+#!/usr/bin/env zsh
+set -o errexit -o nounset -o pipefail
+
+dir=$(mktemp -d)
+screencapture -i "$dir/capture.png"
+up "$dir/capture.png"
+rm -r "$dir"
diff --git a/home/.bin/tup b/home/.bin/tup
new file mode 100755
index 00000000..29af9b0a
--- /dev/null
+++ b/home/.bin/tup
@@ -0,0 +1,7 @@
+#!/usr/bin/env zsh
+set -o errexit -o nounset -o pipefail
+
+dir=$(mktemp -d)
+cat > "$dir/input.txt"
+up "$dir/input.txt"
+rm -r "$dir"
diff --git a/home/.bin/up b/home/.bin/up
new file mode 100755
index 00000000..3a25e112
--- /dev/null
+++ b/home/.bin/up
@@ -0,0 +1,12 @@
+#!/usr/bin/env zsh
+set -o errexit -o nounset -o pipefail
+
+ts=$(date +%s)
+rand=$(openssl rand -hex 4)
+ext=${1##*.}
+url=$(printf 'tmp.cmcenroe.me/%x%s.%s' "$ts" "$rand" "$ext")
+
+scp -q "$1" "tmp.cmcenroe.me:/usr/local/www/$url"
+
+echo "https://$url"
+type pbcopy > /dev/null && echo -n "https://$url" | pbcopy
diff --git a/home/.bin/wake.c b/home/.bin/wake.c
new file mode 100755
index 00000000..2f314975
--- /dev/null
+++ b/home/.bin/wake.c
@@ -0,0 +1,41 @@
+#if 0
+exec cc -Wall -Wextra -Wpedantic $@ -o $(dirname $0)/wake $0
+#endif
+
+#include <err.h>
+#include <netinet/in.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sysexits.h>
+
+#define MAC 0x04, 0x7D, 0x7B, 0xD5, 0x6A, 0x53
+
+const uint8_t payload[] = {
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    MAC, MAC, MAC, MAC, MAC, MAC, MAC, MAC,
+    MAC, MAC, MAC, MAC, MAC, MAC, MAC, MAC,
+};
+
+int main() {
+    int sock = socket(PF_INET, SOCK_DGRAM, 0);
+    if (sock < 0) err(EX_OSERR, "socket");
+
+    int on = 1;
+    int error = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
+    if (error) err(EX_OSERR, "setsockopt");
+
+    struct sockaddr_in addr = {
+        .sin_family = AF_INET,
+        .sin_port = 9,
+        .sin_addr.s_addr = INADDR_BROADCAST,
+    };
+
+    ssize_t len = sendto(
+        sock, payload, sizeof(payload), 0,
+        (struct sockaddr *)&addr, sizeof(addr)
+    );
+    if (len < 0) err(EX_IOERR, "sendto");
+
+    return EX_OK;
+}
diff --git a/home/.bin/watch.c b/home/.bin/watch.c
new file mode 100755
index 00000000..c13f6d71
--- /dev/null
+++ b/home/.bin/watch.c
@@ -0,0 +1,100 @@
+#if 0
+exec cc -Wall -Wextra -Wpedantic -o $(dirname $0)/watch $0
+#endif
+
+/*
+ * Execute a command each time files change.
+ *
+ * Copyright (c) 2017, Curtis McEnroe <programble@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/event.h>
+#include <sys/wait.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+static void watch(int kq, char *path) {
+    int fd = open(path, O_RDONLY);
+    if (fd < 0) err(EX_IOERR, "%s", path);
+
+    struct kevent event = {
+        .ident = fd,
+        .filter = EVFILT_VNODE,
+        .flags = EV_ADD | EV_CLEAR,
+        .fflags = NOTE_WRITE | NOTE_DELETE,
+        .udata = path,
+    };
+    int nevents = kevent(kq, &event, 1, NULL, 0, NULL);
+    if (nevents < 0) err(EX_IOERR, "kevent");
+}
+
+static void exec(char *const argv[]) {
+    pid_t pid = fork();
+    if (pid < 0) err(EX_OSERR, "fork");
+
+    if (!pid) {
+        execvp(argv[0], argv);
+        err(EX_OSERR, "%s", argv[0]);
+    }
+
+    int status;
+    pid = wait(&status);
+    if (pid < 0) err(EX_OSERR, "wait");
+
+    if (WIFEXITED(status)) {
+        warnx("exit %d", WEXITSTATUS(status));
+    } else if (WIFSIGNALED(status)) {
+        warnx("signal %d", WTERMSIG(status));
+    } else {
+        warnx("status %d", status);
+    }
+}
+
+int main(int argc, char *argv[]) {
+    if (argc < 3) return EX_USAGE;
+
+    int kq = kqueue();
+    if (kq < 0) err(EX_OSERR, "kqueue");
+
+    int index;
+    for (index = 1; index < argc - 1; ++index) {
+        if (argv[index][0] == '-') {
+            index++;
+            break;
+        }
+        watch(kq, argv[index]);
+    }
+
+    exec(&argv[index]);
+
+    for (;;) {
+        struct kevent event;
+        int nevents = kevent(kq, NULL, 0, &event, 1, NULL);
+        if (nevents < 0) err(EX_IOERR, "kevent");
+
+        if (event.fflags & NOTE_DELETE) {
+            close(event.ident);
+            watch(kq, event.udata);
+        }
+
+        exec(&argv[index]);
+    }
+}
diff --git a/home/.bin/xx.c b/home/.bin/xx.c
new file mode 100755
index 00000000..78d8db4c
--- /dev/null
+++ b/home/.bin/xx.c
@@ -0,0 +1,117 @@
+#if 0
+exec cc -Wall -Wextra -pedantic $@ -o $(dirname $0)/xx $0
+#endif
+
+// Hexdump.
+
+#include <ctype.h>
+#include <err.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+static bool allZero(const uint8_t *buf, size_t len) {
+    for (size_t i = 0; i < len; ++i)
+        if (buf[i]) return false;
+    return true;
+}
+
+enum {
+    FLAG_ASCII  = 1 << 0,
+    FLAG_OFFSET = 1 << 1,
+    FLAG_SKIP   = 1 << 2,
+    FLAG_UNDUMP = 1 << 3,
+};
+
+static void dump(size_t cols, size_t group, uint8_t flags, FILE *file) {
+    uint8_t buf[cols];
+    size_t offset = 0, len = 0;
+    for (;;) {
+        offset += len;
+        len = fread(buf, 1, sizeof(buf), file);
+        if (!len) break;
+
+        if ((flags & FLAG_SKIP) && len == sizeof(buf)) {
+            static bool skip;
+            if (allZero(buf, len)) {
+                if (!skip) printf("*\n");
+                skip = true;
+                continue;
+            }
+            skip = false;
+        }
+
+        if (flags & FLAG_OFFSET) {
+            printf("%08zx:  ", offset);
+        }
+
+        for (size_t i = 0; i < len; ++i) {
+            if (group && i && !(i % group)) printf(" ");
+            printf("%02x ", buf[i]);
+        }
+
+        if (flags & FLAG_ASCII) {
+            for (size_t i = len; i < cols; ++i) {
+                printf((group && !(i % group)) ? "    " : "   ");
+            }
+            printf(" ");
+            for (size_t i = 0; i < len; ++i) {
+                if (group && i && !(i % group)) printf(" ");
+                printf("%c", isprint(buf[i]) ? buf[i] : '.');
+            }
+        }
+
+        printf("\n");
+        if (len < sizeof(buf)) break;
+    }
+}
+
+static void undump(FILE *file) {
+    uint8_t byte;
+    int match;
+    while (1 == (match = fscanf(file, " %hhx", &byte))) {
+        printf("%c", byte);
+    }
+    if (match == 0) errx(EX_DATAERR, "invalid input");
+}
+
+int main(int argc, char *argv[]) {
+    size_t cols = 16;
+    size_t group = 8;
+    uint8_t flags = FLAG_ASCII | FLAG_OFFSET;
+    char *path = NULL;
+
+    int opt;
+    while (0 < (opt = getopt(argc, argv, "ac:fg:hku"))) {
+        switch (opt) {
+            case 'a': flags ^= FLAG_ASCII; break;
+            case 'f': flags ^= FLAG_OFFSET; break;
+            case 'k': flags ^= FLAG_SKIP; break;
+            case 'u': flags ^= FLAG_UNDUMP; break;
+            case 'c': cols = strtoul(optarg, NULL, 10); break;
+            case 'g': group = strtoul(optarg, NULL, 10); break;
+            default:
+                fprintf(stderr, "usage: xx [-afku] [-c cols] [-g group] [file]\n");
+                return (opt == 'h') ? EX_OK : EX_USAGE;
+        }
+    }
+    if (!cols) return EX_USAGE;
+    if (argc > optind) {
+        path = argv[optind];
+    }
+
+    FILE *file = path ? fopen(path, "r") : stdin;
+    if (!file) err(EX_NOINPUT, "%s", path);
+
+    if (flags & FLAG_UNDUMP) {
+        undump(file);
+    } else {
+        dump(cols, group, flags, file);
+    }
+
+    if (ferror(file)) err(EX_IOERR, "%s", path);
+    return EX_OK;
+}