summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rwxr-xr-xinput.sh40
-rw-r--r--tailburst.c110
3 files changed, 114 insertions, 39 deletions
diff --git a/Makefile b/Makefile
index 12f280a..ee2c866 100644
--- a/Makefile
+++ b/Makefile
@@ -7,7 +7,6 @@ CFLAGS+=-g -Wall -Werror
all: $(MAIN)
$(MAIN): $(OBJECTS)
- $(CC) $(LDFLAGS) $< -o $@
-
+
clean:
rm -f *.o $(MAIN)
diff --git a/input.sh b/input.sh
new file mode 100755
index 0000000..00b6dca
--- /dev/null
+++ b/input.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+TEXT=()
+
+case "$1" in
+1)
+ t=""
+ for _ in {1..2000}; do
+ t+="0123456789"
+ done
+ TEXT=("$t" one)
+ ;;
+2)
+ t=""
+ for _ in {1..100}; do
+ t+="0123456789"$'\n'
+ done
+ for _ in {1..5}; do
+ TEXT+=("$t""0123456789")
+ done
+ ;;
+3)
+ t=""
+ for _ in {1..100}; do
+ t+="0123456789"
+ done
+ for _ in {1..5}; do
+ t="$t"$'\n'"$t"
+ done
+ TEXT=("$t" one)
+ ;;
+*)
+ TEXT=($'one\ntwo\nthree' one two $'three\nfour' five)
+ ;;
+esac
+
+for t in "${TEXT[@]}"; do
+ printf "%s\n" "$t"
+ sleep 1
+done
diff --git a/tailburst.c b/tailburst.c
index 1c621f2..e150e8c 100644
--- a/tailburst.c
+++ b/tailburst.c
@@ -6,7 +6,7 @@
#include <errno.h>
#include <stdlib.h>
-#define BUFLEN 1024
+#define MAXBUFLEN 8096
#define DEBUG 0
#define pr_debug(fmt, args...) if (DEBUG) printf(fmt, ##args)
@@ -30,69 +30,101 @@ ssize_t fdgetline(int fd, struct getline_states *line) {
return -ENOMEM;
line->base[0] = '\0';
line->read = 0;
- line->next = NULL;
+ line->next = line->base;
+ line->cur = NULL;
}
- /* Skip after previously returned line */
- if (line->next)
- line->cur = line->next;
- else
- line->cur = line->base;
-
/* Do we already have a full line in buffer? */
- if ((str = strchr(line->cur, '\n'))) {
+ if (line->read > 0 && (str = strchr(line->next, '\n'))) {
+ line->cur = line->next;
line->next = str+1;
str[0] = '\0';
pr_debug("next already buffered, %p %p: %s\n", str, line->cur, line->cur);
- return str - line->cur;
+ return 1;
}
/* No such luck, move current to base and read what we can */
- if (line->cur != line->base) {
- pr_debug("moving cur: %p, base: %p, read: %zd, moving %zd\n", line->cur, line->base, line->read, line->cur - line->base);
+ if (line->cur && line->cur != line->base) {
+ pr_debug("moving cur: %p, base: %p, read: %zd, moving %zd\n",
+ line->cur, line->base, line->read, line->cur - line->base);
line->read -= line->cur - line->base;
- memmove(line->base, line->cur, line->read);
+ line->next -= line->cur - line->base;
+ memmove(line->base, line->cur, line->read + 1); /* also move trailing \0 */
line->cur = line->base;
}
- /* clear errno before read */
- errno = 0;
-
- while ((nread = read(fd, line->base + line->read, line->size - line->read)) > 0 ) {
- pr_debug("read %zd\n", nread);
+ /* search from here */
+ while (1) {
+ size_t toread = line->size - line->read - 1;
+ /* if there is no current line we need to keep some leeway
+ * for the next read... */
+ if (!line->cur)
+ toread /= 2;
+ errno = 0;
+ nread = read(fd, line->base + line->read, toread);
+ pr_debug("read %zd/%zd (%d)\n", nread, toread, errno);
+ if (nread < 0) {
+ if (errno == EAGAIN)
+ return 0;
+ break;
+ }
+ if (nread == 0) {
+ /* EOF */
+ return -1;
+ }
line->read += nread;
+ line->base[line->read] = '\0';
/* Check if we have a full line now */
- if ((str = strchr(line->base, '\n'))) {
- line->next = str+1;
+ if ((str = strchr(line->next, '\n'))) {
+ line->cur = line->next;
+ line->next = str + 1;
str[0] = '\0';
- pr_debug("found stuff, %p %p %p: %s\n", str, line->base, line->cur, line->cur);
- return str - line->base;
+ pr_debug("found stuff, %p %p %p: %s\n",
+ str, line->base, line->cur, line->cur);
+ return 1;
}
- /* realloc bigger buffer and try again */
+ /* realloc bigger buffer and try again if sensible */
+ if (line->size - line->read > line->size / 2)
+ continue;
+ if (line->size > MAXBUFLEN / 2) {
+ /* pretend this was a full line.. */
+ line->cur = line->next;
+ line->next = line->base + line->read;
+ pr_debug("returning full line early, %p %p %p: %s\n",
+ str, line->base, line->cur, line->cur);
+ return 1;
+ }
line->size *= 2;
- line->base = realloc(line->base, line->size);
- if (line->base == NULL)
+ pr_debug("growing buffer to %zd\n", line->size);
+
+ char *newbase = realloc(line->base, line->size);
+ if (newbase == NULL)
return -ENOMEM;
+ if (line->cur) {
+ pr_debug("base-cur was %p-%p, new %p-%p\n",
+ line->base, line->cur, newbase,
+ newbase + (line->cur - line->base));
+ line->cur = newbase + (line->cur - line->base);
+ }
+ line->next = newbase + (line->next - line->base);
+ line->base = newbase;
}
- pr_debug("got here? %zd %d\n", nread, errno);
- line->next = line->cur;
if (errno)
return -errno;
- return 0; /* no line read */
+ return -1; /* unknown error? */
}
int main(int argc, char **argv)
{
int flags, fd = 0;
- ssize_t nread;
+ ssize_t nread = 0;
struct pollfd pollfd;
struct getline_states line = { 0 };
- char *cur;
/* non-buffered output */
setlinebuf(stdout);
@@ -105,17 +137,21 @@ int main(int argc, char **argv)
pollfd.fd = fd;
pollfd.events = POLLIN;
while (poll(&pollfd, 1, -1) > 0) {
- cur = NULL;
- while ((nread = fdgetline(fd, &line)) > 0)
- cur = line.cur;
+ line.cur = NULL;
+ while ((nread = fdgetline(fd, &line)) > 0);
- if (cur)
- printf("%s\n", cur);
+ if (line.cur)
+ printf("%s\n", line.cur);
- /* eof */
- if (nread == 0)
+ /* eof or error */
+ if (nread < 0)
break;
+
+ /* throttle in case something tries to wake us up every few ms... */
+ sleep(1);
}
+ pr_debug("done, nread: %zd\n", nread);
+ free(line.base);
return 0;
}