Below is the file 'pipeprogress.c' from this revision. You can also download the file.
#include <sys/types.h> #include <sys/stat.h> #include <sys/uio.h> #include <unistd.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #define BUFFER_SIZE (32*(1<<10)) #define FALSE 0 #define TRUE (!(FALSE)) struct progress { long pos, size; int ticks, max_ticks; }; void fail(const char *mesg) { fprintf(stderr, "failure: %s (%s)\n", mesg, strerror(errno)); exit(1); } void display_progress(struct progress *p, int full_display) { int i; /* ANSI codes nicked from http://en.wikipedia.org/wiki/ANSI_X3.64 */ if (full_display) { fputs("\x1B[2K", stderr); fputs("\x1B[1G | ", stderr); for (i=0;i<p->ticks;i++) { fputc('-', stderr); } for (;i<p->max_ticks;i++) { fputc(' ', stderr); } fputs(" |", stderr); } else { fprintf(stderr, "\x1B[%dG-", p->ticks+4); } fprintf(stderr, "\x1B[%dG%2.f%%", p->max_ticks+4+4, (100.0 * p->pos) / (p->size)); } void new_progress(struct progress *p, long size, int max_ticks) { p->pos = 0; p->size = size; p->ticks = 0; p->max_ticks = max_ticks; display_progress(p, TRUE); } void update_progress(struct progress *p, long bytes) { int new_ticks; p->pos += bytes; new_ticks = (p->pos) / (p->size / p->max_ticks); if (new_ticks != p->ticks) { display_progress(p, FALSE); p->ticks = new_ticks; } } void finish_progress(struct progress *p) { p->ticks = p->max_ticks; display_progress(p, TRUE); fputs("\n", stderr); } void copy_to_fd(const char *buf, ssize_t nbytes, int to_fd) { ssize_t written = 0; while (written < nbytes) { ssize_t wbytes = write(to_fd, buf+written, nbytes-written); if (wbytes < 0) { fail("failure writing to stdout"); } written += wbytes; } } void pipe_progress(const char *path) { struct progress p; char buf[BUFFER_SIZE]; struct stat st; int fd; fd = open(path, 0); if (fd < 0) { fail("unable to open output file"); } if (fstat(fd, &st) < 0) { fail("unable to stat file descriptor"); } new_progress(&p, st.st_size, 60); for (;;) { int nbytes; nbytes = read(fd, &buf, BUFFER_SIZE); if (nbytes < 0) { fail("error reading from file"); } else if (nbytes == 0) { /* done! */ break; } update_progress(&p, nbytes); copy_to_fd(buf, nbytes, 1); } finish_progress(&p); } int main(int argc, char *argv[]) { int i; for (i=1;i<argc;i++) { pipe_progress(argv[i]); } return 0; }