From e785e9bbc18922df4187f9a6e27d238bac984d85 Mon Sep 17 00:00:00 2001
From: Karchnu <karchnu@karchnu.fr>
Date: Tue, 20 Apr 2021 02:30:56 +0200
Subject: [PATCH] By-line.

---
 c/by-line/Makefile  |   9 ++++
 c/by-line/by-line.c | 104 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 113 insertions(+)
 create mode 100644 c/by-line/Makefile
 create mode 100644 c/by-line/by-line.c

diff --git a/c/by-line/Makefile b/c/by-line/Makefile
new file mode 100644
index 0000000..56b42f6
--- /dev/null
+++ b/c/by-line/Makefile
@@ -0,0 +1,9 @@
+CC ?= clang
+CFLAGS ?= -Wall -Wextra -std=c11
+
+all: compilation
+
+compilation: by-line
+
+by-line: by-line.c
+	$(Q)$(CC) -o by-line $(CFLAGS) $(LDFLAGS) $^
diff --git a/c/by-line/by-line.c b/c/by-line/by-line.c
new file mode 100644
index 0000000..cf8db61
--- /dev/null
+++ b/c/by-line/by-line.c
@@ -0,0 +1,104 @@
+#include <stdio.h> // printf
+#include <fcntl.h>
+#include <string.h> // memchr
+#include <unistd.h> // read write
+#include <stdint.h> // uint32_t
+#include <stdlib.h> // exit
+#include <poll.h> // poll
+
+// OUTPUT: line-by-line strings
+
+#define line_size_exceeded "line exeeded max buffer size\n"
+#define  MAXBUFFER 64000
+
+char buf[MAXBUFFER];
+
+void err(int error, const char *str) {
+	fprintf (stderr, "%s\n", str);
+	exit(error);
+}
+
+int main(int argc, const char **argv)
+{
+	if (argc > 1) {
+		printf ("usage: %s\n", argv[0]);
+		return 0;
+	}
+
+	// fcntl(0, F_SETFL, O_SYNC);
+
+	uint32_t tot_read = 0;
+	uint32_t n_read = 0;
+	struct pollfd pfd[1];
+	int nready;
+
+	pfd[0].fd = 0;
+
+	while (1) {
+		pfd[0].events = POLLIN;
+		nready = poll(pfd, 1, 60 * 1000);
+
+		if (nready == -1)
+			err (1, "poll");
+
+		if (nready == 0) {
+			fprintf (stderr, "time out\n");
+		}
+
+		if ((pfd[0].revents & (POLLERR|POLLNVAL))) {
+			fprintf (stderr, "bad fd %d", pfd[0].fd);
+			err (1, "bad fd");
+		}
+
+		if ((pfd[0].revents & (POLLIN|POLLHUP))) {
+			n_read = read(0, buf, sizeof(buf));
+			if (n_read > 0) {
+				// fprintf (stderr, "read %u characters\n", n_read);
+
+				tot_read += n_read;
+				// fprintf(stderr, "total read %u\n", tot_read);
+				// fprintf(stderr, "could still read %u\n", MAXBUFFER - tot_read);
+				if (tot_read == MAXBUFFER) {
+					// print anyway
+					write (1, buf, tot_read);
+					write (2, line_size_exceeded, strlen(line_size_exceeded));
+					printf(buf);
+					n_read = 0;
+					tot_read = 0;
+					continue;
+				}
+
+				// print line by line (if any)
+				char * p = NULL;
+				while ((p = memchr(buf, '\n', tot_read)) != NULL) {
+					uint32_t remaining = tot_read - (p - buf) - 1;
+					write (1, buf, tot_read - remaining);
+					// fprintf (stderr, "found retline, %u remaining chars\n", remaining);
+
+					for (uint32_t i = 0; i < remaining ; i++) {
+						buf[i] = buf[i + tot_read - remaining];
+					}
+					tot_read = remaining;
+					n_read = 0;
+				}
+
+			}
+			else if (n_read == 0) {
+				// fprintf (stderr, "EOF\n");
+				break;
+			}
+			else {
+				err (1, "read");
+			}
+		}
+	}
+
+	if (tot_read > 0) {
+		// fprintf(stderr, "print the %u characters remaining in the buffer\n", tot_read);
+		write (1, buf, tot_read);
+	}
+
+	// fprintf (stderr, "end of the loop\n");
+
+	return 0;
+}