X-Git-Url: https://git.xandkar.net/?a=blobdiff_plain;f=x5%2Fkhatus.c;h=62b3774fdb21c18604dfd4da7de1e11f8b1fe926;hb=a415999c271885d6baf38c76b6fcf08ec0c0d2b6;hp=b6f66f7a1134923d8733a18016bb7404d9f4ecd3;hpb=348d5f367c12e60de79ac4647417aa7184996d06;p=khatus.git diff --git a/x5/khatus.c b/x5/khatus.c index b6f66f7..62b3774 100644 --- a/x5/khatus.c +++ b/x5/khatus.c @@ -33,7 +33,9 @@ struct Fifo { int width; int last_read; int ttl; - int pos; /* Position on the output buffer. */ + int pos_init; /* Initial position on the output buffer. */ + int pos_curr; /* Current position on the output buffer. */ + int pos_final; /* Final position on the output buffer. */ Fifo *next; }; @@ -54,6 +56,13 @@ struct Config { .output_to_x_root_window = 0, }; +enum read_status { + END_OF_FILE, + END_OF_MESSAGE, + RETRY, + FAILURE +}; + void fifo_print_one(Fifo *f) { @@ -64,7 +73,9 @@ fifo_print_one(Fifo *f) " width = %d," " last_read = %d," " ttl = %d," - " pos = %d," + " pos_init = %d," + " pos_curr = %d," + " pos_final = %d," " next = %p," " }\n", f->name, @@ -72,7 +83,9 @@ fifo_print_one(Fifo *f) f->width, f->last_read, f->ttl, - f->pos, + f->pos_init, + f->pos_curr, + f->pos_final, f->next ); } @@ -253,7 +266,9 @@ parse_opts_spec(Config *cfg, int argc, char *argv[], int i) f->width = atoi(w); f->ttl = atoi(t); f->last_read = 0; - f->pos = cfg->total_width; + f->pos_init = cfg->total_width; + f->pos_curr = f->pos_init; + f->pos_final = f->pos_init + f->width - 1; f->next = cfg->fifos; cfg->fifos = f; @@ -300,7 +315,7 @@ fifo_read_error(Fifo *f, char *buf) char *b; int i; - b = buf + f->pos; + b = buf + f->pos_init; /* Copy as much of the error message as possible. * EXCLUDING the reminating \0. */ for (i = 0; i < errlen && i < f->width; i++) @@ -310,30 +325,47 @@ fifo_read_error(Fifo *f, char *buf) b[i] = '_'; } -void +enum read_status fifo_read_one(Fifo *f, char *buf) { - ssize_t current; - ssize_t total; - char *b; - char c; + char c; /* Character read. */ + int r; /* Remaining unused slots in buffer range. */ - current = 0; - total = 0; - c = '\0'; - b = buf + f->pos; - while ((current = read(f->fd, &c, 1)) && c != '\n' && c != '\0' && total++ < f->width) - *b++ = c; - if (current == -1) { - error("Failed to read: \"%s\". Error: %s\n", f->name, strerror(errno)); - fifo_read_error(f, buf); - } else { - while (total++ < f->width) - *b++ = ' '; + for (;;) { + switch (read(f->fd, &c, 1)) { + case -1: + error("Failed to read: \"%s\". errno: %d, msg: %s\n", + f->name, errno, strerror(errno)); + switch (errno) { + case EINTR: + case EAGAIN: + return RETRY; + default: + return FAILURE; + } + case 0: + debug("%s: End of FILE\n", f->name); + f->pos_curr = f->pos_init; + return END_OF_FILE; + case 1: + /* TODO: Consider making msg term char a CLI option */ + if (c == '\n' || c == '\0') { + r = f->pos_final - f->pos_curr; + if (r > 0) + memset(buf + f->pos_curr, ' ', r); + f->pos_curr = f->pos_init; + return END_OF_MESSAGE; + } else { + if (f->pos_curr <= f->pos_final) + buf[f->pos_curr++] = c; + /* Drop beyond available range. */ + } + break; + default: + assert(0); + } } /* TODO Record timestamp read */ - close(f->fd); - f->fd = -1; } void @@ -341,7 +373,7 @@ fifo_read_all(Config *cfg, char *buf) { fd_set fds; int maxfd = -1; - int ready; + int ready = 0; struct stat st; FD_ZERO(&fds); @@ -357,15 +389,19 @@ fifo_read_all(Config *cfg, char *buf) fifo_read_error(f, buf); continue; } - debug("opening: %s\n", f->name); - if (f->fd < 0) + if (f->fd < 0) { + debug("%s: closed. opening. fd: %d\n", f->name, f->fd); f->fd = open(f->name, O_RDONLY | O_NONBLOCK); + } else { + debug("%s: already openned. fd: %d\n", f->name, f->fd); + } if (f->fd == -1) { /* TODO: Consider backing off retries for failed fifos. */ error("Failed to open \"%s\"\n", f->name); fifo_read_error(f, buf); continue; } + debug("%s: open. fd: %d\n", f->name, f->fd); if (f->fd > maxfd) maxfd = f->fd; FD_SET(f->fd, &fds); @@ -375,13 +411,43 @@ fifo_read_all(Config *cfg, char *buf) debug("ready: %d\n", ready); assert(ready != 0); if (ready < 0) + /* TODO: Do we really want to fail here? */ fatal("%s", strerror(errno)); - for (Fifo *f = cfg->fifos; f; f = f->next) { - if (FD_ISSET(f->fd, &fds)) { - debug("reading: %s\n", f->name); - fifo_read_one(f, buf); + while (ready) { + for (Fifo *f = cfg->fifos; f; f = f->next) { + if (FD_ISSET(f->fd, &fds)) { + debug("reading: %s\n", f->name); + switch (fifo_read_one(f, buf)) { + /* + * ### MESSAGE LOSS ### + * is introduced by closing at EOM in addition + * to EOF, since there may be unread messages + * remaining in the pipe. However, + * + * ### INTER-MESSAGE PUSHBACK ### + * is also gained, since pipes block at the + * "open" call. + * + * This is an acceptable trade-off because we + * are a stateless reporter of a _most-recent_ + * status, not a stateful accumulator. + */ + case END_OF_MESSAGE: + case END_OF_FILE: + case FAILURE: + close(f->fd); + f->fd = -1; + ready--; + break; + case RETRY: + break; + default: + assert(0); + } + } } } + assert(ready == 0); } int @@ -436,7 +502,9 @@ main(int argc, char *argv[]) /* 2nd pass to make space for separators */ for (Fifo *f = cfg->fifos; f; f = f->next) { - f->pos += prefix; + f->pos_init += prefix; + f->pos_final += prefix; + f->pos_curr = f->pos_init; prefix += seplen; nfifos++; } @@ -448,9 +516,9 @@ main(int argc, char *argv[]) buf[width] = '\0'; /* 3rd pass to set the separators */ for (Fifo *f = cfg->fifos; f; f = f->next) { - if (f->pos) { /* Skip the first, left-most */ + if (f->pos_init) { /* Skip the first, left-most */ /* Copying only seplen ensures we omit the '\0' byte. */ - strncpy(buf + (f->pos - seplen), cfg->separator, seplen); + strncpy(buf + (f->pos_init - seplen), cfg->separator, seplen); } }