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");
 }

Reply via email to