summary refs log tree commit diff
path: root/daemon.h
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2020-08-15 13:05:31 -0400
committerJune McEnroe <june@causal.agency>2020-08-15 13:05:31 -0400
commitf556af9ad5c90db94ecf01af2b50a22f6c721791 (patch)
treea609c64b296fbce484df0306abd12579a67706fc /daemon.h
parentGenerate tags file (diff)
downloadcatsit-f556af9ad5c90db94ecf01af2b50a22f6c721791.tar.gz
catsit-f556af9ad5c90db94ecf01af2b50a22f6c721791.zip
Implement non-blocking line-buffered reading
Diffstat (limited to 'daemon.h')
-rw-r--r--daemon.h43
1 files changed, 37 insertions, 6 deletions
diff --git a/daemon.h b/daemon.h
index db82ee2..7290420 100644
--- a/daemon.h
+++ b/daemon.h
@@ -14,6 +14,7 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <errno.h>
 #include <grp.h>
 #include <pwd.h>
 #include <stdint.h>
@@ -49,6 +50,42 @@ static inline int prependAdd(const char *command) {
 	return 0;
 }
 
+struct Line {
+	size_t len;
+	char buf[512];
+};
+
+static inline char *lineFlush(struct Line *line) {
+	if (!line->len) return NULL;
+	line->buf[line->len++] = '\0';
+	return line->buf;
+}
+
+static inline char *lineRead(struct Line *line, int fd) {
+	char *nul = memchr(line->buf, '\0', line->len);
+	if (nul) {
+		nul++;
+		line->len -= nul - line->buf;
+		memmove(line->buf, nul, line->len);
+	}
+
+	size_t cap = sizeof(line->buf) - line->len - 1;
+	if (!cap) return lineFlush(line);
+
+	ssize_t len = read(fd, &line->buf[line->len], cap);
+	if (len < 0 && errno != EAGAIN) return NULL;
+	if (len > 0) line->len += len;
+
+	char *nl = memchr(line->buf, '\n', line->len);
+	if (nl) {
+		*nl = '\0';
+		return line->buf;
+	} else {
+		errno = EAGAIN;
+		return NULL;
+	}
+}
+
 enum {
 	SHELL,
 	PATH,
@@ -70,12 +107,6 @@ enum State {
 	Restart,
 };
 
-enum { LineCap = 512 };
-struct Line {
-	size_t len;
-	char buf[LineCap];
-};
-
 struct Service {
 	char *name;
 	char *command;