diff options
Diffstat (limited to 'bin')
-rw-r--r-- | bin/beef.c | 7 | ||||
-rw-r--r-- | bin/bit.y | 3 | ||||
-rw-r--r-- | bin/c11.l | 2 | ||||
-rw-r--r-- | bin/dehtml.l | 7 | ||||
-rw-r--r-- | bin/downgrade.c | 57 | ||||
-rw-r--r-- | bin/dtch.c | 61 | ||||
-rw-r--r-- | bin/ever.c | 23 | ||||
-rw-r--r-- | bin/freecell.c | 5 | ||||
-rw-r--r-- | bin/git-comment.pl | 2 | ||||
-rw-r--r-- | bin/glitch.c | 694 | ||||
-rw-r--r-- | bin/hilex.c | 29 | ||||
-rw-r--r-- | bin/hilex.h | 2 | ||||
-rw-r--r-- | bin/htagml.c | 23 | ||||
-rw-r--r-- | bin/make.l | 2 | ||||
-rw-r--r-- | bin/man1/up.1 | 18 | ||||
-rw-r--r-- | bin/man1/when.1 | 34 | ||||
-rw-r--r-- | bin/mdoc.l | 2 | ||||
-rw-r--r-- | bin/modem.c | 29 | ||||
-rw-r--r-- | bin/mtags.c | 11 | ||||
-rw-r--r-- | bin/nudge.c | 15 | ||||
-rw-r--r-- | bin/order.y | 11 | ||||
-rw-r--r-- | bin/pbd.c | 45 | ||||
-rw-r--r-- | bin/png.h | 5 | ||||
-rw-r--r-- | bin/pngo.c | 85 | ||||
-rw-r--r-- | bin/psf2png.c | 17 | ||||
-rw-r--r-- | bin/ptee.c | 39 | ||||
-rw-r--r-- | bin/qf.c | 25 | ||||
-rw-r--r-- | bin/quick.c | 21 | ||||
-rw-r--r-- | bin/relay.c | 45 | ||||
-rw-r--r-- | bin/scheme.c | 7 | ||||
-rw-r--r-- | bin/shotty.l | 15 | ||||
-rw-r--r-- | bin/title.c | 19 | ||||
-rw-r--r-- | bin/up.sh | 30 | ||||
-rw-r--r-- | bin/when.y | 134 | ||||
-rw-r--r-- | bin/xx.c | 15 |
35 files changed, 842 insertions, 697 deletions
diff --git a/bin/beef.c b/bin/beef.c index b2579b73..31781753 100644 --- a/bin/beef.c +++ b/bin/beef.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 C. McEnroe <june@causal.agency> +/* Copyright (C) 2019 June McEnroe <june@causal.agency> * * 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 @@ -19,7 +19,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sysexits.h> #include <time.h> enum { @@ -44,7 +43,7 @@ static long stack[StackLen]; static size_t top = StackLen; static void push(long val) { - if (!top) errx(EX_SOFTWARE, "stack overflow"); + if (!top) errx(1, "stack overflow"); stack[--top] = val; } static long pop(void) { @@ -121,7 +120,7 @@ int main(int argc, char *argv[]) { FILE *file = stdin; if (argc > 1) { file = fopen(argv[1], "r"); - if (!file) err(EX_NOINPUT, "%s", argv[1]); + if (!file) err(1, "%s", argv[1]); } int y = 0; diff --git a/bin/bit.y b/bin/bit.y index ab310492..33f5f940 100644 --- a/bin/bit.y +++ b/bin/bit.y @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 C. McEnroe <june@causal.agency> +/* Copyright (C) 2019 June McEnroe <june@causal.agency> * * 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 @@ -22,7 +22,6 @@ #include <stdint.h> #include <stdio.h> #include <stdlib.h> -#include <sysexits.h> #define MASK(b) ((1ULL << (b)) - 1) diff --git a/bin/c11.l b/bin/c11.l index a4b8c25a..b1f0b960 100644 --- a/bin/c11.l +++ b/bin/c11.l @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 C. McEnroe <june@causal.agency> +/* Copyright (C) 2020 June McEnroe <june@causal.agency> * * 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 diff --git a/bin/dehtml.l b/bin/dehtml.l index 3f2de592..b6aa4eb8 100644 --- a/bin/dehtml.l +++ b/bin/dehtml.l @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 C. McEnroe <june@causal.agency> +/* Copyright (C) 2021 June McEnroe <june@causal.agency> * * 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 @@ -47,7 +47,6 @@ enum Token { #include <stdlib.h> #include <string.h> #include <strings.h> -#include <sysexits.h> #include <unistd.h> #include <wchar.h> @@ -107,7 +106,7 @@ int main(int argc, char *argv[]) { for (int opt; 0 < (opt = getopt(argc, argv, "s"));) { switch (opt) { break; case 's': collapse = true; - break; default: return EX_USAGE; + break; default: return 1; } } argc -= optind; @@ -116,7 +115,7 @@ int main(int argc, char *argv[]) { if (!argc) argc++; for (int i = 0; i < argc; ++i) { yyin = (argv[i] ? fopen(argv[i], "r") : stdin); - if (!yyin) err(EX_NOINPUT, "%s", argv[i]); + if (!yyin) err(1, "%s", argv[i]); bool space = true; bool discard = false; diff --git a/bin/downgrade.c b/bin/downgrade.c index d4c5b598..0d76c787 100644 --- a/bin/downgrade.c +++ b/bin/downgrade.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 C. McEnroe <june@causal.agency> +/* Copyright (C) 2021 June McEnroe <june@causal.agency> * * 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 @@ -22,7 +22,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sysexits.h> #include <tls.h> #include <unistd.h> @@ -40,7 +39,7 @@ static void clientWrite(const char *ptr, size_t len) { while (len) { ssize_t ret = tls_write(client, ptr, len); if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT) continue; - if (ret < 0) errx(EX_IOERR, "tls_write: %s", tls_error(client)); + if (ret < 0) errx(1, "tls_write: %s", tls_error(client)); ptr += ret; len -= ret; } @@ -77,11 +76,11 @@ static void push(struct Message msg) { dst->id = strdup(msg.id); dst->nick = strdup(msg.nick); dst->chan = strdup(msg.chan); - if (!dst->id || !dst->nick || !dst->chan) err(EX_OSERR, "strdup"); + if (!dst->id || !dst->nick || !dst->chan) err(1, "strdup"); dst->mesg = NULL; if (msg.mesg) { dst->mesg = strdup(msg.mesg); - if (!dst->mesg) err(EX_OSERR, "strdup"); + if (!dst->mesg) err(1, "strdup"); } } @@ -103,11 +102,11 @@ static void handle(char *ptr) { if (!strcmp(cmd, "CAP")) { strsep(&ptr, " "); char *sub = strsep(&ptr, " "); - if (!sub) errx(EX_PROTOCOL, "CAP without subcommand"); + if (!sub) errx(1, "CAP without subcommand"); if (!strcmp(sub, "NAK")) { - errx(EX_CONFIG, "server does not support %s", ptr); + errx(1, "server does not support %s", ptr); } else if (!strcmp(sub, "ACK")) { - if (!ptr) errx(EX_PROTOCOL, "CAP ACK without caps"); + if (!ptr) errx(1, "CAP ACK without caps"); if (*ptr == ':') ptr++; if (!strcmp(ptr, "sasl")) format("AUTHENTICATE EXTERNAL\r\n"); } @@ -116,13 +115,13 @@ static void handle(char *ptr) { } else if (!strcmp(cmd, "433")) { strsep(&ptr, " "); char *nick = strsep(&ptr, " "); - if (!nick) errx(EX_PROTOCOL, "ERR_NICKNAMEINUSE missing nick"); + if (!nick) errx(1, "ERR_NICKNAMEINUSE missing nick"); format("NICK %s_\r\n", nick); } else if (!strcmp(cmd, "001")) { if (join) format("JOIN %s\r\n", join); } else if (!strcmp(cmd, "005")) { char *self = strsep(&ptr, " "); - if (!self) errx(EX_PROTOCOL, "RPL_ISUPPORT missing nick"); + if (!self) errx(1, "RPL_ISUPPORT missing nick"); while (ptr && *ptr != ':') { char *tok = strsep(&ptr, " "); char *key = strsep(&tok, "="); @@ -132,16 +131,16 @@ static void handle(char *ptr) { } } else if (!strcmp(cmd, "INVITE") && invite) { strsep(&ptr, " "); - if (!ptr) errx(EX_PROTOCOL, "INVITE missing channel"); + if (!ptr) errx(1, "INVITE missing channel"); if (*ptr == ':') ptr++; format("JOIN %s\r\n", ptr); } else if (!strcmp(cmd, "PING")) { - if (!ptr) errx(EX_PROTOCOL, "PING missing parameter"); + if (!ptr) errx(1, "PING missing parameter"); format("PONG %s\r\n", ptr); } else if (!strcmp(cmd, "ERROR")) { - if (!ptr) errx(EX_PROTOCOL, "ERROR missing parameter"); + if (!ptr) errx(1, "ERROR missing parameter"); if (*ptr == ':') ptr++; - errx(EX_UNAVAILABLE, "%s", ptr); + errx(1, "%s", ptr); } if ( @@ -149,13 +148,13 @@ static void handle(char *ptr) { strcmp(cmd, "NOTICE") && strcmp(cmd, "TAGMSG") ) return; - if (!origin) errx(EX_PROTOCOL, "%s missing origin", cmd); + if (!origin) errx(1, "%s missing origin", cmd); struct Message msg = { .nick = strsep(&origin, "!"), .chan = strsep(&ptr, " "), }; - if (!msg.chan) errx(EX_PROTOCOL, "%s missing target", cmd); + if (!msg.chan) errx(1, "%s missing target", cmd); if (msg.chan[0] == ':') msg.chan++; if (msg.chan[0] != '#') return; if (strcmp(cmd, "TAGMSG")) msg.mesg = (*ptr == ':' ? &ptr[1] : ptr); @@ -263,7 +262,7 @@ static void quit(int sig) { (void)sig; format("QUIT\r\n"); tls_close(client); - exit(EX_OK); + exit(0); } int main(int argc, char *argv[]) { @@ -282,44 +281,44 @@ int main(int argc, char *argv[]) { break; case 'n': nick = optarg; break; case 'p': port = optarg; break; case 'v': verbose = true; - break; default: return EX_USAGE; + break; default: return 1; } } - if (optind == argc) errx(EX_USAGE, "host required"); + if (optind == argc) errx(1, "host required"); host = argv[optind]; client = tls_client(); - if (!client) errx(EX_SOFTWARE, "tls_client"); + if (!client) errx(1, "tls_client"); struct tls_config *config = tls_config_new(); - if (!config) errx(EX_SOFTWARE, "tls_config_new"); + if (!config) errx(1, "tls_config_new"); if (cert) { if (!priv) priv = cert; int error = tls_config_set_keypair_file(config, cert, priv); - if (error) errx(EX_NOINPUT, "%s: %s", cert, tls_config_error(config)); + if (error) errx(1, "%s: %s", cert, tls_config_error(config)); } int error = tls_configure(client, config); - if (error) errx(EX_SOFTWARE, "tls_configure: %s", tls_error(client)); + if (error) errx(1, "tls_configure: %s", tls_error(client)); error = tls_connect(client, host, port); - if (error) errx(EX_UNAVAILABLE, "tls_connect: %s", tls_error(client)); + if (error) errx(1, "tls_connect: %s", tls_error(client)); do { error = tls_handshake(client); } while (error == TLS_WANT_POLLIN || error == TLS_WANT_POLLOUT); - if (error) errx(EX_PROTOCOL, "tls_handshake: %s", tls_error(client)); + if (error) errx(1, "tls_handshake: %s", tls_error(client)); tls_config_clear_keys(config); #ifdef __OpenBSD__ error = pledge("stdio", NULL); - if (error) err(EX_OSERR, "pledge"); + if (error) err(1, "pledge"); #endif #ifdef __FreeBSD__ error = caph_enter() || caph_limit_stdio(); - if (error) err(EX_OSERR, "caph_enter"); + if (error) err(1, "caph_enter"); #endif signal(SIGHUP, quit); @@ -342,8 +341,8 @@ int main(int argc, char *argv[]) { for (;;) { ssize_t n = tls_read(client, &buf[len], sizeof(buf) - len); if (n == TLS_WANT_POLLIN || n == TLS_WANT_POLLOUT) continue; - if (n < 0) errx(EX_IOERR, "tls_read: %s", tls_error(client)); - if (!n) errx(EX_UNAVAILABLE, "disconnected"); + if (n < 0) errx(1, "tls_read: %s", tls_error(client)); + if (!n) errx(1, "disconnected"); len += n; char *ptr = buf; diff --git a/bin/dtch.c b/bin/dtch.c index 2aea53ae..55b33910 100644 --- a/bin/dtch.c +++ b/bin/dtch.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2017-2019 C. McEnroe <june@causal.agency> +/* Copyright (C) 2017-2019 June McEnroe <june@causal.agency> * * 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 @@ -28,7 +28,6 @@ #include <sys/stat.h> #include <sys/un.h> #include <sys/wait.h> -#include <sysexits.h> #include <termios.h> #include <unistd.h> @@ -91,18 +90,18 @@ static void handler(int sig) { static void detach(int server, bool sink, char *argv[]) { int pty; pid_t pid = forkpty(&pty, NULL, NULL, NULL); - if (pid < 0) err(EX_OSERR, "forkpty"); + if (pid < 0) err(1, "forkpty"); if (!pid) { execvp(argv[0], argv); - err(EX_NOINPUT, "%s", argv[0]); + err(127, "%s", argv[0]); } signal(SIGINT, handler); signal(SIGTERM, handler); int error = listen(server, 0); - if (error) err(EX_OSERR, "listen"); + if (error) err(1, "listen"); struct pollfd fds[] = { { .events = POLLIN, .fd = server }, @@ -111,7 +110,7 @@ static void detach(int server, bool sink, char *argv[]) { while (0 < poll(fds, (sink ? 2 : 1), -1)) { if (fds[0].revents) { int client = accept(server, NULL, NULL); - if (client < 0) err(EX_IOERR, "accept"); + if (client < 0) err(1, "accept"); ssize_t len = sendfd(client, pty); if (len < 0) warn("sendfd"); @@ -125,18 +124,18 @@ static void detach(int server, bool sink, char *argv[]) { if (fds[1].revents) { char buf[4096]; ssize_t len = read(pty, buf, sizeof(buf)); - if (len < 0) err(EX_IOERR, "read"); + if (len < 0) err(1, "read"); } int status; pid_t dead = waitpid(pid, &status, WNOHANG); - if (dead < 0) err(EX_OSERR, "waitpid"); + if (dead < 0) err(1, "waitpid"); if (dead) { unlink(addr.sun_path); exit(WIFEXITED(status) ? WEXITSTATUS(status) : -WTERMSIG(status)); } } - err(EX_IOERR, "poll"); + err(1, "poll"); } static struct termios saveTerm; @@ -154,28 +153,28 @@ static void attach(int client) { int error; int pty = recvfd(client); - if (pty < 0) err(EX_IOERR, "recvfd"); + if (pty < 0) err(1, "recvfd"); warnx("attached"); struct winsize window; error = ioctl(STDIN_FILENO, TIOCGWINSZ, &window); - if (error) err(EX_IOERR, "ioctl"); + if (error) err(1, "ioctl"); struct winsize redraw = { .ws_row = 1, .ws_col = 1 }; error = ioctl(pty, TIOCSWINSZ, &redraw); - if (error) err(EX_IOERR, "ioctl"); + if (error) err(1, "ioctl"); error = ioctl(pty, TIOCSWINSZ, &window); - if (error) err(EX_IOERR, "ioctl"); + if (error) err(1, "ioctl"); error = tcgetattr(STDIN_FILENO, &saveTerm); - if (error) err(EX_IOERR, "tcgetattr"); + if (error) err(1, "tcgetattr"); atexit(restoreTerm); struct termios raw = saveTerm; cfmakeraw(&raw); error = tcsetattr(STDIN_FILENO, TCSADRAIN, &raw); - if (error) err(EX_IOERR, "tcsetattr"); + if (error) err(1, "tcsetattr"); signal(SIGWINCH, nop); @@ -187,35 +186,35 @@ static void attach(int client) { for (;;) { int nfds = poll(fds, 2, -1); if (nfds < 0) { - if (errno != EINTR) err(EX_IOERR, "poll"); + if (errno != EINTR) err(1, "poll"); error = ioctl(STDIN_FILENO, TIOCGWINSZ, &window); - if (error) err(EX_IOERR, "ioctl"); + if (error) err(1, "ioctl"); error = ioctl(pty, TIOCSWINSZ, &window); - if (error) err(EX_IOERR, "ioctl"); + if (error) err(1, "ioctl"); continue; } if (fds[0].revents) { ssize_t len = read(STDIN_FILENO, buf, sizeof(buf)); - if (len < 0) err(EX_IOERR, "read"); + if (len < 0) err(1, "read"); if (!len) break; if (len == 1 && buf[0] == CTRL('Q')) break; len = write(pty, buf, len); - if (len < 0) err(EX_IOERR, "write"); + if (len < 0) err(1, "write"); } if (fds[1].revents) { ssize_t len = read(pty, buf, sizeof(buf)); - if (len < 0) err(EX_IOERR, "read"); + if (len < 0) err(1, "read"); if (!len) break; len = write(STDOUT_FILENO, buf, len); - if (len < 0) err(EX_IOERR, "write"); + if (len < 0) err(1, "write"); } } } @@ -231,41 +230,41 @@ int main(int argc, char *argv[]) { switch (opt) { break; case 'a': atch = true; break; case 's': sink = true; - break; default: return EX_USAGE; + break; default: return 1; } } - if (optind == argc) errx(EX_USAGE, "no session name"); + if (optind == argc) errx(1, "no session name"); const char *name = argv[optind++]; if (optind == argc) { argv[--optind] = getenv("SHELL"); - if (!argv[optind]) errx(EX_CONFIG, "SHELL unset"); + if (!argv[optind]) errx(1, "SHELL unset"); } const char *home = getenv("HOME"); - if (!home) errx(EX_CONFIG, "HOME unset"); + if (!home) errx(1, "HOME unset"); int fd = open(home, 0); - if (fd < 0) err(EX_CANTCREAT, "%s", home); + if (fd < 0) err(1, "%s", home); error = mkdirat(fd, ".dtch", 0700); - if (error && errno != EEXIST) err(EX_CANTCREAT, "%s/.dtch", home); + if (error && errno != EEXIST) err(1, "%s/.dtch", home); close(fd); int sock = socket(PF_UNIX, SOCK_STREAM, 0); - if (sock < 0) err(EX_OSERR, "socket"); + if (sock < 0) err(1, "socket"); fcntl(sock, F_SETFD, FD_CLOEXEC); snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/.dtch/%s", home, name); if (atch) { error = connect(sock, (struct sockaddr *)&addr, SUN_LEN(&addr)); - if (error) err(EX_NOINPUT, "%s", addr.sun_path); + if (error) err(1, "%s", addr.sun_path); attach(sock); } else { error = bind(sock, (struct sockaddr *)&addr, SUN_LEN(&addr)); - if (error) err(EX_CANTCREAT, "%s", addr.sun_path); + if (error) err(1, "%s", addr.sun_path); detach(sock, sink, &argv[optind]); } } diff --git a/bin/ever.c b/bin/ever.c index f983912b..24575617 100644 --- a/bin/ever.c +++ b/bin/ever.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 C. McEnroe <june@causal.agency> +/* Copyright (C) 2017 June McEnroe <june@causal.agency> * * 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 @@ -22,12 +22,11 @@ #include <stdlib.h> #include <sys/event.h> #include <sys/wait.h> -#include <sysexits.h> #include <unistd.h> static int watch(int kq, char *path) { int fd = open(path, O_CLOEXEC); - if (fd < 0) err(EX_NOINPUT, "%s", path); + if (fd < 0) err(1, "%s", path); struct kevent event; EV_SET( @@ -40,7 +39,7 @@ static int watch(int kq, char *path) { path ); int nevents = kevent(kq, &event, 1, NULL, 0, NULL); - if (nevents < 0) err(EX_OSERR, "kevent"); + if (nevents < 0) err(1, "kevent"); return fd; } @@ -48,17 +47,17 @@ static int watch(int kq, char *path) { static bool quiet; static void exec(int fd, char *const argv[]) { pid_t pid = fork(); - if (pid < 0) err(EX_OSERR, "fork"); + if (pid < 0) err(1, "fork"); if (!pid) { dup2(fd, STDIN_FILENO); execvp(*argv, argv); - err(EX_NOINPUT, "%s", *argv); + err(127, "%s", *argv); } int status; pid = wait(&status); - if (pid < 0) err(EX_OSERR, "wait"); + if (pid < 0) err(1, "wait"); if (quiet) return; if (WIFEXITED(status)) { @@ -77,15 +76,15 @@ int main(int argc, char *argv[]) { switch (opt) { break; case 'i': input = true; break; case 'q': quiet = true; - break; default: return EX_USAGE; + break; default: return 1; } } argc -= optind; argv += optind; - if (argc < 2) return EX_USAGE; + if (argc < 2) return 1; int kq = kqueue(); - if (kq < 0) err(EX_OSERR, "kqueue"); + if (kq < 0) err(1, "kqueue"); int i; for (i = 0; i < argc - 1; ++i) { @@ -103,7 +102,7 @@ int main(int argc, char *argv[]) { for (;;) { struct kevent event; int nevents = kevent(kq, NULL, 0, &event, 1, NULL); - if (nevents < 0) err(EX_OSERR, "kevent"); + if (nevents < 0) err(1, "kevent"); if (event.fflags & NOTE_DELETE) { close(event.ident); @@ -111,7 +110,7 @@ int main(int argc, char *argv[]) { event.ident = watch(kq, (char *)event.udata); } else if (input) { off_t off = lseek(event.ident, 0, SEEK_SET); - if (off < 0) err(EX_IOERR, "lseek"); + if (off < 0) err(1, "lseek"); } exec((input ? event.ident : STDIN_FILENO), &argv[i]); diff --git a/bin/freecell.c b/bin/freecell.c index 11bed1c0..0110ecfe 100644 --- a/bin/freecell.c +++ b/bin/freecell.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2019, 2021 C. McEnroe <june@causal.agency> +/* Copyright (C) 2019, 2021 June McEnroe <june@causal.agency> * * 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 @@ -22,7 +22,6 @@ #include <stdbool.h> #include <stdio.h> #include <stdlib.h> -#include <sysexits.h> #include <time.h> #include <unistd.h> @@ -367,7 +366,7 @@ int main(int argc, char *argv[]) { switch (opt) { break; case 'd': delay = strtoul(optarg, NULL, 10); break; case 'n': game = strtoul(optarg, NULL, 10); - break; default: return EX_USAGE; + break; default: return 1; } } curse(); diff --git a/bin/git-comment.pl b/bin/git-comment.pl index 5100941f..5352702d 100644 --- a/bin/git-comment.pl +++ b/bin/git-comment.pl @@ -1,5 +1,5 @@ #!/usr/bin/env perl -# Copyright (C) 2021 C. McEnroe <june@causal.agency> +# Copyright (C) 2021 June McEnroe <june@causal.agency> # # 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 diff --git a/bin/glitch.c b/bin/glitch.c index 9747f35a..4eec2c49 100644 --- a/bin/glitch.c +++ b/bin/glitch.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 C. McEnroe <june@causal.agency> +/* Copyright (C) 2018, 2021 June McEnroe <june@causal.agency> * * 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 @@ -14,297 +14,339 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <arpa/inet.h> #include <err.h> +#include <inttypes.h> +#include <limits.h> #include <stdbool.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sysexits.h> #include <unistd.h> #include <zlib.h> -#define PACKED __attribute__((packed)) - -#define CRC_INIT (crc32(0, Z_NULL, 0)) +#define ARRAY_LEN(a) (sizeof(a) / sizeof(a[0])) static const char *path; static FILE *file; static uint32_t crc; -static void readExpect(void *ptr, size_t size, const char *expect) { - fread(ptr, size, 1, file); - if (ferror(file)) err(EX_IOERR, "%s", path); - if (feof(file)) errx(EX_DATAERR, "%s: missing %s", path, expect); - crc = crc32(crc, ptr, size); +static void pngRead(void *ptr, size_t len, const char *desc) { + size_t n = fread(ptr, len, 1, file); + if (!n && ferror(file)) err(1, "%s", path); + if (!n) errx(1, "%s: missing %s", path, desc); + crc = crc32(crc, ptr, len); } -static void writeExpect(const void *ptr, size_t size) { - fwrite(ptr, size, 1, file); - if (ferror(file)) err(EX_IOERR, "%s", path); - crc = crc32(crc, ptr, size); +static void pngWrite(const void *ptr, size_t len) { + size_t n = fwrite(ptr, len, 1, file); + if (!n) err(1, "%s", path); + crc = crc32(crc, ptr, len); } -static const uint8_t Signature[8] = "\x89PNG\r\n\x1A\n"; +static const uint8_t Sig[8] = "\x89PNG\r\n\x1A\n"; -static void readSignature(void) { - uint8_t signature[8]; - readExpect(signature, 8, "signature"); - if (0 != memcmp(signature, Signature, 8)) { - errx(EX_DATAERR, "%s: invalid signature", path); +static void sigRead(void) { + uint8_t sig[sizeof(Sig)]; + pngRead(sig, sizeof(sig), "signature"); + if (memcmp(sig, Sig, sizeof(sig))) { + errx(1, "%s: invalid signature", path); } } -static void writeSignature(void) { - writeExpect(Signature, sizeof(Signature)); +static void sigWrite(void) { + pngWrite(Sig, sizeof(Sig)); } -struct PACKED Chunk { - uint32_t size; - char type[4]; -}; +static uint32_t u32Read(const char *desc) { + uint8_t b[4]; + pngRead(b, sizeof(b), desc); + return (uint32_t)b[0] << 24 | (uint32_t)b[1] << 16 + | (uint32_t)b[2] << 8 | (uint32_t)b[3]; +} -static const char *typeStr(struct Chunk chunk) { - static char buf[5]; - memcpy(buf, chunk.type, 4); - return buf; +static void u32Write(uint32_t x) { + uint8_t b[4] = { x >> 24 & 0xFF, x >> 16 & 0xFF, x >> 8 & 0xFF, x & 0xFF }; + pngWrite(b, sizeof(b)); } -static struct Chunk readChunk(void) { +struct Chunk { + uint32_t len; + char type[5]; +}; + +static struct Chunk chunkRead(void) { struct Chunk chunk; - readExpect(&chunk, sizeof(chunk), "chunk"); - chunk.size = ntohl(chunk.size); - crc = crc32(CRC_INIT, (Byte *)chunk.type, sizeof(chunk.type)); + chunk.len = u32Read("chunk length"); + crc = crc32(0, Z_NULL, 0); + pngRead(chunk.type, 4, "chunk type"); + chunk.type[4] = 0; return chunk; } -static void writeChunk(struct Chunk chunk) { - chunk.size = htonl(chunk.size); - writeExpect(&chunk, sizeof(chunk)); - crc = crc32(CRC_INIT, (Byte *)chunk.type, sizeof(chunk.type)); +static void chunkWrite(struct Chunk chunk) { + u32Write(chunk.len); + crc = crc32(0, Z_NULL, 0); + pngWrite(chunk.type, 4); } -static void readCrc(void) { - uint32_t expected = crc; - uint32_t found; - readExpect(&found, sizeof(found), "CRC32"); - found = ntohl(found); - if (found != expected) { - errx( - EX_DATAERR, "%s: expected CRC32 %08X, found %08X", - path, expected, found - ); - } +static void crcRead(void) { + uint32_t expect = crc; + uint32_t actual = u32Read("CRC32"); + if (actual == expect) return; + errx( + 1, "%s: expected CRC32 %08X, found %08X", + path, expect, actual + ); } -static void writeCrc(void) { - uint32_t net = htonl(crc); - writeExpect(&net, sizeof(net)); +static void crcWrite(void) { + u32Write(crc); } -static void skipChunk(struct Chunk chunk) { - uint8_t discard[chunk.size]; - readExpect(discard, sizeof(discard), "chunk data"); - readCrc(); +static void chunkSkip(struct Chunk chunk) { + if (!(chunk.type[0] & 0x20)) { + errx(1, "%s: unsupported critical chunk %s", path, chunk.type); + } + uint8_t buf[4096]; + while (chunk.len > sizeof(buf)) { + pngRead(buf, sizeof(buf), "chunk data"); + chunk.len -= sizeof(buf); + } + if (chunk.len) pngRead(buf, chunk.len, "chunk data"); + crcRead(); } -static struct PACKED { +enum Color { + Grayscale = 0, + Truecolor = 2, + Indexed = 3, + GrayscaleAlpha = 4, + TruecolorAlpha = 6, +}; +enum Compression { + Deflate, +}; +enum FilterMethod { + Adaptive, +}; +enum Interlace { + Progressive, + Adam7, +}; + +enum { HeaderLen = 13 }; +static struct { uint32_t width; uint32_t height; uint8_t depth; - enum PACKED { - Grayscale = 0, - Truecolor = 2, - Indexed = 3, - GrayscaleAlpha = 4, - TruecolorAlpha = 6, - } color; + uint8_t color; uint8_t compression; uint8_t filter; uint8_t interlace; } header; -_Static_assert(13 == sizeof(header), "header size"); -static size_t pixelBits(void) { +static size_t pixelLen; +static size_t lineLen; +static size_t dataLen; + +static void recalc(void) { + size_t pixelBits = header.depth; switch (header.color) { - case Grayscale: return 1 * header.depth; - case Truecolor: return 3 * header.depth; - case Indexed: return 1 * header.depth; - case GrayscaleAlpha: return 2 * header.depth; - case TruecolorAlpha: return 4 * header.depth; - default: abort(); + break; case GrayscaleAlpha: pixelBits *= 2; + break; case Truecolor: pixelBits *= 3; + break; case TruecolorAlpha: pixelBits *= 4; } + pixelLen = (pixelBits + 7) / 8; + lineLen = (header.width * pixelBits + 7) / 8; + dataLen = (1 + lineLen) * header.height; } -static size_t pixelSize(void) { - return (pixelBits() + 7) / 8; +static void headerRead(struct Chunk chunk) { + if (chunk.len != HeaderLen) { + errx( + 1, "%s: expected %s length %" PRIu32 ", found %" PRIu32, + path, chunk.type, (uint32_t)HeaderLen, chunk.len + ); + } + header.width = u32Read("header width"); + header.height = u32Read("header height"); + pngRead(&header.depth, 1, "header depth"); + pngRead(&header.color, 1, "header color"); + pngRead(&header.compression, 1, "header compression"); + pngRead(&header.filter, 1, "header filter"); + pngRead(&header.interlace, 1, "header interlace"); + crcRead(); + recalc(); +} + +static void headerWrite(void) { + struct Chunk ihdr = { HeaderLen, "IHDR" }; + chunkWrite(ihdr); + u32Write(header.width); + u32Write(header.height); + pngWrite(&header.depth, 1); + pngWrite(&header.color, 1); + pngWrite(&header.compression, 1); + pngWrite(&header.filter, 1); + pngWrite(&header.interlace, 1); + crcWrite(); } -static size_t lineSize(void) { - return (header.width * pixelBits() + 7) / 8; -} +static struct { + uint32_t len; + uint8_t rgb[256][3]; +} pal; -static size_t dataSize(void) { - return (1 + lineSize()) * header.height; +static struct { + uint32_t len; + uint8_t a[256]; +} trans; + +static void palClear(void) { + pal.len = 0; + trans.len = 0; } -static void readHeader(void) { - struct Chunk ihdr = readChunk(); - if (0 != memcmp(ihdr.type, "IHDR", 4)) { - errx(EX_DATAERR, "%s: expected IHDR, found %s", path, typeStr(ihdr)); +static void palRead(struct Chunk chunk) { + if (chunk.len % 3) { + errx( + 1, "%s: %s length %" PRIu32 " not divisible by 3", + path, chunk.type, chunk.len + ); } - if (ihdr.size != sizeof(header)) { + pal.len = chunk.len / 3; + if (pal.len > 256) { errx( - EX_DATAERR, "%s: expected IHDR size %zu, found %u", - path, sizeof(header), ihdr.size + 1, "%s: %s length %" PRIu32 " > 256", + path, chunk.type, pal.len ); } - readExpect(&header, sizeof(header), "header"); - readCrc(); - header.width = ntohl(header.width); - header.height = ntohl(header.height); - if (!header.width) errx(EX_DATAERR, "%s: invalid width 0", path); - if (!header.height) errx(EX_DATAERR, "%s: invalid height 0", path); + pngRead(pal.rgb, chunk.len, "palette data"); + crcRead(); } -static void writeHeader(void) { - struct Chunk ihdr = { .size = sizeof(header), .type = "IHDR" }; - writeChunk(ihdr); - header.width = htonl(header.width); - header.height = htonl(header.height); - writeExpect(&header, sizeof(header)); - writeCrc(); - header.width = ntohl(header.width); - header.height = ntohl(header.height); +static void palWrite(void) { + struct Chunk plte = { 3 * pal.len, "PLTE" }; + chunkWrite(plte); + pngWrite(pal.rgb, plte.len); + crcWrite(); } -static struct { - uint32_t len; - uint8_t entries[256][3]; -} palette; - -static void readPalette(void) { - struct Chunk chunk; - for (;;) { - chunk = readChunk(); - if (0 == memcmp(chunk.type, "PLTE", 4)) break; - skipChunk(chunk); +static void transRead(struct Chunk chunk) { + trans.len = chunk.len; + if (trans.len > 256) { + errx( + 1, "%s: %s length %" PRIu32 " > 256", + path, chunk.type, trans.len + ); } - palette.len = chunk.size / 3; - readExpect(palette.entries, chunk.size, "palette data"); - readCrc(); + pngRead(trans.a, chunk.len, "transparency data"); + crcRead(); } -static void writePalette(void) { - struct Chunk plte = { .size = 3 * palette.len, .type = "PLTE" }; - writeChunk(plte); - writeExpect(palette.entries, plte.size); - writeCrc(); +static void transWrite(void) { + struct Chunk trns = { trans.len, "tRNS" }; + chunkWrite(trns); + pngWrite(trans.a, trns.len); + crcWrite(); } static uint8_t *data; -static void readData(void) { - data = malloc(dataSize()); - if (!data) err(EX_OSERR, "malloc(%zu)", dataSize()); +static void dataAlloc(void) { + data = malloc(dataLen); + if (!data) err(1, "malloc"); +} - struct z_stream_s stream = { .next_out = data, .avail_out = dataSize() }; +static void dataRead(struct Chunk chunk) { + z_stream stream = { .next_out = data, .avail_out = dataLen }; int error = inflateInit(&stream); - if (error != Z_OK) errx(EX_SOFTWARE, "%s: inflateInit: %s", path, stream.msg); + if (error != Z_OK) errx(1, "inflateInit: %s", stream.msg); for (;;) { - struct Chunk chunk = readChunk(); - if (0 == memcmp(chunk.type, "IDAT", 4)) { - uint8_t *idat = malloc(chunk.size); - if (!idat) err(EX_OSERR, "malloc"); - - readExpect(idat, chunk.size, "image data"); - readCrc(); + if (strcmp(chunk.type, "IDAT")) { + errx(1, "%s: missing IDAT chunk", path); + } - stream.next_in = idat; - stream.avail_in = chunk.size; - int error = inflate(&stream, Z_SYNC_FLUSH); - free(idat); + uint8_t *idat = malloc(chunk.len); + if (!idat) err(1, "malloc"); - if (error == Z_STREAM_END) break; - if (error != Z_OK) errx(EX_DATAERR, "%s: inflate: %s", path, stream.msg); + pngRead(idat, chunk.len, "image data"); + crcRead(); + + stream.next_in = idat; + stream.avail_in = chunk.len; + error = inflate(&stream, Z_SYNC_FLUSH); + free(idat); - } else if (0 == memcmp(chunk.type, "IEND", 4)) { - errx(EX_DATAERR, "%s: missing IDAT chunk", path); - } else { - skipChunk(chunk); + if (error == Z_STREAM_END) break; + if (error != Z_OK) { + errx(1, "%s: inflate: %s", path, stream.msg); } - } + chunk = chunkRead(); + } inflateEnd(&stream); - if ((size_t)stream.total_out != dataSize()) { + if ((size_t)stream.total_out != dataLen) { errx( - EX_DATAERR, "%s: expected data size %zu, found %zu", - path, dataSize(), (size_t)stream.total_out + 1, "%s: expected data length %zu, found %zu", + path, dataLen, (size_t)stream.total_out ); } } -static void writeData(void) { - uLong size = compressBound(dataSize()); - uint8_t *deflate = malloc(size); - if (!deflate) err(EX_OSERR, "malloc"); +static void dataWrite(void) { + z_stream stream = { + .next_in = data, + .avail_in = dataLen, + }; + int error = deflateInit2( + &stream, Z_BEST_COMPRESSION, Z_DEFLATED, 15, 8, Z_FILTERED + ); + if (error != Z_OK) errx(1, "deflateInit2: %s", stream.msg); - int error = compress2(deflate, &size, data, dataSize(), Z_BEST_SPEED); - if (error != Z_OK) errx(EX_SOFTWARE, "%s: compress2: %d", path, error); + uLong bound = deflateBound(&stream, dataLen); + uint8_t *buf = malloc(bound); + if (!buf) err(1, "malloc"); - struct Chunk idat = { .size = size, .type = "IDAT" }; - writeChunk(idat); - writeExpect(deflate, size); - writeCrc(); + stream.next_out = buf; + stream.avail_out = bound; + deflate(&stream, Z_FINISH); + deflateEnd(&stream); - free(deflate); -} + struct Chunk idat = { stream.total_out, "IDAT" }; + chunkWrite(idat); + pngWrite(buf, stream.total_out); + crcWrite(); + free(buf); -static void writeEnd(void) { - struct Chunk iend = { .size = 0, .type = "IEND" }; - writeChunk(iend); - writeCrc(); + struct Chunk iend = { 0, "IEND" }; + chunkWrite(iend); + crcWrite(); } -enum PACKED Filter { +enum Filter { None, Sub, Up, Average, Paeth, - FilterCount, + FilterCap, }; -static struct { - bool brokenPaeth; - bool filt; - bool recon; - uint8_t declareFilter; - uint8_t applyFilter; - enum Filter declareFilters[255]; - enum Filter applyFilters[255]; - bool invert; - bool mirror; - bool zeroX; - bool zeroY; -} options; - struct Bytes { - uint8_t x; - uint8_t a; - uint8_t b; - uint8_t c; + uint8_t x, a, b, c; }; +static bool brokenPaeth; static uint8_t paethPredictor(struct Bytes f) { int32_t p = (int32_t)f.a + (int32_t)f.b - (int32_t)f.c; - int32_t pa = abs(p - (int32_t)f.a); - int32_t pb = abs(p - (int32_t)f.b); - int32_t pc = abs(p - (int32_t)f.c); + int32_t pa = labs(p - (int32_t)f.a); + int32_t pb = labs(p - (int32_t)f.b); + int32_t pc = labs(p - (int32_t)f.c); if (pa <= pb && pa <= pc) return f.a; - if (options.brokenPaeth) { + if (brokenPaeth) { if (pb < pc) return f.b; } else { if (pb <= pc) return f.b; @@ -319,7 +361,7 @@ static uint8_t recon(enum Filter type, struct Bytes f) { case Up: return f.x + f.b; case Average: return f.x + ((uint32_t)f.a + (uint32_t)f.b) / 2; case Paeth: return f.x + paethPredictor(f); - default: abort(); + default: abort(); } } @@ -330,59 +372,59 @@ static uint8_t filt(enum Filter type, struct Bytes f) { case Up: return f.x - f.b; case Average: return f.x - ((uint32_t)f.a + (uint32_t)f.b) / 2; case Paeth: return f.x - paethPredictor(f); - default: abort(); + default: abort(); } } -static struct Line { - enum Filter type; - uint8_t data[]; -} **lines; - -static void scanlines(void) { - lines = calloc(header.height, sizeof(*lines)); - if (!lines) err(EX_OSERR, "calloc(%u, %zu)", header.height, sizeof(*lines)); - - size_t stride = 1 + lineSize(); - for (uint32_t y = 0; y < header.height; ++y) { - lines[y] = (struct Line *)&data[y * stride]; - if (lines[y]->type >= FilterCount) { - errx(EX_DATAERR, "%s: invalid filter type %hhu", path, lines[y]->type); - } - } +static uint8_t *lineType(uint32_t y) { + return &data[y * (1 + lineLen)]; +} +static uint8_t *lineData(uint32_t y) { + return 1 + lineType(y); } static struct Bytes origBytes(uint32_t y, size_t i) { - bool a = (i >= pixelSize()), b = (y > 0), c = (a && b); + bool a = (i >= pixelLen), b = (y > 0), c = (a && b); return (struct Bytes) { - .x = lines[y]->data[i], - .a = a ? lines[y]->data[i - pixelSize()] : 0, - .b = b ? lines[y - 1]->data[i] : 0, - .c = c ? lines[y - 1]->data[i - pixelSize()] : 0, + .x = lineData(y)[i], + .a = (a ? lineData(y)[i-pixelLen] : 0), + .b = (b ? lineData(y-1)[i] : 0), + .c = (c ? lineData(y-1)[i-pixelLen] : 0), }; } -static void reconData(void) { +static bool reconFilter; +static void dataRecon(void) { for (uint32_t y = 0; y < header.height; ++y) { - for (size_t i = 0; i < lineSize(); ++i) { - if (options.filt) { - lines[y]->data[i] = filt(lines[y]->type, origBytes(y, i)); + for (size_t i = 0; i < lineLen; ++i) { + if (reconFilter) { + lineData(y)[i] = filt(*lineType(y), origBytes(y, i)); } else { - lines[y]->data[i] = recon(lines[y]->type, origBytes(y, i)); + lineData(y)[i] = recon(*lineType(y), origBytes(y, i)); } } - lines[y]->type = None; + *lineType(y) = None; } } -static void filterData(void) { - for (uint32_t y = header.height - 1; y < header.height; --y) { - uint8_t filter[FilterCount][lineSize()]; - uint32_t heuristic[FilterCount] = {0}; +static bool filterRecon; +static size_t applyFilter; +static enum Filter applyFilters[256]; +static size_t declFilter; +static enum Filter declFilters[256]; + +static void dataFilter(void) { + uint8_t *filter[FilterCap]; + for (enum Filter i = None; i < FilterCap; ++i) { + filter[i] = malloc(lineLen); + if (!filter[i]) err(1, "malloc"); + } + for (uint32_t y = header.height-1; y < header.height; --y) { + uint32_t heuristic[FilterCap] = {0}; enum Filter minType = None; - for (enum Filter type = None; type < FilterCount; ++type) { - for (size_t i = 0; i < lineSize(); ++i) { - if (options.recon) { + for (enum Filter type = None; type < FilterCap; ++type) { + for (size_t i = 0; i < lineLen; ++i) { + if (filterRecon) { filter[type][i] = recon(type, origBytes(y, i)); } else { filter[type][i] = filt(type, origBytes(y, i)); @@ -391,148 +433,172 @@ static void filterData(void) { } if (heuristic[type] < heuristic[minType]) minType = type; } - - if (options.declareFilter) { - lines[y]->type = options.declareFilters[y % options.declareFilter]; + if (declFilter) { + *lineType(y) = declFilters[y % declFilter]; } else { - lines[y]->type = minType; + *lineType(y) = minType; } - - if (options.applyFilter) { - enum Filter type = options.applyFilters[y % options.applyFilter]; - memcpy(lines[y]->data, filter[type], lineSize()); + if (applyFilter) { + memcpy(lineData(y), filter[applyFilters[y % applyFilter]], lineLen); } else { - memcpy(lines[y]->data, filter[minType], lineSize()); + memcpy(lineData(y), filter[minType], lineLen); } } -} - -static void invert(void) { - for (uint32_t y = 0; y < header.height; ++y) { - for (size_t i = 0; i < lineSize(); ++i) { - lines[y]->data[i] ^= 0xFF; - } - } -} - -static void mirror(void) { - for (uint32_t y = 0; y < header.height; ++y) { - for (size_t i = 0, j = lineSize() - 1; i < j; ++i, --j) { - uint8_t t = lines[y]->data[i]; - lines[y]->data[i] = lines[y]->data[j]; - lines[y]->data[j] = t; - } + for (enum Filter i = None; i < FilterCap; ++i) { + free(filter[i]); } } -static void zeroX(void) { - for (uint32_t y = 0; y < header.height; ++y) { - memset(lines[y]->data, 0, pixelSize()); - } -} - -static void zeroY(void) { - memset(lines[0]->data, 0, lineSize()); -} +static bool invertData; +static bool mirrorData; +static bool zeroX; +static bool zeroY; static void glitch(const char *inPath, const char *outPath) { if (inPath) { path = inPath; file = fopen(path, "r"); - if (!file) err(EX_NOINPUT, "%s", path); + if (!file) err(1, "%s", path); } else { - path = "(stdin)"; + path = "stdin"; file = stdin; } - readSignature(); - readHeader(); - if (header.color == Indexed) readPalette(); - readData(); + sigRead(); + struct Chunk ihdr = chunkRead(); + if (strcmp(ihdr.type, "IHDR")) { + errx(1, "%s: expected IHDR, found %s", path, ihdr.type); + } + headerRead(ihdr); + if (header.interlace != Progressive) { + errx(1, "%s: unsupported interlacing", path); + } + + palClear(); + dataAlloc(); + for (;;) { + struct Chunk chunk = chunkRead(); + if (!strcmp(chunk.type, "PLTE")) { + palRead(chunk); + } else if (!strcmp(chunk.type, "tRNS")) { + transRead(chunk); + } else if (!strcmp(chunk.type, "IDAT")) { + dataRead(chunk); + } else if (!strcmp(chunk.type, "IEND")) { + break; + } else { + chunkSkip(chunk); + } + } fclose(file); - scanlines(); - reconData(); - filterData(); - if (options.invert) invert(); - if (options.mirror) mirror(); - if (options.zeroX) zeroX(); - if (options.zeroY) zeroY(); - free(lines); + dataRecon(); + dataFilter(); + + if (invertData) { + for (uint32_t y = 0; y < header.height; ++y) { + for (size_t i = 0; i < lineLen; ++i) { + lineData(y)[i] ^= 0xFF; + } + } + } + if (mirrorData) { + for (uint32_t y = 0; y < header.height; ++y) { + for (size_t i = 0, j = lineLen-1; i < j; ++i, --j) { + uint8_t x = lineData(y)[i]; + lineData(y)[i] = lineData(y)[j]; + lineData(y)[j] = x; + } + } + } + if (zeroX) { + for (uint32_t y = 0; y < header.height; ++y) { + memset(lineData(y), 0, pixelLen); + } + } + if (zeroY) { + memset(lineData(0), 0, lineLen); + } + char buf[PATH_MAX]; if (outPath) { path = outPath; - file = fopen(path, "w"); - if (!file) err(EX_CANTCREAT, "%s", path); + if (outPath == inPath) { + snprintf(buf, sizeof(buf), "%sg", outPath); + file = fopen(buf, "wx"); + if (!file) err(1, "%s", buf); + } else { + file = fopen(path, "w"); + if (!file) err(1, "%s", outPath); + } } else { - path = "(stdout)"; + path = "stdout"; file = stdout; } - writeSignature(); - writeHeader(); - if (header.color == Indexed) writePalette(); - writeData(); - writeEnd(); + sigWrite(); + headerWrite(); + if (header.color == Indexed) { + palWrite(); + if (trans.len) transWrite(); + } + dataWrite(); free(data); - int error = fclose(file); - if (error) err(EX_IOERR, "%s", path); + if (error) err(1, "%s", path); + + if (outPath && outPath == inPath) { + error = rename(buf, outPath); + if (error) err(1, "%s", outPath); + } } -static enum Filter parseFilter(const char *s) { - switch (s[0]) { +static enum Filter parseFilter(const char *str) { + switch (str[0]) { case 'N': case 'n': return None; case 'S': case 's': return Sub; case 'U': case 'u': return Up; case 'A': case 'a': return Average; case 'P': case 'p': return Paeth; - default: errx(EX_USAGE, "invalid filter type %s", s); + default: errx(1, "invalid filter type %s", str); } } -static uint8_t parseFilters(enum Filter *filters, const char *s) { - uint8_t len = 0; - do { - filters[len++] = parseFilter(s); - s = strchr(s, ','); - } while (s++); +static size_t parseFilters(enum Filter *filters, char *str) { + size_t len = 0; + while (str) { + char *filt = strsep(&str, ","); + filters[len++] = parseFilter(filt); + } return len; } int main(int argc, char *argv[]) { bool stdio = false; - char *output = NULL; + char *outPath = NULL; - int opt; - while (0 < (opt = getopt(argc, argv, "a:cd:fimo:prxy"))) { + for (int opt; 0 < (opt = getopt(argc, argv, "a:cd:fimo:prxy"));) { switch (opt) { - break; case 'a': - options.applyFilter = parseFilters(options.applyFilters, optarg); + break; case 'a': applyFilter = parseFilters(applyFilters, optarg); break; case 'c': stdio = true; - break; case 'd': - options.declareFilter = parseFilters(options.declareFilters, optarg); - break; case 'f': options.filt = true; - break; case 'i': options.invert = true; - break; case 'm': options.mirror = true; - break; case 'o': output = optarg; - break; case 'p': options.brokenPaeth = true; - break; case 'r': options.recon = true; - break; case 'x': options.zeroX = true; - break; case 'y': options.zeroY = true; - break; default: return EX_USAGE; + break; case 'd': declFilter = parseFilters(declFilters, optarg); + break; case 'f': reconFilter = true; + break; case 'i': invertData = true; + break; case 'm': mirrorData = true; + break; case 'o': outPath = optarg; + break; case 'p': brokenPaeth = true; + break; case 'r': filterRecon = true; + break; case 'x': zeroX = true; + break; case 'y': zeroY = true; + break; default: return 1; } } - if (argc - optind == 1 && (output || stdio)) { - glitch(argv[optind], output); - } else if (optind < argc) { + if (optind < argc) { for (int i = optind; i < argc; ++i) { - glitch(argv[i], argv[i]); + glitch(argv[i], (stdio ? NULL : outPath ? outPath : argv[i])); } } else { - glitch(NULL, output); + glitch(NULL, outPath); } - - return EX_OK; } diff --git a/bin/hilex.c b/bin/hilex.c index 0bcc5c7f..81485ab2 100644 --- a/bin/hilex.c +++ b/bin/hilex.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 C. McEnroe <june@causal.agency> +/* Copyright (C) 2020 June McEnroe <june@causal.agency> * * 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 @@ -23,7 +23,6 @@ #include <stdlib.h> #include <string.h> #include <sys/wait.h> -#include <sysexits.h> #include <unistd.h> #include "hilex.h" @@ -53,7 +52,7 @@ static const struct { { &LexC, "c", "[.][chlmy]$", NULL }, { &LexMake, "make", "[.](mk|am)$|^Makefile$", NULL }, { &LexMdoc, "mdoc", "[.][1-9]$", "^[.]Dd" }, - { &LexSh, "sh", "[.]sh$|^[.](profile|shrc)$", "^#![ ]?/bin/sh" }, + { &LexSh, "sh", "[.]sh$|^[.](profile|shrc)$", "^#![ ]?/bin/k?sh" }, { &LexText, "text", "[.]txt$", NULL }, }; @@ -61,14 +60,14 @@ static const struct Lexer *parseLexer(const char *name) { for (size_t i = 0; i < ARRAY_LEN(Lexers); ++i) { if (!strcmp(name, Lexers[i].name)) return Lexers[i].lexer; } - errx(EX_USAGE, "unknown lexer %s", name); + errx(1, "unknown lexer %s", name); } static void ungets(const char *str, FILE *file) { size_t len = strlen(str); for (size_t i = len-1; i < len; --i) { int ch = ungetc(str[i], file); - if (ch == EOF) errx(EX_IOERR, "cannot push back string"); + if (ch == EOF) errx(1, "cannot push back string"); } } @@ -134,16 +133,16 @@ static void ansiHeader(const char *opts[]) { int rw[2]; int error = pipe(rw); - if (error) err(EX_OSERR, "pipe"); + if (error) err(1, "pipe"); pid_t pid = fork(); - if (pid < 0) err(EX_OSERR, "fork"); + if (pid < 0) err(1, "fork"); if (!pid) { dup2(rw[0], STDIN_FILENO); close(rw[0]); close(rw[1]); execl(shell, shell, "-c", pager, NULL); - err(EX_CONFIG, "%s", shell); + err(127, "%s", shell); } dup2(rw[1], STDOUT_FILENO); close(rw[0]); @@ -152,7 +151,7 @@ static void ansiHeader(const char *opts[]) { #ifdef __OpenBSD__ error = pledge("stdio", NULL); - if (error) err(EX_OSERR, "pledge"); + if (error) err(1, "pledge"); #endif } @@ -330,7 +329,7 @@ static const struct Formatter *parseFormatter(const char *name) { for (size_t i = 0; i < ARRAY_LEN(Formatters); ++i) { if (!strcmp(name, Formatters[i].name)) return &Formatters[i]; } - errx(EX_USAGE, "unknown formatter %s", name); + errx(1, "unknown formatter %s", name); } static char *const OptionKeys[OptionCap + 1] = { @@ -356,12 +355,12 @@ int main(int argc, char *argv[]) { while (*optarg) { char *val; int key = getsubopt(&optarg, OptionKeys, &val); - if (key < 0) errx(EX_USAGE, "no such option %s", val); + if (key < 0) errx(1, "no such option %s", val); opts[key] = (val ? val : ""); } } break; case 't': text = true; - break; default: return EX_USAGE; + break; default: return 1; } } @@ -370,7 +369,7 @@ int main(int argc, char *argv[]) { if (optind < argc) { path = argv[optind]; file = fopen(path, "r"); - if (!file) err(EX_NOINPUT, "%s", path); + if (!file) err(1, "%s", path); pager = isatty(STDOUT_FILENO); } @@ -381,7 +380,7 @@ int main(int argc, char *argv[]) { } else { error = pledge("stdio", NULL); } - if (error) err(EX_OSERR, "pledge"); + if (error) err(1, "pledge"); #endif if (!name) { @@ -394,7 +393,7 @@ int main(int argc, char *argv[]) { if (!opts[Title]) opts[Title] = name; if (!lexer) lexer = matchLexer(name, file); if (!lexer && text) lexer = &LexText; - if (!lexer) errx(EX_USAGE, "cannot infer lexer for %s", name); + if (!lexer) errx(1, "cannot infer lexer for %s", name); *lexer->in = file; if (formatter->header) formatter->header(opts); diff --git a/bin/hilex.h b/bin/hilex.h index 882b5f95..b57fc8cc 100644 --- a/bin/hilex.h +++ b/bin/hilex.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 C. McEnroe <june@causal.agency> +/* Copyright (C) 2020 June McEnroe <june@causal.agency> * * 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 diff --git a/bin/htagml.c b/bin/htagml.c index 1f547be6..c35cdb15 100644 --- a/bin/htagml.c +++ b/bin/htagml.c @@ -20,12 +20,11 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sysexits.h> #include <unistd.h> static char *deregex(const char *patt) { char *buf = malloc(strlen(patt) + 1); - if (!buf) err(EX_OSERR, "malloc"); + if (!buf) err(1, "malloc"); char *ptr = buf; if (*patt == '^') patt++; for (; *patt; ++patt) { @@ -94,21 +93,21 @@ int main(int argc, char *argv[]) { break; case 'm': main = true; break; case 'p': pre = true; break; case 'x': index = true; - break; default: return EX_USAGE; + break; default: return 1; } } - if (optind == argc) errx(EX_USAGE, "name required"); + if (optind == argc) errx(1, "name required"); const char *name = argv[optind]; FILE *file = fopen(name, "r"); - if (!file) err(EX_NOINPUT, "%s", name); + if (!file) err(1, "%s", name); FILE *tagsFile = fopen(tagsPath, "r"); - if (!tagsFile) err(EX_NOINPUT, "%s", tagsPath); + if (!tagsFile) err(1, "%s", tagsPath); #ifdef __OpenBSD__ int error = pledge("stdio", NULL); - if (error) err(EX_OSERR, "pledge"); + if (error) err(1, "pledge"); #endif size_t len = 0; @@ -119,7 +118,7 @@ int main(int argc, char *argv[]) { char *str; size_t len; } *tags = malloc(cap * sizeof(*tags)); - if (!tags) err(EX_OSERR, "malloc"); + if (!tags) err(1, "malloc"); char *buf = NULL; size_t bufCap = 0; @@ -128,15 +127,15 @@ int main(int argc, char *argv[]) { char *tag = strsep(&line, "\t"); char *file = strsep(&line, "\t"); char *def = strsep(&line, "\n"); - if (!tag || !file || !def) errx(EX_DATAERR, "malformed tags file"); + if (!tag || !file || !def) errx(1, "malformed tags file"); if (strcmp(file, name)) continue; if (len == cap) { tags = realloc(tags, (cap *= 2) * sizeof(*tags)); - if (!tags) err(EX_OSERR, "realloc"); + if (!tags) err(1, "realloc"); } tags[len].tag = strdup(tag); - if (!tags[len].tag) err(EX_OSERR, "strdup"); + if (!tags[len].tag) err(1, "strdup"); tags[len].num = 0; if (def[0] == '/' || def[0] == '?') { @@ -184,7 +183,7 @@ int main(int argc, char *argv[]) { if (pipe) { ssize_t len = getline(&buf, &bufCap, stdin); if (len < 0) { - errx(EX_DATAERR, "missing line %d on standard input", num); + errx(1, "missing line %d on standard input", num); } } if (!tag) { diff --git a/bin/make.l b/bin/make.l index ae1be2f5..6296716d 100644 --- a/bin/make.l +++ b/bin/make.l @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 C. McEnroe <june@causal.agency> +/* Copyright (C) 2020 June McEnroe <june@causal.agency> * * 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 diff --git a/bin/man1/up.1 b/bin/man1/up.1 index 2240b99a..aece79bd 100644 --- a/bin/man1/up.1 +++ b/bin/man1/up.1 @@ -1,4 +1,4 @@ -.Dd June 21, 2021 +.Dd July 26, 2022 .Dt UP 1 .Os . @@ -8,15 +8,9 @@ . .Sh SYNOPSIS .Nm -.Op Fl h -.Op Ar file -. -.Nm -.Fl c | t -.Ar command -. -.Nm -.Fl s +.Op Fl c | h | s | t +.Op Fl w Ar warn +.Op Ar file | command . .Sh DESCRIPTION .Nm @@ -65,6 +59,10 @@ Run a command with and .Xr shotty 1 to produce an HTML file for upload. +.It Fl w Ar warn +Create an HTML redirect with +.Ar warn +in its title. .El . .Pp diff --git a/bin/man1/when.1 b/bin/man1/when.1 index 0b473573..3f2735f7 100644 --- a/bin/man1/when.1 +++ b/bin/man1/when.1 @@ -1,4 +1,4 @@ -.Dd July 24, 2019 +.Dd September 19, 2022 .Dt WHEN 1 .Os . @@ -9,6 +9,8 @@ .Sh SYNOPSIS .Nm .Op Ar expr +.Nm +.Cm - . .Sh DESCRIPTION .Nm @@ -18,24 +20,32 @@ If no is given, expressions are read from standard input. +If +.Cm - +is given, +the intervals between each named date +and today are printed. . .Pp The grammar is as follows: .Bl -tag -width Ds .It Sy \&. Today's date. +The empty expression is equivalent. +. +.It Ar name Op Sy = Ar date +A named date. +Names are alphanumeric including underscores. . .It Ar month Ar date Op Ar year A full date, or a date in the current year. -.Ar month -must be at least three letters. +Months can be abbreviated to three letters. . .It Ar day A day of the week in the current week. -.Ar day -must be at least three letters. +Days can be abbreviated to three letters. . .It Sy < Ar date The date one week before. @@ -65,6 +75,14 @@ A number of months. A number of years. .El . +.Sh FILES +The file +.Pa $XDG_CONFIG_HOME/when/dates +or +.Pa ~/.config/when/dates +is read before any other expressions, +if it exists. +. .Sh EXAMPLES .Bl -tag -width "Dec 25 - ." .It Ic Dec 25 - \&. @@ -74,3 +92,9 @@ The date next Friday. .It Ic \&. + 2w Your last day at work. .El +.Pp +Checking a milestone: +.Bd -literal -offset indent +$ echo 'hrt = oct 15 2021' >> ~/.config/when/dates +$ when -hrt +.Ed diff --git a/bin/mdoc.l b/bin/mdoc.l index f29b6ceb..b6deacbe 100644 --- a/bin/mdoc.l +++ b/bin/mdoc.l @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 C. McEnroe <june@causal.agency> +/* Copyright (C) 2020 June McEnroe <june@causal.agency> * * 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 diff --git a/bin/modem.c b/bin/modem.c index 2133ae08..75517159 100644 --- a/bin/modem.c +++ b/bin/modem.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 C. McEnroe <june@causal.agency> +/* Copyright (C) 2018 June McEnroe <june@causal.agency> * * 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 @@ -19,7 +19,6 @@ #include <stdlib.h> #include <sys/ioctl.h> #include <sys/wait.h> -#include <sysexits.h> #include <termios.h> #include <unistd.h> @@ -46,31 +45,31 @@ int main(int argc, char *argv[]) { for (int opt; 0 < (opt = getopt(argc, argv, "r:"));) { switch (opt) { break; case 'r': baudRate = strtoul(optarg, NULL, 10); - break; default: return EX_USAGE; + break; default: return 1; } } - if (argc - optind < 1) return EX_USAGE; + if (argc - optind < 1) return 1; error = tcgetattr(STDIN_FILENO, &saveTerm); - if (error) err(EX_IOERR, "tcgetattr"); + if (error) err(1, "tcgetattr"); atexit(restoreTerm); struct termios raw = saveTerm; cfmakeraw(&raw); error = tcsetattr(STDIN_FILENO, TCSADRAIN, &raw); - if (error) err(EX_IOERR, "tcsetattr"); + if (error) err(1, "tcsetattr"); struct winsize window; error = ioctl(STDIN_FILENO, TIOCGWINSZ, &window); - if (error) err(EX_IOERR, "TIOCGWINSZ"); + if (error) err(1, "TIOCGWINSZ"); int pty; pid_t pid = forkpty(&pty, NULL, NULL, &window); - if (pid < 0) err(EX_OSERR, "forkpty"); + if (pid < 0) err(1, "forkpty"); if (!pid) { execvp(argv[optind], &argv[optind]); - err(EX_NOINPUT, "%s", argv[optind]); + err(1, "%s", argv[optind]); } byte c; @@ -81,22 +80,22 @@ int main(int argc, char *argv[]) { while (usleep(8 * 1000000 / baudRate), 0 < poll(fds, 2, -1)) { if (fds[0].revents) { ssize_t size = read(STDIN_FILENO, &c, 1); - if (size < 0) err(EX_IOERR, "read(%d)", STDIN_FILENO); + if (size < 0) err(1, "read(%d)", STDIN_FILENO); size = write(pty, &c, 1); - if (size < 0) err(EX_IOERR, "write(%d)", pty); + if (size < 0) err(1, "write(%d)", pty); } if (fds[1].revents) { ssize_t size = read(pty, &c, 1); - if (size < 0) err(EX_IOERR, "read(%d)", pty); + if (size < 0) err(1, "read(%d)", pty); if (!size) break; size = write(STDOUT_FILENO, &c, 1); - if (size < 0) err(EX_IOERR, "write(%d)", STDOUT_FILENO); + if (size < 0) err(1, "write(%d)", STDOUT_FILENO); } } int status; pid_t dead = waitpid(pid, &status, 0); - if (dead < 0) err(EX_OSERR, "waitpid"); - return WIFEXITED(status) ? WEXITSTATUS(status) : EX_SOFTWARE; + if (dead < 0) err(1, "waitpid"); + return WIFEXITED(status) ? WEXITSTATUS(status) : 1; } diff --git a/bin/mtags.c b/bin/mtags.c index 11cd9c8a..5c42f343 100644 --- a/bin/mtags.c +++ b/bin/mtags.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 C. McEnroe <june@causal.agency> +/* Copyright (C) 2021 June McEnroe <june@causal.agency> * * 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 @@ -21,7 +21,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sysexits.h> #include <unistd.h> static void escape(FILE *file, const char *str, size_t len) { @@ -41,16 +40,16 @@ int main(int argc, char *argv[]) { switch (opt) { break; case 'a': append = true; break; case 'f': path = optarg; - break; default: return EX_USAGE; + break; default: return 1; } } FILE *tags = fopen(path, (append ? "a" : "w")); - if (!tags) err(EX_CANTCREAT, "%s", path); + if (!tags) err(1, "%s", path); #ifdef __OpenBSD__ error = pledge("stdio rpath", NULL); - if (error) err(EX_OSERR, "pledge"); + if (error) err(1, "pledge"); #endif regex_t makeFile, makeLine; @@ -87,7 +86,7 @@ int main(int argc, char *argv[]) { } FILE *file = fopen(argv[i], "r"); - if (!file) err(EX_NOINPUT, "%s", argv[i]); + if (!file) err(1, "%s", argv[i]); while (0 < getline(&buf, &cap, file)) { regmatch_t match[2]; diff --git a/bin/nudge.c b/bin/nudge.c index 108d2459..c6247b87 100644 --- a/bin/nudge.c +++ b/bin/nudge.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 C. McEnroe <june@causal.agency> +/* Copyright (C) 2020 June McEnroe <june@causal.agency> * * 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 @@ -18,7 +18,6 @@ #include <fcntl.h> #include <stdio.h> #include <stdlib.h> -#include <sysexits.h> #include <termios.h> #include <unistd.h> @@ -39,21 +38,21 @@ int main(int argc, char *argv[]) { break; case 'n': count = atoi(optarg); break; case 's': shake = atoi(optarg); break; case 't': delay = atoi(optarg) * 1000; - break; default: return EX_USAGE; + break; default: return 1; } } int tty = open(path, O_RDWR); - if (tty < 0) err(EX_OSFILE, "%s", path); + if (tty < 0) err(1, "%s", path); struct termios save; int error = tcgetattr(tty, &save); - if (error) err(EX_IOERR, "tcgetattr"); + if (error) err(1, "tcgetattr"); struct termios raw = save; cfmakeraw(&raw); error = tcsetattr(tty, TCSAFLUSH, &raw); - if (error) err(EX_IOERR, "tcsetattr"); + if (error) err(1, "tcsetattr"); char buf[256]; dprintf(tty, "\33[13t"); @@ -64,8 +63,8 @@ int main(int argc, char *argv[]) { int n = sscanf(buf, "\33[3;%d;%dt", &x, &y); error = tcsetattr(tty, TCSANOW, &save); - if (error) err(EX_IOERR, "tcsetattr"); - if (n < 2) return EX_CONFIG; + if (error) err(1, "tcsetattr"); + if (n < 2) return 1; dprintf(tty, "\33[5t"); for (int i = 0; i < count; ++i) { diff --git a/bin/order.y b/bin/order.y index c2e87971..05be9838 100644 --- a/bin/order.y +++ b/bin/order.y @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 C. McEnroe <june@causal.agency> +/* Copyright (C) 2019 June McEnroe <june@causal.agency> * * 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 @@ -22,7 +22,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sysexits.h> #define YYSTYPE char * @@ -32,7 +31,7 @@ static char *fmt(const char *format, ...) { va_start(ap, format); vasprintf(&str, format, ap); va_end(ap); - if (!str) err(EX_OSERR, "vasprintf"); + if (!str) err(1, "vasprintf"); return str; } @@ -179,17 +178,17 @@ static int yylex(void) { } static void yyerror(const char *str) { - errx(EX_DATAERR, "%s", str); + errx(1, "%s", str); } int main(int argc, char *argv[]) { for (int i = 1; i < argc; ++i) { in = fmemopen(argv[i], strlen(argv[i]), "r"); - if (!in) err(EX_OSERR, "fmemopen"); + if (!in) err(1, "fmemopen"); yyparse(); fclose(in); } - if (argc > 1) return EX_OK; + if (argc > 1) return 0; in = stdin; yyparse(); } diff --git a/bin/pbd.c b/bin/pbd.c index 2fd401ae..8375fc38 100644 --- a/bin/pbd.c +++ b/bin/pbd.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 C. McEnroe <june@causal.agency> +/* Copyright (C) 2017 June McEnroe <june@causal.agency> * * 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 @@ -24,27 +24,26 @@ #include <string.h> #include <sys/socket.h> #include <sys/wait.h> -#include <sysexits.h> #include <unistd.h> typedef unsigned char byte; static void spawn(const char *cmd, const char *arg, int dest, int src) { pid_t pid = fork(); - if (pid < 0) err(EX_OSERR, "fork"); + if (pid < 0) err(1, "fork"); if (pid) { int status; pid_t dead = waitpid(pid, &status, 0); - if (dead < 0) err(EX_OSERR, "waitpid(%d)", pid); + if (dead < 0) err(1, "waitpid(%d)", pid); if (status) warnx("%s: status %d", cmd, status); } else { int fd = dup2(src, dest); - if (fd < 0) err(EX_OSERR, "dup2"); + if (fd < 0) err(1, "dup2"); execlp(cmd, cmd, arg, NULL); - err(EX_UNAVAILABLE, "%s", cmd); + err(127, "%s", cmd); } } @@ -52,10 +51,10 @@ static int pbd(void) { int error; int server = socket(PF_INET, SOCK_STREAM, 0); - if (server < 0) err(EX_OSERR, "socket"); + if (server < 0) err(1, "socket"); error = fcntl(server, F_SETFD, FD_CLOEXEC); - if (error) err(EX_IOERR, "fcntl"); + if (error) err(1, "fcntl"); struct sockaddr_in addr = { .sin_family = AF_INET, @@ -63,17 +62,17 @@ static int pbd(void) { .sin_addr = { .s_addr = htonl(0x7F000001) }, }; error = bind(server, (struct sockaddr *)&addr, sizeof(addr)); - if (error) err(EX_UNAVAILABLE, "bind"); + if (error) err(1, "bind"); error = listen(server, 0); - if (error) err(EX_UNAVAILABLE, "listen"); + if (error) err(1, "listen"); for (;;) { int client = accept(server, NULL, NULL); - if (client < 0) err(EX_IOERR, "accept"); + if (client < 0) err(1, "accept"); error = fcntl(client, F_SETFD, FD_CLOEXEC); - if (error) err(EX_IOERR, "fcntl"); + if (error) err(1, "fcntl"); char c = 0; ssize_t size = read(client, &c, 1); @@ -91,7 +90,7 @@ static int pbd(void) { static int pbdClient(char c) { int client = socket(PF_INET, SOCK_STREAM, 0); - if (client < 0) err(EX_OSERR, "socket"); + if (client < 0) err(1, "socket"); struct sockaddr_in addr = { .sin_family = AF_INET, @@ -99,10 +98,10 @@ static int pbdClient(char c) { .sin_addr = { .s_addr = htonl(0x7F000001) }, }; int error = connect(client, (struct sockaddr *)&addr, sizeof(addr)); - if (error) err(EX_UNAVAILABLE, "connect"); + if (error) err(1, "connect"); ssize_t size = write(client, &c, 1); - if (size < 0) err(EX_IOERR, "write"); + if (size < 0) err(1, "write"); return client; } @@ -112,29 +111,29 @@ static void copy(int out, int in) { ssize_t readSize; while (0 < (readSize = read(in, buf, sizeof(buf)))) { ssize_t writeSize = write(out, buf, readSize); - if (writeSize < 0) err(EX_IOERR, "write(%d)", out); + if (writeSize < 0) err(1, "write(%d)", out); } - if (readSize < 0) err(EX_IOERR, "read(%d)", in); + if (readSize < 0) err(1, "read(%d)", in); } static int pbcopy(void) { int client = pbdClient('c'); copy(client, STDIN_FILENO); - return EX_OK; + return 0; } static int pbpaste(void) { int client = pbdClient('p'); copy(STDOUT_FILENO, client); - return EX_OK; + return 0; } static int open1(const char *url) { - if (!url) return EX_USAGE; + if (!url) return 1; int client = pbdClient('o'); ssize_t size = write(client, url, strlen(url)); - if (size < 0) err(EX_IOERR, "write"); - return EX_OK; + if (size < 0) err(1, "write"); + return 0; } int main(int argc, char *argv[]) { @@ -144,7 +143,7 @@ int main(int argc, char *argv[]) { case 'o': return open1(optarg); case 'p': return pbpaste(); case 's': return pbd(); - default: return EX_USAGE; + default: return 1; } } return pbd(); diff --git a/bin/png.h b/bin/png.h index 15b6d13d..ec884395 100644 --- a/bin/png.h +++ b/bin/png.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 C. McEnroe <june@causal.agency> +/* Copyright (C) 2018 June McEnroe <june@causal.agency> * * 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 @@ -18,7 +18,6 @@ #include <stdint.h> #include <stdio.h> #include <stdlib.h> -#include <sysexits.h> static inline uint32_t pngCRCTable(uint8_t n) { static uint32_t table[256]; @@ -35,7 +34,7 @@ static inline uint32_t pngCRCTable(uint8_t n) { static uint32_t pngCRC; static inline void pngWrite(FILE *file, const uint8_t *ptr, uint32_t len) { - if (!fwrite(ptr, len, 1, file)) err(EX_IOERR, "pngWrite"); + if (!fwrite(ptr, len, 1, file)) err(1, "pngWrite"); for (uint32_t i = 0; i < len; ++i) { pngCRC = pngCRCTable(pngCRC ^ ptr[i]) ^ (pngCRC >> 8); } diff --git a/bin/pngo.c b/bin/pngo.c index ba90889a..e2ad3837 100644 --- a/bin/pngo.c +++ b/bin/pngo.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2018, 2021 C. McEnroe <june@causal.agency> +/* Copyright (C) 2018, 2021 June McEnroe <june@causal.agency> * * 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 @@ -22,7 +22,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sysexits.h> #include <unistd.h> #include <zlib.h> @@ -35,14 +34,14 @@ static uint32_t crc; static void pngRead(void *ptr, size_t len, const char *desc) { size_t n = fread(ptr, len, 1, file); - if (!n && ferror(file)) err(EX_IOERR, "%s", path); - if (!n) errx(EX_DATAERR, "%s: missing %s", path, desc); + if (!n && ferror(file)) err(1, "%s", path); + if (!n) errx(1, "%s: missing %s", path, desc); crc = crc32(crc, ptr, len); } static void pngWrite(const void *ptr, size_t len) { size_t n = fwrite(ptr, len, 1, file); - if (!n) err(EX_IOERR, "%s", path); + if (!n) err(1, "%s", path); crc = crc32(crc, ptr, len); } @@ -52,7 +51,7 @@ static void sigRead(void) { uint8_t sig[sizeof(Sig)]; pngRead(sig, sizeof(sig), "signature"); if (memcmp(sig, Sig, sizeof(sig))) { - errx(EX_DATAERR, "%s: invalid signature", path); + errx(1, "%s: invalid signature", path); } } @@ -96,10 +95,7 @@ static void crcRead(void) { uint32_t expect = crc; uint32_t actual = u32Read("CRC32"); if (actual == expect) return; - errx( - EX_DATAERR, "%s: expected CRC32 %08X, found %08X", - path, expect, actual - ); + errx(1, "%s: expected CRC32 %08X, found %08X", path, expect, actual); } static void crcWrite(void) { @@ -108,7 +104,7 @@ static void crcWrite(void) { static void chunkSkip(struct Chunk chunk) { if (!(chunk.type[0] & 0x20)) { - errx(EX_CONFIG, "%s: unsupported critical chunk %s", path, chunk.type); + errx(1, "%s: unsupported critical chunk %s", path, chunk.type); } uint8_t buf[4096]; while (chunk.len > sizeof(buf)) { @@ -181,7 +177,7 @@ static void headerPrint(void) { static void headerRead(struct Chunk chunk) { if (chunk.len != HeaderLen) { errx( - EX_DATAERR, "%s: expected %s length %" PRIu32 ", found %" PRIu32, + 1, "%s: expected %s length %" PRIu32 ", found %" PRIu32, path, chunk.type, (uint32_t)HeaderLen, chunk.len ); } @@ -195,8 +191,8 @@ static void headerRead(struct Chunk chunk) { crcRead(); recalc(); - if (!header.width) errx(EX_DATAERR, "%s: invalid width 0", path); - if (!header.height) errx(EX_DATAERR, "%s: invalid height 0", path); + if (!header.width) errx(1, "%s: invalid width 0", path); + if (!header.height) errx(1, "%s: invalid height 0", path); static const struct { uint8_t color; uint8_t depth; @@ -228,28 +224,21 @@ static void headerRead(struct Chunk chunk) { } if (!valid) { errx( - EX_DATAERR, - "%s: invalid color type %" PRIu8 " and bit depth %" PRIu8, + 1, "%s: invalid color type %" PRIu8 " and bit depth %" PRIu8, path, header.color, header.depth ); } if (header.compression != Deflate) { errx( - EX_DATAERR, "%s: invalid compression method %" PRIu8, + 1, "%s: invalid compression method %" PRIu8, path, header.compression ); } if (header.filter != Adaptive) { - errx( - EX_DATAERR, "%s: invalid filter method %" PRIu8, - path, header.filter - ); + errx(1, "%s: invalid filter method %" PRIu8, path, header.filter); } if (header.interlace > Adam7) { - errx( - EX_DATAERR, "%s: invalid interlace method %" PRIu8, - path, header.interlace - ); + errx(1, "%s: invalid interlace method %" PRIu8, path, header.interlace); } if (verbose) headerPrint(); @@ -331,16 +320,13 @@ static void transCompact(void) { static void palRead(struct Chunk chunk) { if (chunk.len % 3) { errx( - EX_DATAERR, "%s: %s length %" PRIu32 " not divisible by 3", + 1, "%s: %s length %" PRIu32 " not divisible by 3", path, chunk.type, chunk.len ); } pal.len = chunk.len / 3; if (pal.len > 256) { - errx( - EX_DATAERR, "%s: %s length %" PRIu32 " > 256", - path, chunk.type, pal.len - ); + errx(1, "%s: %s length %" PRIu32 " > 256", path, chunk.type, pal.len); } pngRead(pal.rgb, chunk.len, "palette data"); crcRead(); @@ -362,10 +348,7 @@ static void palWrite(void) { static void transRead(struct Chunk chunk) { trans.len = chunk.len; if (trans.len > 256) { - errx( - EX_DATAERR, "%s: %s length %" PRIu32 " > 256", - path, chunk.type, trans.len - ); + errx(1, "%s: %s length %" PRIu32 " > 256", path, chunk.type, trans.len); } pngRead(trans.a, chunk.len, "transparency data"); crcRead(); @@ -388,7 +371,7 @@ static uint8_t *data; static void dataAlloc(void) { data = malloc(dataLen); - if (!data) err(EX_OSERR, "malloc"); + if (!data) err(1, "malloc"); } static const char *humanize(size_t n) { @@ -408,15 +391,15 @@ static void dataRead(struct Chunk chunk) { z_stream stream = { .next_out = data, .avail_out = dataLen }; int error = inflateInit(&stream); - if (error != Z_OK) errx(EX_SOFTWARE, "inflateInit: %s", stream.msg); + if (error != Z_OK) errx(1, "inflateInit: %s", stream.msg); for (;;) { if (strcmp(chunk.type, "IDAT")) { - errx(EX_DATAERR, "%s: missing IDAT chunk", path); + errx(1, "%s: missing IDAT chunk", path); } uint8_t *idat = malloc(chunk.len); - if (!idat) err(EX_OSERR, "malloc"); + if (!idat) err(1, "malloc"); pngRead(idat, chunk.len, "image data"); crcRead(); @@ -428,7 +411,7 @@ static void dataRead(struct Chunk chunk) { if (error == Z_STREAM_END) break; if (error != Z_OK) { - errx(EX_DATAERR, "%s: inflate: %s", path, stream.msg); + errx(1, "%s: inflate: %s", path, stream.msg); } chunk = chunkRead(); @@ -436,7 +419,7 @@ static void dataRead(struct Chunk chunk) { inflateEnd(&stream); if ((size_t)stream.total_out != dataLen) { errx( - EX_DATAERR, "%s: expected data length %zu, found %zu", + 1, "%s: expected data length %zu, found %zu", path, dataLen, (size_t)stream.total_out ); } @@ -461,11 +444,11 @@ static void dataWrite(void) { int error = deflateInit2( &stream, Z_BEST_COMPRESSION, Z_DEFLATED, 15, 8, Z_FILTERED ); - if (error != Z_OK) errx(EX_SOFTWARE, "deflateInit2: %s", stream.msg); + if (error != Z_OK) errx(1, "deflateInit2: %s", stream.msg); uLong bound = deflateBound(&stream, dataLen); uint8_t *buf = malloc(bound); - if (!buf) err(EX_OSERR, "malloc"); + if (!buf) err(1, "malloc"); stream.next_out = buf; stream.avail_out = bound; @@ -566,7 +549,7 @@ static void dataFilter(void) { uint8_t *filter[FilterCap]; for (enum Filter i = None; i < FilterCap; ++i) { filter[i] = malloc(lineLen); - if (!filter[i]) err(EX_OSERR, "malloc"); + if (!filter[i]) err(1, "malloc"); } for (uint32_t y = header.height-1; y < header.height; --y) { uint32_t heuristic[FilterCap] = {0}; @@ -838,7 +821,7 @@ static void optimize(const char *inPath, const char *outPath) { if (inPath) { path = inPath; file = fopen(path, "r"); - if (!file) err(EX_NOINPUT, "%s", path); + if (!file) err(1, "%s", path); } else { path = "stdin"; file = stdin; @@ -847,11 +830,11 @@ static void optimize(const char *inPath, const char *outPath) { sigRead(); struct Chunk ihdr = chunkRead(); if (strcmp(ihdr.type, "IHDR")) { - errx(EX_DATAERR, "%s: expected IHDR, found %s", path, ihdr.type); + errx(1, "%s: expected IHDR, found %s", path, ihdr.type); } headerRead(ihdr); if (header.interlace != Progressive) { - errx(EX_CONFIG, "%s: unsupported interlacing", path); + errx(1, "%s: unsupported interlacing", path); } palClear(); @@ -888,10 +871,10 @@ static void optimize(const char *inPath, const char *outPath) { if (outPath == inPath) { snprintf(buf, sizeof(buf), "%so", outPath); file = fopen(buf, "wx"); - if (!file) err(EX_CANTCREAT, "%s", buf); + if (!file) err(1, "%s", buf); } else { file = fopen(path, "w"); - if (!file) err(EX_CANTCREAT, "%s", outPath); + if (!file) err(1, "%s", outPath); } } else { path = "stdout"; @@ -907,11 +890,11 @@ static void optimize(const char *inPath, const char *outPath) { dataWrite(); free(data); int error = fclose(file); - if (error) err(EX_IOERR, "%s", path); + if (error) err(1, "%s", path); if (outPath && outPath == inPath) { error = rename(buf, outPath); - if (error) err(EX_CANTCREAT, "%s", outPath); + if (error) err(1, "%s", outPath); } } @@ -927,7 +910,7 @@ int main(int argc, char *argv[]) { break; case 'g': discardColor = true; break; case 'o': outPath = optarg; break; case 'v': verbose = true; - break; default: return EX_USAGE; + break; default: return 1; } } diff --git a/bin/psf2png.c b/bin/psf2png.c index 1aaa8635..aeb975b3 100644 --- a/bin/psf2png.c +++ b/bin/psf2png.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2018 C. McEnroe <june@causal.agency> +/* Copyright (C) 2018 June McEnroe <june@causal.agency> * * 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 @@ -19,7 +19,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sysexits.h> #include <unistd.h> #include "png.h" @@ -37,17 +36,17 @@ int main(int argc, char *argv[]) { break; case 'c': cols = strtoul(optarg, NULL, 0); break; case 'f': fg = strtoul(optarg, NULL, 16); break; case 's': str = optarg; - break; default: return EX_USAGE; + break; default: return 1; } } if (!cols && str) cols = strlen(str); - if (!cols) return EX_USAGE; + if (!cols) return 1; const char *path = NULL; if (optind < argc) path = argv[optind]; FILE *file = path ? fopen(path, "r") : stdin; - if (!file) err(EX_NOINPUT, "%s", path); + if (!file) err(1, "%s", path); if (!path) path = "(stdin)"; struct { @@ -63,15 +62,15 @@ int main(int argc, char *argv[]) { } glyph; } header; size_t len = fread(&header, sizeof(header), 1, file); - if (ferror(file)) err(EX_IOERR, "%s", path); - if (len < 1) errx(EX_DATAERR, "%s: truncated header", path); + if (ferror(file)) err(1, "%s", path); + if (len < 1) errx(1, "%s: truncated header", path); uint32_t widthBytes = (header.glyph.width + 7) / 8; uint8_t glyphs[header.glyph.len][header.glyph.height][widthBytes]; len = fread(glyphs, header.glyph.size, header.glyph.len, file); - if (ferror(file)) err(EX_IOERR, "%s", path); + if (ferror(file)) err(1, "%s", path); if (len < header.glyph.len) { - errx(EX_DATAERR, "%s: truncated glyphs", path); + errx(1, "%s: truncated glyphs", path); } fclose(file); diff --git a/bin/ptee.c b/bin/ptee.c index 8374bd8f..c4749d62 100644 --- a/bin/ptee.c +++ b/bin/ptee.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 C. McEnroe <june@causal.agency> +/* Copyright (C) 2019 June McEnroe <june@causal.agency> * * 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 @@ -24,7 +24,6 @@ #include <sys/ioctl.h> #include <sys/time.h> #include <sys/wait.h> -#include <sysexits.h> #include <termios.h> #include <unistd.h> @@ -52,35 +51,35 @@ int main(int argc, char *argv[]) { for (int opt; 0 < (opt = getopt(argc, argv, "t:"));) { switch (opt) { break; case 't': timer = atoi(optarg); - break; default: return EX_USAGE; + break; default: return 1; } } argc -= optind; argv += optind; - if (argc < 1) return EX_USAGE; - if (isatty(STDOUT_FILENO)) errx(EX_USAGE, "stdout is not redirected"); + if (argc < 1) return 1; + if (isatty(STDOUT_FILENO)) errx(1, "stdout is not redirected"); int error = tcgetattr(STDIN_FILENO, &saveTerm); - if (error) err(EX_IOERR, "tcgetattr"); + if (error) err(1, "tcgetattr"); atexit(restoreTerm); struct termios raw = saveTerm; cfmakeraw(&raw); error = tcsetattr(STDIN_FILENO, TCSADRAIN, &raw); - if (error) err(EX_IOERR, "tcsetattr"); + if (error) err(1, "tcsetattr"); struct winsize window; error = ioctl(STDIN_FILENO, TIOCGWINSZ, &window); - if (error) err(EX_IOERR, "ioctl"); + if (error) err(1, "ioctl"); int pty; pid_t pid = forkpty(&pty, NULL, NULL, &window); - if (pid < 0) err(EX_OSERR, "forkpty"); + if (pid < 0) err(1, "forkpty"); if (!pid) { execvp(argv[0], argv); - err(EX_NOINPUT, "%s", argv[0]); + err(1, "%s", argv[0]); } if (timer) { @@ -103,17 +102,17 @@ int main(int argc, char *argv[]) { }; for (;;) { int nfds = poll(fds, 2, -1); - if (nfds < 0 && errno != EINTR) err(EX_IOERR, "poll"); + if (nfds < 0 && errno != EINTR) err(1, "poll"); if (nfds < 0) { ssize_t wlen = write(STDOUT_FILENO, mc, sizeof(mc) - 1); - if (wlen < 0) err(EX_IOERR, "write"); + if (wlen < 0) err(1, "write"); continue; } if (fds[0].revents & POLLIN) { ssize_t rlen = read(STDIN_FILENO, buf, sizeof(buf)); - if (rlen < 0) err(EX_IOERR, "read"); + if (rlen < 0) err(1, "read"); if (rlen == 1 && buf[0] == CTRL('Q')) { stop ^= true; @@ -122,30 +121,30 @@ int main(int argc, char *argv[]) { if (rlen == 1 && buf[0] == CTRL('S')) { ssize_t wlen = write(STDOUT_FILENO, mc, sizeof(mc) - 1); - if (wlen < 0) err(EX_IOERR, "write"); + if (wlen < 0) err(1, "write"); continue; } ssize_t wlen = write(pty, buf, rlen); - if (wlen < 0) err(EX_IOERR, "write"); + if (wlen < 0) err(1, "write"); } if (fds[1].revents & POLLIN) { ssize_t rlen = read(pty, buf, sizeof(buf)); - if (rlen < 0) err(EX_IOERR, "read"); + if (rlen < 0) err(1, "read"); ssize_t wlen = write(STDIN_FILENO, buf, rlen); - if (wlen < 0) err(EX_IOERR, "write"); + if (wlen < 0) err(1, "write"); if (!stop) { wlen = write(STDOUT_FILENO, buf, rlen); - if (wlen < 0) err(EX_IOERR, "write"); + if (wlen < 0) err(1, "write"); } } int status; pid_t dead = waitpid(pid, &status, WNOHANG); - if (dead < 0) err(EX_OSERR, "waitpid"); - if (dead) return WIFEXITED(status) ? WEXITSTATUS(status) : EX_SOFTWARE; + if (dead < 0) err(1, "waitpid"); + if (dead) return WIFEXITED(status) ? WEXITSTATUS(status) : 1; } } diff --git a/bin/qf.c b/bin/qf.c index 1fbf48b9..afa7eced 100644 --- a/bin/qf.c +++ b/bin/qf.c @@ -24,7 +24,6 @@ #include <stdlib.h> #include <string.h> #include <sys/wait.h> -#include <sysexits.h> #include <unistd.h> enum Type { @@ -51,7 +50,7 @@ static void push(struct Line line) { if (lines.len == lines.cap) { lines.cap = (lines.cap ? lines.cap * 2 : 256); lines.ptr = realloc(lines.ptr, sizeof(*lines.ptr) * lines.cap); - if (!lines.ptr) err(EX_OSERR, "realloc"); + if (!lines.ptr) err(1, "realloc"); } lines.ptr[lines.len++] = line; } @@ -176,15 +175,15 @@ static void edit(struct Line line) { const char *editor = getenv("EDITOR"); if (!editor) editor = "vi"; pid_t pid = fork(); - if (pid < 0) err(EX_OSERR, "fork"); + if (pid < 0) err(1, "fork"); if (!pid) { dup2(STDERR_FILENO, STDIN_FILENO); execlp(editor, editor, cmd, line.path, NULL); - err(EX_CONFIG, "%s", editor); + err(127, "%s", editor); } int status; pid = waitpid(pid, &status, 0); - if (pid < 0) err(EX_OSERR, "waitpid"); + if (pid < 0) err(1, "waitpid"); } static void toPrev(enum Type type) { @@ -228,7 +227,7 @@ static void input(void) { break; case 'n': toNext(Match); break; case 'q': { endwin(); - exit(EX_OK); + exit(0); } break; case 'r': clearok(stdscr, true); } @@ -238,7 +237,7 @@ static void input(void) { } int main(int argc, char *argv[]) { - if (isatty(STDIN_FILENO)) errx(EX_USAGE, "no input"); + if (isatty(STDIN_FILENO)) errx(1, "no input"); if (argc > 1) { pattern = argv[1]; int flags = REG_EXTENDED | REG_ICASE; @@ -249,7 +248,7 @@ int main(int argc, char *argv[]) { } } int error = regcomp(®ex, pattern, flags); - if (error) errx(EX_USAGE, "invalid pattern"); + if (error) errx(1, "invalid pattern"); } curse(); draw(); @@ -260,14 +259,14 @@ int main(int argc, char *argv[]) { size_t len = 0; size_t cap = 4096; char *buf = malloc(cap); - if (!buf) err(EX_OSERR, "malloc"); + if (!buf) err(1, "malloc"); while (poll(fds, (reading ? 2 : 1), -1)) { if (fds[0].revents) { input(); } if (reading && fds[1].revents) { ssize_t n = read(fds[1].fd, &buf[len], cap - len); - if (n < 0) err(EX_IOERR, "read"); + if (n < 0) err(1, "read"); if (!n) reading = false; len += n; char *ptr = buf; @@ -277,7 +276,7 @@ int main(int argc, char *argv[]) { ptr = &nl[1] ) { struct Line line = { .text = strndup(ptr, nl - ptr) }; - if (!line.text) err(EX_OSERR, "strndup"); + if (!line.text) err(1, "strndup"); parse(line); } len -= ptr - buf; @@ -285,10 +284,10 @@ int main(int argc, char *argv[]) { if (len == cap) { cap *= 2; buf = realloc(buf, cap); - if (!buf) err(EX_OSERR, "realloc"); + if (!buf) err(1, "realloc"); } } draw(); } - err(EX_IOERR, "poll"); + err(1, "poll"); } diff --git a/bin/quick.c b/bin/quick.c index edf35a3b..96f29eb0 100644 --- a/bin/quick.c +++ b/bin/quick.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 C. McEnroe <june@causal.agency> +/* Copyright (C) 2021 June McEnroe <june@causal.agency> * * 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 @@ -26,13 +26,12 @@ #include <strings.h> #include <sys/socket.h> #include <sys/wait.h> -#include <sysexits.h> #include <unistd.h> static void request(int sock, char *argv[]) { struct pollfd pfd = { .fd = sock, .events = POLLIN }; int nfds = poll(&pfd, 1, -1); - if (nfds < 0) err(EX_OSERR, "poll"); + if (nfds < 0) err(1, "poll"); char buf[4096]; ssize_t len = recv(sock, buf, sizeof(buf)-1, MSG_PEEK); @@ -89,7 +88,7 @@ static void request(int sock, char *argv[]) { dprintf(sock, "HTTP/1.1 200 OK\nConnection: close\n"); pid_t pid = fork(); - if (pid < 0) err(EX_OSERR, "fork"); + if (pid < 0) err(1, "fork"); if (!pid) { dup2(sock, STDIN_FILENO); dup2(sock, STDOUT_FILENO); @@ -100,7 +99,7 @@ static void request(int sock, char *argv[]) { int status; pid = wait(&status); - if (pid < 0) err(EX_OSERR, "wait"); + if (pid < 0) err(1, "wait"); if (WIFEXITED(status) && WEXITSTATUS(status)) { warnx("%s exited %d", argv[0], WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { @@ -113,13 +112,13 @@ int main(int argc, char *argv[]) { for (int opt; 0 < (opt = getopt(argc, argv, "p:"));) { switch (opt) { break; case 'p': port = atoi(optarg); - break; default: return EX_USAGE; + break; default: return 1; } } - if (optind == argc) errx(EX_USAGE, "script required"); + if (optind == argc) errx(1, "script required"); int server = socket(AF_INET, SOCK_STREAM, 0); - if (server < 0) err(EX_OSERR, "socket"); + if (server < 0) err(1, "socket"); fcntl(server, F_SETFD, FD_CLOEXEC); int on = 1; @@ -135,7 +134,7 @@ int main(int argc, char *argv[]) { || bind(server, (struct sockaddr *)&addr, addrlen) || getsockname(server, (struct sockaddr *)&addr, &addrlen) || listen(server, -1); - if (error) err(EX_UNAVAILABLE, "%hd", port); + if (error) err(1, "%hd", port); char host[NI_MAXHOST], serv[NI_MAXSERV]; error = getnameinfo( @@ -143,7 +142,7 @@ int main(int argc, char *argv[]) { host, sizeof(host), serv, sizeof(serv), NI_NOFQDN | NI_NUMERICSERV ); - if (error) errx(EX_UNAVAILABLE, "getnameinfo: %s", gai_strerror(error)); + if (error) errx(1, "getnameinfo: %s", gai_strerror(error)); printf("http://%s:%s/\n", host, serv); fflush(stdout); @@ -159,5 +158,5 @@ int main(int argc, char *argv[]) { fcntl(sock, F_SETFD, FD_CLOEXEC); request(sock, &argv[optind]); } - err(EX_IOERR, "accept"); + err(1, "accept"); } diff --git a/bin/relay.c b/bin/relay.c index aa7913c9..a1a134d4 100644 --- a/bin/relay.c +++ b/bin/relay.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 C. McEnroe <june@causal.agency> +/* Copyright (C) 2019 June McEnroe <june@causal.agency> * * 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 @@ -35,7 +35,6 @@ #include <stdlib.h> #include <string.h> #include <sys/socket.h> -#include <sysexits.h> #include <tls.h> #include <unistd.h> @@ -47,7 +46,7 @@ static void clientWrite(struct tls *client, const char *ptr, size_t len) { while (len) { ssize_t ret = tls_write(client, ptr, len); if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT) continue; - if (ret < 0) errx(EX_IOERR, "tls_write: %s", tls_error(client)); + if (ret < 0) errx(1, "tls_write: %s", tls_error(client)); ptr += ret; len -= ret; } @@ -59,7 +58,7 @@ static void clientFormat(struct tls *client, const char *format, ...) { va_start(ap, format); int len = vsnprintf(buf, sizeof(buf), format, ap); va_end(ap); - if ((size_t)len > sizeof(buf) - 1) errx(EX_DATAERR, "message too large"); + if ((size_t)len > sizeof(buf) - 1) errx(1, "message too large"); clientWrite(client, buf, len); } @@ -67,7 +66,7 @@ static void clientHandle(struct tls *client, const char *chan, char *line) { char *prefix = NULL; if (line[0] == ':') { prefix = strsep(&line, " ") + 1; - if (!line) errx(EX_PROTOCOL, "unexpected eol"); + if (!line) errx(1, "unexpected eol"); } char *command = strsep(&line, " "); @@ -78,14 +77,14 @@ static void clientHandle(struct tls *client, const char *chan, char *line) { } if (strcmp(command, "PRIVMSG") && strcmp(command, "NOTICE")) return; - if (!prefix) errx(EX_PROTOCOL, "message without prefix"); + if (!prefix) errx(1, "message without prefix"); char *nick = strsep(&prefix, "!"); - if (!line) errx(EX_PROTOCOL, "message without destination"); + if (!line) errx(1, "message without destination"); char *dest = strsep(&line, " "); if (strcmp(dest, chan)) return; - if (!line || line[0] != ':') errx(EX_PROTOCOL, "message without message"); + if (!line || line[0] != ':') errx(1, "message without message"); line = &line[1]; if (!strncmp(line, "\1ACTION ", 8)) { @@ -102,14 +101,14 @@ static void clientHandle(struct tls *client, const char *chan, char *line) { #ifdef __FreeBSD__ static void limit(int fd, const cap_rights_t *rights) { int error = cap_rights_limit(fd, rights); - if (error) err(EX_OSERR, "cap_rights_limit"); + if (error) err(1, "cap_rights_limit"); } #endif int main(int argc, char *argv[]) { int error; - if (argc < 5) return EX_USAGE; + if (argc < 5) return 1; const char *host = argv[1]; const char *port = argv[2]; const char *nick = argv[3]; @@ -119,18 +118,18 @@ int main(int argc, char *argv[]) { signal(SIGPIPE, SIG_IGN); struct tls_config *config = tls_config_new(); - if (!config) errx(EX_SOFTWARE, "tls_config_new"); + if (!config) errx(1, "tls_config_new"); error = tls_config_set_ciphers(config, "compat"); if (error) { - errx(EX_SOFTWARE, "tls_config_set_ciphers: %s", tls_config_error(config)); + errx(1, "tls_config_set_ciphers: %s", tls_config_error(config)); } struct tls *client = tls_client(); - if (!client) errx(EX_SOFTWARE, "tls_client"); + if (!client) errx(1, "tls_client"); error = tls_configure(client, config); - if (error) errx(EX_SOFTWARE, "tls_configure: %s", tls_error(client)); + if (error) errx(1, "tls_configure: %s", tls_error(client)); tls_config_free(config); struct addrinfo *head; @@ -140,12 +139,12 @@ int main(int argc, char *argv[]) { .ai_protocol = IPPROTO_TCP, }; error = getaddrinfo(host, port, &hints, &head); - if (error) errx(EX_NOHOST, "getaddrinfo: %s", gai_strerror(error)); + if (error) errx(1, "getaddrinfo: %s", gai_strerror(error)); int sock = -1; for (struct addrinfo *ai = head; ai; ai = ai->ai_next) { sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); - if (sock < 0) err(EX_OSERR, "socket"); + if (sock < 0) err(1, "socket"); error = connect(sock, ai->ai_addr, ai->ai_addrlen); if (!error) break; @@ -153,15 +152,15 @@ int main(int argc, char *argv[]) { close(sock); sock = -1; } - if (sock < 0) err(EX_UNAVAILABLE, "connect"); + if (sock < 0) err(1, "connect"); freeaddrinfo(head); error = tls_connect_socket(client, sock, host); - if (error) errx(EX_PROTOCOL, "tls_connect: %s", tls_error(client)); + if (error) errx(1, "tls_connect: %s", tls_error(client)); #ifdef __FreeBSD__ error = cap_enter(); - if (error) err(EX_OSERR, "cap_enter"); + if (error) err(1, "cap_enter"); cap_rights_t rights; cap_rights_init(&rights, CAP_WRITE); @@ -190,7 +189,7 @@ int main(int argc, char *argv[]) { while (0 < poll(fds, 2, -1)) { if (fds[0].revents) { ssize_t len = getline(&input, &cap, stdin); - if (len < 0) err(EX_IOERR, "getline"); + if (len < 0) err(1, "getline"); input[len - 1] = '\0'; clientFormat(client, "NOTICE %s :%s\r\n", chan, input); } @@ -198,8 +197,8 @@ int main(int argc, char *argv[]) { ssize_t read = tls_read(client, &buf[len], sizeof(buf) - len); if (read == TLS_WANT_POLLIN || read == TLS_WANT_POLLOUT) continue; - if (read < 0) errx(EX_IOERR, "tls_read: %s", tls_error(client)); - if (!read) return EX_UNAVAILABLE; + if (read < 0) errx(1, "tls_read: %s", tls_error(client)); + if (!read) return 1; len += read; char *crlf; @@ -214,5 +213,5 @@ int main(int argc, char *argv[]) { len -= line - buf; memmove(buf, line, len); } - err(EX_IOERR, "poll"); + err(1, "poll"); } diff --git a/bin/scheme.c b/bin/scheme.c index 33fd8b60..82539ba2 100644 --- a/bin/scheme.c +++ b/bin/scheme.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2018, 2019 C. McEnroe <june@causal.agency> +/* Copyright (C) 2018, 2019 June McEnroe <june@causal.agency> * * 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 @@ -19,7 +19,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sysexits.h> #include <unistd.h> #include "png.h" @@ -263,14 +262,14 @@ int main(int argc, char *argv[]) { break; case 'm': output = outputMintty; break; case 'p': { uint p = strtoul(optarg, NULL, 0); - if (p >= SchemeLen) return EX_USAGE; + if (p >= SchemeLen) return 1; hsv = &scheme[p]; len = 1; } break; case 's': output = outputCSS; break; case 't': len = SchemeLen; break; case 'x': output = outputRGB; - break; default: return EX_USAGE; + break; default: return 1; } } diff --git a/bin/shotty.l b/bin/shotty.l index ff78d241..b6d54eee 100644 --- a/bin/shotty.l +++ b/bin/shotty.l @@ -1,4 +1,4 @@ -/* Copyright (C) 2019, 2021 C. McEnroe <june@causal.agency> +/* Copyright (C) 2019, 2021 June McEnroe <june@causal.agency> * * 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 @@ -26,7 +26,6 @@ #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> -#include <sysexits.h> #include <unistd.h> #include <wchar.h> @@ -181,13 +180,13 @@ ESC \x1B | (wchar_t)(yytext[1] & 0x3F); return Data; } -[\xE0-\xEF][\x80-\xBF]{2} { +[\xE0-\xEF]([\x80-\xBF]{2}) { ch = (wchar_t)(yytext[0] & 0x0F) << 12 | (wchar_t)(yytext[1] & 0x3F) << 6 | (wchar_t)(yytext[2] & 0x3F); return Data; } -[\xF0-\xF7][\x80-\xBF]{3} { +[\xF0-\xF7]([\x80-\xBF]{3}) { ch = (wchar_t)(yytext[0] & 0x07) << 18 | (wchar_t)(yytext[1] & 0x3F) << 12 | (wchar_t)(yytext[2] & 0x3F) << 6 @@ -554,25 +553,25 @@ int main(int argc, char *argv[]) { break; case 'n': hide = true; break; case 's': size = true; break; case 'w': cols = atoi(optarg); - break; default: return EX_USAGE; + break; default: return 1; } } if (optind < argc) { yyin = fopen(argv[optind], "r"); - if (!yyin) err(EX_NOINPUT, "%s", argv[optind]); + if (!yyin) err(1, "%s", argv[optind]); } if (size) { struct winsize win; int error = ioctl(STDERR_FILENO, TIOCGWINSZ, &win); - if (error) err(EX_IOERR, "ioctl"); + if (error) err(1, "ioctl"); cols = win.ws_col; rows = win.ws_row; } scr.bot = rows; cells = calloc(cols * rows, sizeof(*cells)); - if (!cells) err(EX_OSERR, "calloc"); + if (!cells) err(1, "calloc"); erase(cell(0, 0), cell(rows-1, cols)); bool mc = false; diff --git a/bin/title.c b/bin/title.c index 82f89d95..f40f5c87 100644 --- a/bin/title.c +++ b/bin/title.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 C. McEnroe <june@causal.agency> +/* Copyright (C) 2019 June McEnroe <june@causal.agency> * * 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 @@ -22,7 +22,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <sysexits.h> #include <unistd.h> #include <wchar.h> @@ -33,7 +32,7 @@ static regex_t regex(const char *pattern, int flags) { char buf[256]; regerror(error, ®ex, buf, sizeof(buf)); - errx(EX_SOFTWARE, "regcomp: %s: %s", buf, pattern); + errx(1, "regcomp: %s: %s", buf, pattern); } static const struct Entity { @@ -128,7 +127,7 @@ static CURLcode fetchTitle(const char *url) { char *dest; curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &dest); dest = strdup(dest); - if (!dest) err(EX_OSERR, "strdup"); + if (!dest) err(1, "strdup"); code = curl_easy_setopt(curl, CURLOPT_URL, dest); if (code) return code; @@ -149,10 +148,10 @@ int main(int argc, char *argv[]) { setlinebuf(stdout); CURLcode code = curl_global_init(CURL_GLOBAL_ALL); - if (code) errx(EX_OSERR, "curl_global_init: %s", curl_easy_strerror(code)); + if (code) errx(1, "curl_global_init: %s", curl_easy_strerror(code)); curl = curl_easy_init(); - if (!curl) errx(EX_SOFTWARE, "curl_easy_init"); + if (!curl) errx(1, "curl_easy_init"); static char error[CURL_ERROR_SIZE]; curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error); @@ -180,14 +179,14 @@ int main(int argc, char *argv[]) { excludeRegex = regex(optarg, REG_NOSUB); } break; case 'v': curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); - break; default: return EX_USAGE; + break; default: return 1; } } if (optind < argc) { code = fetchTitle(argv[optind]); - if (!code) return EX_OK; - errx(EX_DATAERR, "curl_easy_perform: %s", error); + if (!code) return 0; + errx(1, "curl_easy_perform: %s", error); } char *buf = NULL; @@ -207,5 +206,5 @@ int main(int argc, char *argv[]) { ptr[match.rm_eo] = ' '; } } - if (ferror(stdin)) err(EX_IOERR, "getline"); + if (ferror(stdin)) err(1, "getline"); } diff --git a/bin/up.sh b/bin/up.sh index cebc29c4..6305b1ee 100644 --- a/bin/up.sh +++ b/bin/up.sh @@ -4,21 +4,32 @@ set -eu readonly Host='temp.causal.agency' readonly Root='/var/www' +temp= +temp() { + temp=$(mktemp -d) + trap 'rm -r "$temp"' EXIT +} + +warn= upload() { src=$1 ext=${src##*.} - ts=$(date +'%s') - rand=$(openssl rand -hex 4) - url=$(printf '%s/%x%s.%s' "$Host" "$ts" "$rand" "$ext") + name=$(printf '%x%s' "$(date +%s)" "$(openssl rand -hex 4)") + url="${Host}/${name}.${ext}" scp -q "$src" "${Host}:${Root}/${url}" + if test -n "$warn"; then + test -n "$temp" || temp + cat >"${temp}/warn.html" <<-EOF + <!DOCTYPE html> + <title>${warn}</title> + <meta http-equiv="refresh" content="0;url=${name}.${ext}"> + EOF + url="${Host}/${name}.html" + scp -q "${temp}/warn.html" "${Host}:${Root}/${url}" + fi echo "https://${url}" } -temp() { - temp=$(mktemp -d) - trap 'rm -r "$temp"' EXIT -} - uploadText() { temp cat >"${temp}/input.txt" @@ -64,12 +75,13 @@ uploadTerminal() { upload "${temp}/term.html" } -while getopts 'chst' opt; do +while getopts 'chstw:' opt; do case $opt in (c) fn=uploadCommand;; (h) fn=uploadHilex;; (s) fn=uploadScreen;; (t) fn=uploadTerminal;; + (w) warn=$OPTARG;; (?) exit 1;; esac done diff --git a/bin/when.y b/bin/when.y index 64859da7..1d3795ad 100644 --- a/bin/when.y +++ b/bin/when.y @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 June McEnroe <june@causal.agency> +/* Copyright (C) 2019, 2022 June McEnroe <june@causal.agency> * * 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 @@ -18,10 +18,12 @@ #include <ctype.h> #include <err.h> +#include <errno.h> +#include <limits.h> +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <strings.h> -#include <sysexits.h> #include <time.h> static void yyerror(const char *str); @@ -30,12 +32,13 @@ static int yylex(void); #define YYSTYPE struct tm static const char *Days[7] = { - "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday", }; static const char *Months[12] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December", }; static const struct tm Week = { .tm_mday = 7 }; @@ -43,14 +46,14 @@ static const struct tm Week = { .tm_mday = 7 }; static struct tm normalize(struct tm date) { time_t time = timegm(&date); struct tm *norm = gmtime(&time); - if (!norm) err(EX_OSERR, "gmtime"); + if (!norm) err(1, "gmtime"); return *norm; } static struct tm today(void) { time_t now = time(NULL); struct tm *local = localtime(&now); - if (!local) err(EX_OSERR, "localtime"); + if (!local) err(1, "localtime"); struct tm date = { .tm_year = local->tm_year, .tm_mon = local->tm_mon, @@ -117,7 +120,10 @@ static struct tm dateDiff(struct tm a, struct tm b) { .tm_mon = a.tm_mon - b.tm_mon, .tm_mday = a.tm_mday - b.tm_mday, }; - if (a.tm_mon < b.tm_mon) { + if ( + a.tm_mon < b.tm_mon || + (a.tm_mon == b.tm_mon && a.tm_mday < b.tm_mday) + ) { diff.tm_year--; diff.tm_mon += 12; } @@ -130,15 +136,50 @@ static struct tm dateDiff(struct tm a, struct tm b) { return diff; } +static struct { + size_t cap, len; + struct tm *ptr; +} dates; + +static struct tm getDate(const char *name) { + for (size_t i = 0; i < dates.len; ++i) { + if (!strcmp(dates.ptr[i].tm_zone, name)) return dates.ptr[i]; + } + return (struct tm) {0}; +} + +static void setDate(const char *name, struct tm date) { + for (size_t i = 0; i < dates.len; ++i) { + if (strcmp(dates.ptr[i].tm_zone, name)) continue; + char *tm_zone = dates.ptr[i].tm_zone; + dates.ptr[i] = date; + dates.ptr[i].tm_zone = tm_zone; + return; + } + if (dates.len == dates.cap) { + dates.cap = (dates.cap ? dates.cap * 2 : 8); + dates.ptr = realloc(dates.ptr, sizeof(*dates.ptr) * dates.cap); + if (!dates.ptr) err(1, "realloc"); + } + dates.ptr[dates.len] = date; + dates.ptr[dates.len].tm_zone = strdup(name); + if (!dates.ptr[dates.len].tm_zone) err(1, "strdup"); + dates.len++; +} + +static bool silent; + static void printDate(struct tm date) { + if (silent) return; printf( - "%s %s %d %d\n", + "%.3s %.3s %d %d\n", Days[date.tm_wday], Months[date.tm_mon], date.tm_mday, 1900 + date.tm_year ); } static void printScalar(struct tm scalar) { + if (silent) return; if (scalar.tm_year) printf("%dy ", scalar.tm_year); if (scalar.tm_mon) printf("%dm ", scalar.tm_mon); if (scalar.tm_mday % 7) { @@ -161,7 +202,8 @@ static void printScalar(struct tm scalar) { %} -%token Number Month Day +%token Name Number Month Day +%right '=' %left '+' '-' %right '<' '>' @@ -174,6 +216,8 @@ expr: date: dateLit + | Name { $$ = getDate($1.tm_zone); free($1.tm_zone); } + | Name '=' date { setDate($1.tm_zone, $3); free($1.tm_zone); $$ = $3; } | '(' date ')' { $$ = $2; } | '<' date { $$ = dateSub($2, Week); } | '>' date { $$ = dateAdd($2, Week); } @@ -223,35 +267,77 @@ static int yylex(void) { return Number; } - for (int i = 0; i < 7; ++i) { - if (strncasecmp(input, Days[i], 3)) continue; - while (isalpha(*input)) input++; - yylval.tm_wday = i; - return Day; + size_t len; + for (len = 0; isalnum(input[len]) || input[len] == '_'; ++len); + + if (len >= 3) { + for (int i = 0; i < 7; ++i) { + if (strncasecmp(input, Days[i], len)) continue; + yylval.tm_wday = i; + input += len; + return Day; + } + + for (int i = 0; i < 12; ++i) { + if (strncasecmp(input, Months[i], len)) continue; + yylval.tm_mon = i; + input += len; + return Month; + } } - for (int i = 0; i < 12; ++i) { - if (strncasecmp(input, Months[i], 3)) continue; - while (isalpha(*input)) input++; - yylval.tm_mon = i; - return Month; + if (len && (len != 1 || !strchr("dwmy", *input))) { + yylval.tm_zone = strndup(input, len); + if (!yylval.tm_zone) err(1, "strndup"); + input += len; + return Name; } return *input++; } int main(int argc, char *argv[]) { + size_t cap = 0; + char *line = NULL; + + char path[PATH_MAX]; + const char *configHome = getenv("XDG_CONFIG_HOME"); + if (configHome) { + snprintf(path, sizeof(path), "%s/when/dates", configHome); + } else { + snprintf(path, sizeof(path), "%s/.config/when/dates", getenv("HOME")); + } + + FILE *file = fopen(path, "r"); + if (file) { + silent = true; + while (0 < getline(&line, &cap, file)) { + input = line; + yyparse(); + } + fclose(file); + silent = false; + } else if (errno != ENOENT) { + err(1, "%s", path); + } + if (argc > 1) { - input = argv[1]; - return yyparse(); + if (strcmp(argv[1], "-")) { + input = argv[1]; + return yyparse(); + } else { + for (size_t i = 0; i < dates.len; ++i) { + printf("%s: ", dates.ptr[i].tm_zone); + printScalar(dateDiff(today(), dates.ptr[i])); + } + return 0; + } } struct tm date = today(); printDate(date); printf("\n"); - char *line = NULL; - size_t cap = 0; while (0 < getline(&line, &cap, stdin)) { if (line[0] == '\n') continue; diff --git a/bin/xx.c b/bin/xx.c index 6d04f2f5..89966a38 100644 --- a/bin/xx.c +++ b/bin/xx.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2017 C. McEnroe <june@causal.agency> +/* Copyright (C) 2017 June McEnroe <june@causal.agency> * * 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 @@ -19,7 +19,6 @@ #include <stdbool.h> #include <stdio.h> #include <stdlib.h> -#include <sysexits.h> #include <unistd.h> typedef unsigned char byte; @@ -105,7 +104,7 @@ static void undump(FILE *file) { while (0 < (match = fscanf(file, " %hhx", &c))) { printf("%c", c); } - if (!match) errx(EX_DATAERR, "invalid input"); + if (!match) errx(1, "invalid input"); } int main(int argc, char *argv[]) { @@ -122,21 +121,21 @@ int main(int argc, char *argv[]) { break; case 'r': reverse = true; break; case 's': options.offset ^= true; break; case 'z': options.skip ^= true; - break; default: return EX_USAGE; + break; default: return 1; } } if (argc > optind) path = argv[optind]; - if (!options.cols) return EX_USAGE; + if (!options.cols) return 1; FILE *file = path ? fopen(path, "r") : stdin; - if (!file) err(EX_NOINPUT, "%s", path); + if (!file) err(1, "%s", path); if (reverse) { undump(file); } else { dump(file); } - if (ferror(file)) err(EX_IOERR, "%s", path); + if (ferror(file)) err(1, "%s", path); - return EX_OK; + return 0; } |