diff options
author | Dominique Martinet <asmadeus@codewreck.org> | 2022-01-28 16:25:03 +0900 |
---|---|---|
committer | Dominique Martinet <asmadeus@coderweck.org> | 2022-01-28 16:25:17 +0900 |
commit | d1726fd170b088e45e439e5b8308a650ddbf2ee3 (patch) | |
tree | d88af697c32c987e28fbfe0fec2fe555816ecfa6 | |
parent | a444771cb5d3dc1f7696cdc9262bf84f5c1bfab3 (diff) |
fix more bugs than could be enumerated...
- would overwrite to-be-printed content with memmove occasionally
- empty lines (n) would be considered as EOF early and make tailburst exit
- if no line was found in a read buffer would be grown even if not required
(e.g. no current usage check before growing :|)
-rw-r--r-- | tailburst.c | 91 |
1 files changed, 58 insertions, 33 deletions
diff --git a/tailburst.c b/tailburst.c index 1c621f2..b5b919e 100644 --- a/tailburst.c +++ b/tailburst.c @@ -30,59 +30,83 @@ 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 ) { + /* search from here */ + while (1) { + errno = 0; + nread = read(fd, line->base + line->read, line->size - line->read - 1); + if (nread < 0) { + if (errno == EAGAIN) + return 0; + break; + } + if (nread == 0) { + /* EOF */ + return -1; + } pr_debug("read %zd\n", nread); 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; + return 1; } - /* realloc bigger buffer and try again */ + /* realloc bigger buffer and try again if sensible */ + if (line->size - line->read > 100) + continue; + if (line->size > 1024) { + /* pretend this was a full line.. */ + line->cur = line->next; + line->next = line->base + line->read; + 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); + pr_debug("read failed? %zd %d\n", nread, errno); - line->next = line->cur; if (errno) return -errno; - return 0; /* no line read */ + return -1; /* unknown error? */ } @@ -92,7 +116,6 @@ int main(int argc, char **argv) ssize_t nread; struct pollfd pollfd; struct getline_states line = { 0 }; - char *cur; /* non-buffered output */ setlinebuf(stdout); @@ -105,16 +128,18 @@ 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); } return 0; |