summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--README3
-rw-r--r--chat.c102
-rw-r--r--chat.h5
-rw-r--r--event.c123
-rw-r--r--url.c2
6 files changed, 132 insertions, 104 deletions
diff --git a/Makefile b/Makefile
index 435172f..9ec7b26 100644
--- a/Makefile
+++ b/Makefile
@@ -10,6 +10,7 @@ LDLIBS = -lcursesw -ltls
OBJS += chat.o
OBJS += edit.o
+OBJS += event.o
OBJS += handle.o
OBJS += input.o
OBJS += irc.o
diff --git a/README b/README
index be2c84b..9c86694 100644
--- a/README
+++ b/README
@@ -3,7 +3,8 @@ IRC client originally intended for use over anonymous SSH.
This software requires LibreSSL and targets FreeBSD and Darwin.
chat.h Shared state and function prototypes
- chat.c Command line parsing and event loop
+ chat.c Command line parsing
+ event.c Event loop and process spawning
tag.c Tag (channel, query) ID assignment
handle.c Incoming command handling
input.c Input command handling
diff --git a/chat.c b/chat.c
index fb9e68f..c7a3229 100644
--- a/chat.c
+++ b/chat.c
@@ -17,15 +17,11 @@
#define _WITH_GETLINE
#include <err.h>
-#include <errno.h>
-#include <poll.h>
-#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
-#include <sys/wait.h>
#include "chat.h"
@@ -45,98 +41,6 @@ void selfJoin(const char *join) {
if (!self.join) err(EX_OSERR, "strdup");
}
-static union {
- struct {
- struct pollfd ui;
- struct pollfd irc;
- struct pollfd pipe;
- };
- struct pollfd fds[3];
-} fds = {
- .ui = { .events = POLLIN, .fd = STDIN_FILENO },
- .irc = { .events = POLLIN },
- .pipe = { .events = 0 },
-};
-
-void spawn(char *const argv[]) {
- if (fds.pipe.events) {
- uiLog(TagStatus, UIWarm, L"spawn: existing pipe");
- return;
- }
-
- int rw[2];
- int error = pipe(rw);
- if (error) err(EX_OSERR, "pipe");
-
- pid_t pid = fork();
- if (pid < 0) err(EX_OSERR, "fork");
- if (!pid) {
- close(rw[0]);
- close(STDIN_FILENO);
- dup2(rw[1], STDOUT_FILENO);
- dup2(rw[1], STDERR_FILENO);
- close(rw[1]);
- execvp(argv[0], argv);
- perror(argv[0]);
- exit(EX_CONFIG);
- }
-
- close(rw[1]);
- fds.pipe.fd = rw[0];
- fds.pipe.events = POLLIN;
-}
-
-static void pipeRead(void) {
- char buf[256];
- ssize_t len = read(fds.pipe.fd, buf, sizeof(buf) - 1);
- if (len < 0) err(EX_IOERR, "read");
- if (len) {
- buf[len] = '\0';
- len = strcspn(buf, "\n");
- uiFmt(TagStatus, UIWarm, "spawn: %.*s", (int)len, buf);
- } else {
- close(fds.pipe.fd);
- fds.pipe.events = 0;
- fds.pipe.revents = 0;
- }
-}
-
-static void eventLoop(void) {
- for (;;) {
- uiDraw();
-
- int n = poll(fds.fds, (fds.pipe.events ? 3 : 2), -1);
- if (n < 0) {
- if (errno != EINTR) err(EX_IOERR, "poll");
- uiRead();
- continue;
- }
-
- if (fds.ui.revents) uiRead();
- if (fds.irc.revents) ircRead();
- if (fds.pipe.revents) pipeRead();
- }
-}
-
-static void sigchld(int sig) {
- (void)sig;
- int status;
- pid_t pid = wait(&status);
- if (pid < 0) err(EX_OSERR, "wait");
- if (WIFEXITED(status) && WEXITSTATUS(status)) {
- uiFmt(TagStatus, UIWarm, "spawn: exit %d", WEXITSTATUS(status));
- } else if (WIFSIGNALED(status)) {
- uiFmt(TagStatus, UIWarm, "spawn: signal %d", WTERMSIG(status));
- }
-}
-
-static void sigint(int sig) {
- (void)sig;
- input(TagStatus, "/quit");
- uiExit();
- exit(EX_OK);
-}
-
static char *prompt(const char *prompt) {
char *line = NULL;
size_t cap;
@@ -186,10 +90,8 @@ int main(int argc, char *argv[]) {
uiLog(TagStatus, UIWarm, L"Traveling...");
uiDraw();
- fds.irc.fd = ircConnect(host, port, pass, webirc);
+ int irc = ircConnect(host, port, pass, webirc);
free(host);
- signal(SIGINT, sigint);
- signal(SIGCHLD, sigchld);
- eventLoop();
+ eventLoop(STDIN_FILENO, irc);
}
diff --git a/chat.h b/chat.h
index df532d7..6c95ab6 100644
--- a/chat.h
+++ b/chat.h
@@ -37,6 +37,9 @@ void selfNick(const char *nick);
void selfUser(const char *user);
void selfJoin(const char *join);
+void eventSpawn(char *const argv[]);
+void eventLoop(int ui, int irc);
+
struct Tag {
size_t id;
const char *name;
@@ -161,8 +164,6 @@ void logFmt(
struct Tag tag, const time_t *ts, const char *format, ...
) __attribute__((format(printf, 3, 4)));
-void spawn(char *const argv[]);
-
wchar_t *wcsnchr(const wchar_t *wcs, size_t len, wchar_t chr);
wchar_t *wcsnrchr(const wchar_t *wcs, size_t len, wchar_t chr);
wchar_t *ambstowcs(const char *src);
diff --git a/event.c b/event.c
new file mode 100644
index 0000000..4771aac
--- /dev/null
+++ b/event.c
@@ -0,0 +1,123 @@
+/* Copyright (C) 2018 Curtis 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <err.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "chat.h"
+
+static union {
+ struct {
+ struct pollfd ui;
+ struct pollfd irc;
+ struct pollfd pipe;
+ };
+ struct pollfd fds[3];
+} fds;
+
+void eventSpawn(char *const argv[]) {
+ if (fds.pipe.events) {
+ uiLog(TagStatus, UIHot, L"eventSpawn: existing pipe");
+ return;
+ }
+
+ int rw[2];
+ int error = pipe(rw);
+ if (error) err(EX_OSERR, "pipe");
+
+ pid_t pid = fork();
+ if (pid < 0) err(EX_OSERR, "fork");
+ if (!pid) {
+ close(rw[0]);
+ close(STDIN_FILENO);
+ dup2(rw[1], STDOUT_FILENO);
+ dup2(rw[1], STDERR_FILENO);
+ close(rw[1]);
+ execvp(argv[0], argv);
+ perror(argv[0]);
+ exit(EX_CONFIG);
+ }
+
+ close(rw[1]);
+ fds.pipe.fd = rw[0];
+ fds.pipe.events = POLLIN;
+}
+
+static void pipeRead(void) {
+ char buf[256];
+ ssize_t len = read(fds.pipe.fd, buf, sizeof(buf) - 1);
+ if (len < 0) err(EX_IOERR, "read");
+ if (len) {
+ buf[len] = '\0';
+ len = strcspn(buf, "\n");
+ uiFmt(TagStatus, UIHot, "eventSpawn: %.*s", (int)len, buf);
+ } else {
+ close(fds.pipe.fd);
+ memset(&fds.pipe, 0, sizeof(fds.pipe));
+ }
+}
+
+static void sigchld(int sig) {
+ (void)sig;
+ int status;
+ pid_t pid = wait(&status);
+ if (pid < 0) err(EX_OSERR, "wait");
+ if (WIFEXITED(status) && WEXITSTATUS(status)) {
+ uiFmt(TagStatus, UIHot, "eventSpawn: exit %d", WEXITSTATUS(status));
+ } else if (WIFSIGNALED(status)) {
+ uiFmt(TagStatus, UIHot, "eventSpawn: singal %d", WTERMSIG(status));
+ }
+}
+
+static void sigint(int sig) {
+ (void)sig;
+ input(TagStatus, "/quit");
+ uiExit();
+ exit(EX_OK);
+}
+
+void eventLoop(int ui, int irc) {
+ signal(SIGINT, sigint);
+ signal(SIGCHLD, sigchld);
+
+ fds.ui.fd = ui;
+ fds.irc.fd = irc;
+ fds.ui.events = POLLIN;
+ fds.irc.events = POLLIN;
+
+ for (;;) {
+ uiDraw();
+
+ int ready = poll(fds.fds, (fds.pipe.events ? 3 : 2), -1);
+ if (ready < 0) {
+ if (errno != EINTR) err(EX_IOERR, "poll");
+ uiRead();
+ continue;
+ }
+
+ if (fds.ui.revents) uiRead();
+ if (fds.irc.revents) ircRead();
+ if (fds.pipe.revents) pipeRead();
+ }
+}
diff --git a/url.c b/url.c
index e6207a5..3f8d57a 100644
--- a/url.c
+++ b/url.c
@@ -82,5 +82,5 @@ void urlOpen(struct Tag tag, size_t at, size_t to) {
if (tagIndex >= at && tagIndex < to) argv[argc++] = entry.url;
tagIndex++;
}
- if (argc > 1) spawn(argv);
+ if (argc > 1) eventSpawn(argv);
}