wc(1) SIGINFO - show count so far

2015-06-25 Thread Jean-Philippe Ouellet
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.c16 Jan 2015 06:40:14 -  1.17
+++ wc.c25 Jun 2015 14:49:21 -
@@ -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_tlinect, wordct, charct;
 int64_ttlinect, twordct, tcharct;
 intdoline, doword, dochar, humanchar;
 intrval;
 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_treread(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, 

Re: wc(1) SIGINFO - show count so far

2015-06-25 Thread Theo de Raadt
We do not need (or want) SIGINFO support in a program like this.

The complexity is way too high, and I see no benefit.