SIGINFO is awesome, but it's even better when it actually does something relevant.
This makes it print the total counts so far to stderr. Useful? Feature creep? You decide. Index: wc.c =================================================================== RCS file: /cvs/src/usr.bin/wc/wc.c,v retrieving revision 1.17 diff -u -p -d -r1.17 wc.c --- wc.c 16 Jan 2015 06:40:14 -0000 1.17 +++ wc.c 25 Jun 2015 14:49:21 -0000 @@ -32,6 +32,9 @@ #include <sys/param.h> /* MAXBSIZE */ #include <sys/stat.h> #include <sys/file.h> + +#include <errno.h> +#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -41,18 +44,23 @@ #include <unistd.h> #include <util.h> +int64_t linect, wordct, charct; int64_t tlinect, twordct, tcharct; int doline, doword, dochar, humanchar; int rval; extern char *__progname; +volatile sig_atomic_t wants_info = 0; -void print_counts(int64_t, int64_t, int64_t, char *); -void format_and_print(long long); +void handler(int); +ssize_t reread(int, void *, size_t); +void print_counts(FILE *, int64_t, int64_t, int64_t, char *); +void format_and_print(FILE *, long long); void cnt(char *); int main(int argc, char *argv[]) { + struct sigaction act; int ch; setlocale(LC_ALL, ""); @@ -90,6 +98,13 @@ main(int argc, char *argv[]) if (!doline && !doword && !dochar) doline = doword = dochar = 1; + memset(&act, 0, sizeof(act)); + act.sa_handler = handler; + sigemptyset(&act.sa_mask); + /* SA_RESTART specifically not set */ + if (sigaction(SIGINFO, &act, NULL) == -1) + err(1, "sigaction"); + if (!*argv) { cnt((char *)NULL); } else { @@ -100,19 +115,43 @@ main(int argc, char *argv[]) } while(*++argv); if (dototal) - print_counts(tlinect, twordct, tcharct, "total"); + print_counts(stdout, tlinect, twordct, tcharct, + "total"); } exit(rval); } void +handler(int sig __unused) +{ + wants_info = 1; +} + +ssize_t +reread(int d, void *buf, size_t nbytes) +{ + ssize_t len; + +restart: + len = read(d, buf, nbytes); + if (wants_info) { + print_counts(stderr, linect + tlinect, wordct + twordct, + charct + tcharct, "total so far"); + wants_info = 0; + } + if (len == -1 && errno == EINTR) + goto restart; + + return len; +} + +void cnt(char *file) { u_char *C; short gotsp; int len; - int64_t linect, wordct, charct; struct stat sbuf; int fd; u_char buf[MAXBSIZE]; @@ -135,7 +174,7 @@ cnt(char *file) * the word count requires some logic. */ if (doline) { - while ((len = read(fd, buf, MAXBSIZE)) > 0) { + while ((len = reread(fd, buf, MAXBSIZE)) > 0) { charct += len; for (C = buf; len--; ++C) if (*C == '\n') @@ -165,7 +204,7 @@ cnt(char *file) || ifmt == S_IFDIR) { charct = sbuf.st_size; } else { - while ((len = read(fd, buf, MAXBSIZE)) > 0) + while ((len = reread(fd, buf, MAXBSIZE)) > 0) charct += len; if (len == -1) { warn("%s", file); @@ -177,7 +216,7 @@ cnt(char *file) } else { /* Do it the hard way... */ gotsp = 1; - while ((len = read(fd, buf, MAXBSIZE)) > 0) { + while ((len = reread(fd, buf, MAXBSIZE)) > 0) { /* * This loses in the presence of multi-byte characters. * To do it right would require a function to return a @@ -211,7 +250,7 @@ cnt(char *file) } } - print_counts(linect, wordct, charct, file); + print_counts(stdout, linect, wordct, charct, file); /* * Don't bother checking doline, doword, or dochar -- speeds @@ -228,30 +267,30 @@ cnt(char *file) } void -format_and_print(long long v) +format_and_print(FILE *f, long long v) { if (humanchar) { char result[FMT_SCALED_STRSIZE]; (void)fmt_scaled(v, result); - (void)printf("%7s", result); + (void)fprintf(f, "%7s", result); } else { - (void)printf(" %7lld", v); + (void)fprintf(f, " %7lld", v); } } void -print_counts(int64_t lines, int64_t words, int64_t chars, char *name) +print_counts(FILE *f, int64_t lines, int64_t words, int64_t chars, char *name) { if (doline) - format_and_print((long long)lines); + format_and_print(f, (long long)lines); if (doword) - format_and_print((long long)words); + format_and_print(f, (long long)words); if (dochar) - format_and_print((long long)chars); + format_and_print(f, (long long)chars); if (name) - (void)printf(" %s\n", name); + (void)fprintf(f, " %s\n", name); else - (void)printf("\n"); + (void)fprintf(f, "\n"); }