+/*
+ * Allows reading from a FIFO (i.e., /dev/xconsole). The file descriptor is
+ * set to non-blocking which makes this possible.
+ *
+ * FIXME
+ * Since lseek cannot seek a file descriptor long lines will break.
+ */
+static void tail_pipe(struct text_object *obj, char *dst, size_t dst_size)
+{
+#define TAIL_PIPE_BUFSIZE 4096
+ int lines = 0;
+ int line_len = 0;
+ int last_line = 0;
+ int fd = obj->data.tail.fd;
+
+ while (1) {
+ char buf[TAIL_PIPE_BUFSIZE];
+ ssize_t len = read(fd, buf, sizeof(buf));
+ int i;
+
+ if (len == -1) {
+ if (errno != EAGAIN) {
+ strcpy(obj->data.tail.buffer, "Logfile Read Error");
+ snprintf(dst, dst_size, "Logfile Read Error");
+ }
+
+ break;
+ }
+ else if (len == 0) {
+ strcpy(obj->data.tail.buffer, "Logfile Empty");
+ snprintf(dst, dst_size, "Logfile Empty");
+ break;
+ }
+
+ for (line_len = 0, i = 0; i < len; i++) {
+ int pos = 0;
+ char *p;
+
+ if (buf[i] == '\n') {
+ lines++;
+
+ if (obj->data.tail.readlines > 0) {
+ int n;
+ int olines = 0;
+ int first_line = 0;
+
+ for (n = 0; obj->data.tail.buffer[n]; n++) {
+ if (obj->data.tail.buffer[n] == '\n') {
+ if (!first_line)
+ first_line = n+1;
+
+ if (++olines < obj->data.tail.wantedlines) {
+ pos = n+1;
+ continue;
+ }
+
+ n++;
+ p = obj->data.tail.buffer + first_line;
+ pos = n - first_line;
+ memmove(obj->data.tail.buffer, obj->data.tail.buffer + first_line, strlen(p));
+ obj->data.tail.buffer[pos] = 0;
+ break;
+ }
+ }
+ }
+
+ p = buf + last_line;
+ line_len++;
+ memcpy(&(obj->data.tail.buffer[pos]), p, line_len);
+ obj->data.tail.buffer[pos + line_len] = 0;
+ last_line = i+1;
+ line_len = 0;
+ obj->data.tail.readlines = lines;
+ continue;
+ }
+
+ line_len++;
+ }
+ }
+
+ snprintf(dst, dst_size, "%s", obj->data.tail.buffer);
+}
+