+
+ close(f->fd);
+ f->fd = -1;
+}
+
+void
+read_all(Config *cfg, char *buf)
+{
+ fd_set fds;
+ int maxfd;
+ int ready;
+ struct stat st;
+
+ FD_ZERO(&fds);
+
+ /* TODO: Check TTL */
+ for (File *f = cfg->files; f; f = f->next) {
+ /* TODO: Create the FIFO if it doesn't already exist. */
+ if (lstat(f->name, &st) < 0)
+ fatal("Cannot stat \"%s\". Error: %s\n", f->name, strerror(errno));
+ if (!(st.st_mode & S_IFIFO))
+ fatal("\"%s\" is not a FIFO\n", f->name);
+ debug("opening: %s\n", f->name);
+ if (f->fd < 0)
+ f->fd = open(f->name, O_RDONLY | O_NONBLOCK);
+ if (f->fd == -1)
+ /* TODO: Consider backing off retries for failed files. */
+ fatal("Failed to open \"%s\"\n", f->name);
+ if (f->fd > maxfd)
+ maxfd = f->fd;
+ FD_SET(f->fd, &fds);
+ }
+ debug("selecting...\n");
+ ready = select(maxfd + 1, &fds, NULL, NULL, NULL);
+ debug("ready: %d\n", ready);
+ assert(ready != 0);
+ if (ready < 0)
+ fatal("%s", strerror(errno));
+ for (File *f = cfg->files; f; f = f->next) {
+ if (FD_ISSET(f->fd, &fds)) {
+ debug("reading: %s\n", f->name);
+ read_one(f, buf);
+ }
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ int width;
+ int nfiles = 0;
+ int seplen;
+ int prefix = 0;
+ char *buf;
+ Config *cfg = &defaults;
+
+ argv0 = argv[0];
+
+ opts_parse(cfg, argc, argv, 1);
+ debug("argv0 = %s\n", argv0);
+ config_print(cfg);
+ if (cfg->files == NULL)
+ usage("No file specs were given!\n");
+
+ width = cfg->total_width;
+ seplen = strlen(cfg->separator);
+
+ /* 1st pass to make space for separators */
+ for (File *f = cfg->files; f; f = f->next) {
+ f->pos += prefix;
+ prefix += seplen;
+ nfiles++;
+ }
+ width += (seplen * (nfiles - 1));
+ buf = calloc(1, width + 1);
+ if (buf == NULL)
+ fatal("[memory] Failed to allocate buffer of %d bytes", width);
+ memset(buf, ' ', width);
+ buf[width] = '\0';
+ /* 2nd pass to set the separators */
+ for (File *f = cfg->files; f; f = f->next) {
+ if (f->pos) { /* Skip the first, left-most */
+ /* Copying only seplen ensures we omit the '\0' byte. */
+ strncpy(buf + (f->pos - seplen), cfg->separator, seplen);
+ }
+ }
+
+ printf("%s\n", buf);
+ /* TODO: nanosleep and nano time diff */
+ for (;;) {
+ read_all(cfg, buf);
+ printf("%s\n", buf);
+ }