/* TICK.C do something periodically, v2 BUILD: make tick USE: ./tick [seconds to wait] AUTHOR: philip k. SHARE: in the public domain */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #define USAGE "usage: %s [interval]" /* tries to read stdin, returns false if nothing was found, true if * anything was written to stdout. */ static bool checkpipe(void) { static char *line; static size_t len, cap; char *last, *new; int ret; for (char buf[BUFSIZ];;) { /* try to read from buffer */ ssize_t n = read(STDIN_FILENO, buf, sizeof buf); if (n == -1) { if (errno == EAGAIN) { break; } else { perror("read"); exit(EXIT_FAILURE); } } else if (n == 0) { break; } else { /* append buf to line */ if (n > (ssize_t) (cap - len)) { line = realloc(line, cap += BUFSIZ); if (!line) { perror("realloc"); exit(EXIT_FAILURE) } } memcpy(line + len, buf, (size_t) n); len += (size_t) n; } } /* check if anything was written */ if (line == NULL) { return false; } /* find last newline and print until there */ last = memrchr(line, '\n', len); if (last == NULL) { return false; } ret = fwrite(line, sizeof(char), last - line + 1, stdout); if (ret == 0) { perror("fwrite"); exit(EXIT_FAILURE); } /* relocate rest */ len -= last - line + 1; cap = (len / BUFSIZ + 1) * BUFSIZ; new = malloc(cap); if (!new) { perror("malloc"); exit(EXIT_FAILURE); } memcpy(new, last, len); free(line); line = new; return true; } int main(int argc, char *argv[]) { useconds_t msec; if (argc == 2) { if (!strcmp(argv[1], "-h")) { fprintf(stderr, USAGE "\n", argv[0]); exit(EXIT_SUCCESS); } msec = (useconds_t) (atof(argv[1]) * 1e6); if (msec <= 0) { fprintf(stderr, "Interval must be positive\n"); exit(EXIT_FAILURE); } } else { fprintf(stderr, USAGE "\n", argv[0]); exit(EXIT_FAILURE); } /* activate non-blocking I/O on standard input */ if (-1 == fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK)) { perror("fcntl"); exit(EXIT_FAILURE); } /* input loop */ for (;;) { if (!checkpipe()) printf("\n"); if (-1 == usleep(msec)) { perror("usleep"); exit(EXIT_FAILURE); } } return EXIT_SUCCESS; } /* Local Variables: */ /* indent-tabs-mode: nil */ /* End: */