#include #include #include #include #include #include #include #define BUFLEN 1024 #define DEBUG 0 #define pr_debug(fmt, args...) if (DEBUG) printf(fmt, ##args) struct getline_states { char *base; char *cur; size_t size; size_t read; char *next; }; ssize_t fdgetline(int fd, struct getline_states *line) { char *str; ssize_t nread; if (line->base == NULL) { /* First pass: init state */ line->size = 120; line->base = malloc(line->size); if (line->base == NULL) return -ENOMEM; line->base[0] = '\0'; line->read = 0; line->next = 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'))) { 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; } /* 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); line->read -= line->cur - line->base; memmove(line->base, line->cur, line->read); line->cur = line->base; } while ((nread = read(fd, line->base + line->read, line->size - line->read)) > 0 ) { pr_debug("read %zd\n", nread); line->read += nread; /* Check if we have a full line now */ if ((str = strchr(line->base, '\n'))) { 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; } /* realloc bigger buffer and try again */ line->size *= 2; line->base = realloc(line->base, line->size); if (line->base == NULL) return -ENOMEM; } pr_debug("got here? %zd %d\n", nread, errno); line->next = line->cur; if (errno) return -errno; return 0; /* no line read */ } int main(int argc, char **argv) { int flags, fd = 0; ssize_t nread; struct pollfd pollfd; struct getline_states line = { 0 }; char *cur; /* non-buffered output */ setlinebuf(stdout); /* make stream non-block */ flags = fcntl(fd, F_GETFL); flags |= O_NONBLOCK; fcntl(fd, F_SETFL, flags); pollfd.fd = fd; pollfd.events = POLLIN | POLLHUP; while (poll(&pollfd, 1, -1) > 0) { cur = NULL; while ((nread = fdgetline(fd, &line)) > 0) cur = line.cur; if (cur) printf("%s\n", cur); if (pollfd.revents & POLLHUP) break; } return 0; }